core.clj

Branches > namespace-reorganization > 099bbf1 > 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))