Skip to content

Instantly share code, notes, and snippets.

@samdphillips
Created March 31, 2023 18:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samdphillips/f39795f0ed5bbb0f4186034bdfd8eec6 to your computer and use it in GitHub Desktop.
Save samdphillips/f39795f0ed5bbb0f4186034bdfd8eec6 to your computer and use it in GitHub Desktop.
#lang racket/base
(require mzlib/thread
racket/match
racket/port
racket/string
"mcast-channel.rkt")
(define-logger chat-server)
(struct message (nick text) #:transparent)
(define messages-in (make-mcast-channel))
(define (get-nick inp outp)
(display "nick: " outp)
(flush-output outp)
(string-trim (read-line inp)))
(define (send-message! nick text)
(mcast-channel-put messages-in (message nick text)))
(define (run-client inp outp)
(log-chat-server-info "new client connection")
(define nick (get-nick inp outp))
(define c->s/evt
(handle-evt (read-line-evt inp)
(λ (line)
(log-chat-server-debug "received message ~s from ~a" line nick)
(match line
[(or (? eof-object?)
(pregexp "^\\s*quit\\s*$"))
(void)]
[msg (send-message! nick msg)
(run)]))))
(define s->c/evt
(handle-evt (make-mcast-output messages-in)
(λ (msg)
(log-chat-server-debug "~a received message ~a from server" nick msg)
(match msg
[(message (== nick) _) (run)]
[_ (writeln msg outp)
(flush-output outp)
(run)]))))
(define (run)
(sync c->s/evt s->c/evt))
(run)
(log-chat-server-debug "disconnecting ~a" nick))
(log-chat-server-info "starting server")
(run-server 12777 run-client #f)
#lang racket/base
(require racket/contract
racket/match
syncvar)
(provide mcast-channel?
mcast-output?
make-mcast-channel
(contract-out
[mcast-channel-put (-> mcast-channel? any/c any)]
[make-mcast-output (-> mcast-channel? any)]
[mcast-output-get (-> mcast-output? any)]))
(struct mcast-channel (req-ch rpy-ch))
(struct mcast-output (ch)
#:property prop:evt 0)
(define (make-mcast-channel)
(define req-ch (make-channel))
(define rpy-ch (make-channel))
(define (server iv)
(match (channel-get req-ch)
['new-port
(channel-put rpy-ch (make-mcast-output-tee iv))
(server iv)]
[(list 'message value)
(let ([next-iv (make-ivar)])
(ivar-put! iv (cons value next-iv))
(server next-iv))]))
(thread (lambda () (server (make-ivar))))
(mcast-channel req-ch rpy-ch))
(define (make-mcast-output-tee iv)
(define output-ch (make-channel))
(define (tee iv)
(match-define (cons value next-iv) (ivar-get iv))
(channel-put output-ch value)
(tee next-iv))
(thread (lambda () (tee iv)))
(mcast-output output-ch))
(define (mcast-channel-put a-mcast-channel value)
(channel-put (mcast-channel-req-ch a-mcast-channel) (list 'message value)))
(define (make-mcast-output a-mcast-channel)
(channel-put (mcast-channel-req-ch a-mcast-channel) 'new-port)
(channel-get (mcast-channel-rpy-ch a-mcast-channel)))
(define (mcast-output-get a-mcast-output)
(sync a-mcast-output))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment