core.clj
Branches > main > 524e938 > files / src / net / bowmap / core.clj
(ns net.bowmap.core
(:require
[aleph.tcp :as tcp]
[manifold.stream :as s]
[net.bowmap.client.state :as state]
[net.bowmap.codecs.read :as read]
[net.bowmap.packet-handling :refer [handle-packet]]
[net.bowmap.packets.client :refer [encode-packet!]]
[net.bowmap.packets.server :as sp])
(:import
[io.netty.buffer ByteBuf Unpooled]
[io.netty.channel ChannelOption]))
(defn print-bb [bb]
(subvec (vec (.array bb))
(.readerIndex bb)
(.writerIndex bb)))
;; Document why parsing and handling are done synchronously
(defn read-packet! [client bs]
(let [{::keys [buf stream]} client
buf (ByteBuf/.writeBytes buf bs)]
(loop [client client]
(if (read/can-read-packet? buf)
(let [{:keys [::state/state response]}
(handle-packet (sp/decode-packet! buf (::state/state client))
client)
client (cond-> client state (assoc ::state/state state))]
(when response
;; TODO this can also throw...
(let [pk (encode-packet! response (::state/state client))]
(prn "response packet:" (print-bb pk))
(s/put! stream pk)))
(ByteBuf/.discardReadBytes buf)
(recur client))
client))))
(defn client-handler [s _]
(let [client {::state/state ::state/handshaking
::buf (Unpooled/buffer)
::stream s}]
(s/reduce (fn [client bs]
(read-packet! client bs))
client
s)))
(defn start-server! []
(tcp/start-server #'client-handler
{:port 25565
:bootstrap-transform (fn [bootstrap]
(.childOption bootstrap ChannelOption/TCP_NODELAY true)
bootstrap)}))
(defn -main [& _args]
(start-server!)
(println "Server Started"))
(comment
(.close server)
(def server (start-server!)))