#!/usr/bin/env racket #lang racket ; vim:syntax=racket (require json "iputil.rkt" "unix-socket.rkt") ;; info : Peer ;; sock-in : Input-Port ;; sock-out : Output-Port (struct peer-conn [info sock-in sock-out] #:transparent) ;; Str [Listof Peer-Conn] -> [-> Void] ;; -- ;; runs router logic given peer connections. returns thunk that, when called, aborts the ;; router. (define (run-router/conns ans peer-conns) (define mail (make-channel)) (define peer-threads (for/list ([pc (in-list peer-conns)]) (match-define (peer-conn peer sock-in sock-out) pc) (thread (λ () (define buf (make-bytes 65536)) (let loop () (define len (read-bytes-avail! buf sock-in)) (define jsexpr (bytes->jsexpr (subbytes buf 0 len))) (channel-put mail (list peer jsexpr)) (loop)))))) (define (loop) (match-define (list peer data) (channel-get mail)) (printf "from ~a:\n~s\n" peer data) (loop)) (define loop-thread (thread loop)) (λ () (for-each break-thread (cons loop-thread peer-threads)))) ;; Str [Listof Peer] -> ;; Router main (define (run-router asn peers) (displayln asn) (map displayln peers) (run-router/conns (for/list ([peer (in-list peers)]) (define-values [sock-in sock-out] (unix-socket-connect (ip->string (peer-ip peer)) 'SOCK_SEQPACKET)) (peer-conn peer sock-in sock-out)))) (module+ main (command-line #:program "router" #:args (asn . peers) ;; Run the router (run-router asn (map string->peer peers)))) (module+ test (define-values [in1 out1] (make-pipe)) (define-values [in2 out2] (make-pipe)) (define p1 (peer-conn (string->peer "1.2.3.4-cust") in1 out1)) (define p2 (peer-conn (string->peer "1.2.3.5-peer") in2 out2)) (define abort-router (run-router/conns "123" (list p1 p2))) (void (write-string "{\"a\": 1, \"b\": [1,2,3]}" out1)))