server.clj
Branches > main > e95c513 > files / src / net / bowmap / network / server.clj
(ns net.bowmap.network.server
(:require
[clojure.core.async :refer [<!! >!! chan close! io-thread]]
[net.bowmap.network.stream :as stream])
(:import
[java.io Closeable]
[java.net InetAddress ServerSocket Socket]))
(defn new-client [socket]
(let [incoming-frames (chan)
outgoing-frames (chan)]
(io-thread
(loop []
(try (let [frame (stream/read-frame!! (Socket/.getInputStream socket))]
(>!! incoming-frames frame))
(catch Exception _
; Disconnect?
(Socket/.close socket)))
(recur)))
(io-thread
(loop []
(if-some [frame (<!! outgoing-frames)]
(stream/write-frame!! frame (Socket/.getOutputStream socket))
(Socket/.close socket))
(recur)))
{::incoming-frames incoming-frames
::outgoing-frames outgoing-frames}))
; TODO should return the actual server...
(defn start-tcp-server!
"Starts a TCP server at the given port. Returns a channel of clients as they connect.
When the server closes, client channel will be closed, and vice versa."
[& {:keys! [port]}]
(let [server (ServerSocket. port 50 (InetAddress/getByName "0.0.0.0"))
clients (chan 64)]
(io-thread
(try
(loop []
(let [socket (ServerSocket/.accept server)]
(Socket/.setTcpNoDelay socket true)
(if (>!! clients (new-client socket))
(recur)
(Closeable/.close socket))))
(catch Throwable t
(close! clients)
(throw t))))
clients))