core.clj

Branches > main > adaa9ca > 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]))

;; Document why parsing and handling are done synchronously
(defn read-packet! [bs client]
  (let [{::keys [buf]} @client
        buf (ByteBuf/.writeBytes buf bs)]
    (while (read/can-read-packet? buf)
      (prn [(subvec (vec (.array buf))
                    (.readerIndex buf)
                    (.writerIndex buf))
            (::state/state @client)])
      ;; TODO handle exceptions?
      (let [{:keys [::state/state response]} (handle-packet (sp/decode-packet! buf (::state/state @client))
                                                            client)]
        (when state
          (vswap! client assoc ::state/state state))
        (when response
          ;; TODO this can also throw...
          (encode-packet! response (::state/state @client))))
      (ByteBuf/.discardReadBytes buf))))

(defn client-handler [s _]
  (let [client (volatile! {::state/state ::state/handshaking
                           ::buf (Unpooled/buffer)})]
    (s/consume (fn [bs] (read-packet! 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!)))