server.clj
Branches > main > 3fafff8 > files / src / net / bowmap / server / runtime / server.clj
(ns net.bowmap.server.runtime.server
(:require
[clojure.core.async :refer [<!! alts!! chan io-thread put!]]
[net.bowmap.server.network.connection :as connection]
[net.bowmap.server.protocol.client :as client]
[net.bowmap.server.protocol.codec :as codec]
[net.bowmap.server.protocol.phase :as phase]
[net.bowmap.server.runtime.packets :as packets]))
(defn client-step
([_] {::phase/phase ::phase/handshaking})
([client in x]
(case in
::connection/serverbound-frame
(let [[client' packets] (packets/apply-packet client (codec/decode-frame client x))]
[client' {::client/clientbound-packets packets}])
::client/clientbound-packet
[client {::connection/clientbound-frames [(codec/encode-packet client x)]}])))
(defn handle-connection! [{::connection/keys! [serverbound-frames clientbound-frames]}]
(let [clientbound-packets (chan 1024)]
(io-thread
(loop [client-state (client-step nil)]
(let [[x ch] (alts!! [serverbound-frames clientbound-packets])
in (condp = ch
serverbound-frames ::connection/serverbound-frame
clientbound-packets ::client/clientbound-packet)]
(when (some? x)
(let [[client' {frames ::connection/clientbound-frames
packets ::client/clientbound-packets}]
(client-step client-state in x)]
(doseq [frame frames]
(put! clientbound-frames frame))
(doseq [packet packets]
(put! clientbound-packets packet))
(recur client'))))))))
(defn run-server!
"Starts running the given server, where server is a channel of connections.
Blocks until the server closes."
[server]
(loop []
(when-some [connection (<!! server)]
(handle-connection! connection)
(recur))))