racket-matrix-2012/os2-tcp-test-chat-service.rkt

67 lines
2.6 KiB
Racket

#lang racket/base
;; Trivial example program demonstrating os2-tcp.rkt.
(require racket/string)
(require racket/set)
(require racket/match)
(require "os2.rkt")
(require "os2-tcp.rkt")
(define (send-to-all local-addr active-remotes speaker line)
(define formatted-line (string->bytes/utf-8
(format "~a: ~a~n" speaker (bytes->string/utf-8 line))))
(for/list ([remote (in-set active-remotes)])
(send-message (tcp-channel local-addr remote formatted-line))))
(define (format-names active-remotes)
(if (set-empty? active-remotes)
#"No-one else is here right now.\r\n"
(string->bytes/utf-8
(string-append*
"These connections are active:\r\n"
(for/list ([remote (in-set active-remotes)]) (format " - ~a\r\n" remote))))))
(define (connection-handler local-addr)
(transition (set) ;; of remote TcpAddresses
(role (topic-publisher (tcp-channel local-addr (wild) (wild))))
(role (topic-subscriber (tcp-channel (wild) local-addr (wild)))
#:state active-remotes
#:topic t
#:on-presence (match t
[(topic 'publisher (tcp-channel (== local-addr) _ _) #f)
;; Ignore loopback flow.
(transition active-remotes)]
[(topic 'publisher (tcp-channel remote-addr (== local-addr) _) #f)
(write `(arrived ,remote-addr)) (newline)
(transition (set-add active-remotes remote-addr)
(send-message (tcp-channel local-addr remote-addr
(format-names active-remotes)))
(send-to-all local-addr active-remotes remote-addr #"<arrived>")
(send-tcp-mode remote-addr local-addr 'lines)
(send-tcp-credit remote-addr local-addr 1))])
#:on-absence (match t
[(topic 'publisher (tcp-channel (== local-addr) _ _) #f)
;; Ignore loopback flow.
(transition active-remotes)]
[(topic 'publisher (tcp-channel remote-addr (== local-addr) _) #f)
(write `(departed ,remote-addr)) (newline)
(transition (set-remove active-remotes remote-addr))])
[(tcp-channel remote-addr (== local-addr) (? eof-object?))
(define new-active-remotes (set-remove active-remotes remote-addr))
(transition new-active-remotes
(send-message (tcp-channel local-addr remote-addr #"Goodbye!\r\n"))
(send-to-all local-addr new-active-remotes remote-addr #"<departed>"))]
[(tcp-channel remote-addr (== local-addr) (? bytes? bs))
(transition active-remotes
(send-tcp-credit remote-addr local-addr 1)
(send-to-all local-addr active-remotes remote-addr bs))])))
(define (main port)
(ground-vm
(transition 'none
(spawn tcp-spy)
(spawn tcp-driver)
(spawn (connection-handler (tcp-listener port))))))
(main 5999)