connection.clj

Bowmap · bowmap.git · Tickets

Branches > main > f5d10a8 > files / src / net / bowmap / server / network / connection.clj

(ns net.bowmap.server.network.connection
  "A connection to the Minecraft server."
  (:require
   [clojure.core.async :refer [<!! >!! chan close! io-thread]]
   [clojure.spec.alpha :as s]
   [net.bowmap.server.network.streams :as streams])
  (:import
   [java.io IOException]
   [java.net Socket]))

(s/def ::connection (s/keys :opt [::clientbound-frames ::serverbound-frames]))

(defn connection
  "Returns a connection from a given java.net.Socket.
   Connection has keys [::clientbound-frames ::serverbound-frames], both
   channels of clientbound and serverbound frames respectively.
   The lifecycles of the client socket and both frame channels are coupled."
  [socket]
  (let [clientbound-frames (chan 128)
        serverbound-frames (chan 128)
        input-stream (Socket/.getInputStream socket)
        output-stream (Socket/.getOutputStream socket)]
    (Socket/.setTcpNoDelay socket true)
    (io-thread
      (try
        (loop []
          (when (>!! serverbound-frames (streams/read-frame!! input-stream))
            (recur)))
        (catch IOException _)
        (finally
          (close! serverbound-frames)
          (close! clientbound-frames)
          (Socket/.close socket))))
    (io-thread
      (try
        (loop []
          (when-some [frame (<!! clientbound-frames)]
            (streams/write-frame!! frame output-stream)
            (recur)))
        (catch IOException _)
        (finally
          (close! clientbound-frames)
          (close! serverbound-frames)
          (Socket/.close socket))))
    {::clientbound-frames clientbound-frames
     ::serverbound-frames serverbound-frames}))