server.clj
Branches > main > e3dbdf6 > 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 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)))
{::incoming-frames packets-in
::outgoing-frames 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)]
(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))