server.clj
Branches > main > fc6a193 > 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 ServerSocket Socket]))
#_(defn- handle-client [client-chan stream info]
(let [packets-in (chan 1 pk/packet-framer-xf)
packets-out (chan)]
(s/connect stream packets-in)
(s/connect packets-out stream)
(put! client-chan {::packets-in packets-in
::packets-out packets-out})))
(defn new-client [socket]
(let [packets-in (chan)
packets-out (chan)]
(io-thread
(loop []
(try (let [frame (stream/read-frame!! (Socket/.getInputStream socket))]
(>!! packets-in frame))
(catch Exception _
; Disconnect packet?
(Socket/.close socket)))
(recur)))
(io-thread
(loop []
(let [frame (<!! packets-out)]
(stream/write-frame!! frame (Socket/.getOutputStream socket)))
(recur)))
{::packets-in packets-in
::packets-out packets-out}))
(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)
clients (chan 64)
shutdown (promise)]
(io-thread
(try
(loop []
; TODO TCP_NODELAY
(let [socket (ServerSocket/.accept server)]
(if (>!! clients (new-client socket))
(recur)
(do (Closeable/.close socket)
(deliver shutdown :shutdown)))))
(catch Throwable t
(close! clients)
(deliver shutdown :shutdown)
(throw t))))
{::client-chan clients
::shutdown shutdown}))