connection.clj

Bowmap · bowmap.git · Tickets

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

(ns net.bowmap.server.network.connection
  "A connection to the Minecraft server."
  (:require
   [clojure.spec.alpha :as s]
   [clojure.stacktrace :refer [print-stack-trace]]
   [clojure.tools.logging :as log]
   [net.bowmap.server.network.streams :as streams])
  (:import
   [java.io IOException]
   [java.net Socket]))

(defprotocol Connection
  (send-frame! [conn frame]
    "Sends 'frame' to the connection asynchronously. Returns nil immediately.")
  (receive-frame!! [conn]
    "Blocks until a frame can be read from 'conn'.
     Returns nil when a frame cannot be read."))

(s/def ::connection #(satisfies? Connection %))

(defn- log-unexpected-exception [ex]
  (when-not (instance? IOException ex)
    (log/warn
      (with-out-str
        (print-stack-trace ex)))))

(defn connection
  "Creates a connection from a given java.net.Socket."
  [socket]
  (let [input-stream (Socket/.getInputStream socket)
        output-stream (Socket/.getOutputStream socket)]
    (Socket/.setTcpNoDelay socket true)
    (reify Connection
      (send-frame! [_ frame]
        (Thread/startVirtualThread
          #(try (streams/write-frame!! frame output-stream)
                (catch Exception e
                  (Socket/.close socket)
                  (log-unexpected-exception e))))
        nil)
      (receive-frame!! [_]
        (try (streams/read-frame!! input-stream)
             (catch Exception e
               (Socket/.close socket)
               (log-unexpected-exception e)
               nil))))))