#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 #"") (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 #""))] [(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)