core.clj
Branches > main > 16276c5 > files / src / net / bowmap / core.clj
(ns net.bowmap.core
(:require
[clojure.core.async :refer [<!! >!! alt!! chan io-thread put! timeout]]
[net.bowmap.network.message :as msg]
[net.bowmap.network.state :as state]
[net.bowmap.packet-handling :as handle]
[net.bowmap.network.message.client :as client]
[net.bowmap.network.message.server :as server]
[net.bowmap.server :as server-process]))
;; TODO yeah...
(defn handle-packet
"Handles one ByteBuf of a framed serialized serverbound packet, and returns a
map of :client and :packets."
[client packet-buf]
(let [pk (server/packet->message packet-buf (::state/state client))]
(handle/response client pk)))
; could return a map of side-effects as data and be pure.
(defmulti handle-message
(fn [client msg]
(:msg/id msg)))
; Should be per-client and able to dispatch to the global thing, probably a tick loop or async dun really matter
(defn handle-message!
"Handles one serverbound message from 'client', and performs the side effects of that message.
Returns the new client state."
[client msg]
(let [res (handle-message client msg)]
(or (:client res) client)))
; TODO why is this not qualified?
(defmethod handle-message :server/handshaking [client msg]
(assoc client ::state/state (:intent msg)))
; Does it make more sense to use a channel here?
(defn handle-messages
"Handles all the messages in the client, which may involve sending some messages out, and
sending some async events to the server.
And also starting a keepalive loop?"
[client msg])
(defn handle-something-or-other [client in packets-out out]
(alt!!
; These could be agents around clients with vectors as well instead of immutable maps holding channels
in ([buf]
(when buf
(let [response (handle-packet client buf)]
(when (:keepalive response)
; TODO this should probably be a global scheduler
(io-thread
(loop []
(<!! (timeout 5000))
(when (>!! packets-out {::msg/id ::client/keep-alive
:id (long (* (rand) Long/MAX_VALUE))})
(recur)))))
(doseq [pk (:response response)]
(put! packets-out pk))
(:client response))))
packets-out ([pk]
(assert (>!! out (client/encode-packet pk (::state/state client))))
client)))
; Do I need to close out?
(defn client-handler [in out]
(let [packets-out (chan)
client {::state/state ::state/handshaking}]
(try (loop [client client]
(when-some [client (handle-something-or-other client in packets-out out)]
(recur client)))
(catch Throwable e
(println "In client handler: " e)))))
(defn start-server []
(server-process/start-server! {:handler #'client-handler
:port 25565}))
(defn -main [& _args]
(start-server)
(println "Server Started"))
(comment
(def server (start-server))
(.close server))