88faa97

Bowmap · bowmap.git · Tickets

Branches > main > 88faa97 > files

Use Connection protocol and drop core.async

Grahp, 2026-09-25

Commit: 88faa97c4182e48c79d5f243410fc7c94ec88cd0
Parent: 068f95e

4 changed files:

deps.edn modified (view file)

@@ -6,6 +6,5 @@   org.clojure/tools.logging {:mvn/version "1.3.1"}   nrepl/nrepl {:mvn/version "1.7.0"}   dev.weavejester/medley {:mvn/version "1.10.0"}-  org.clojure/core.async {:mvn/version "1.9.865"}   org.clojure/data.json {:mvn/version "2.5.2"}   io.netty/netty-buffer {:mvn/version "4.1.111.Final"}}}

src/net/bowmap/server/network/connection.clj modified (view file)

@@ -1,46 +1,35 @@ (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-frame-chan ::serverbound-frame-chan]))+(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 connection-  "Returns a connection from a given java.net.Socket.-   Connection has keys [::clientbound-frame-chan ::serverbound-frame-chan],-   which are channels of clientbound and serverbound frames respectively.-   The lifecycles of the client socket and both frame channels are coupled."+  "Creates a connection from a given java.net.Socket."   [socket]-  (let [clientbound-frames (chan 128)-        serverbound-frames (chan 128)-        input-stream (Socket/.getInputStream socket)+  (let [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-frame-chan clientbound-frames-     ::serverbound-frame-chan serverbound-frames}))+    (reify Connection+      (send-frame! [_ frame]+        (Thread/startVirtualThread+          #(try (streams/write-frame!! frame output-stream)+                (catch Exception _+                  (Socket/.close socket))))+        nil)+      (receive-frame!! [_]+        (try (streams/read-frame!! input-stream)+             (catch Exception _+               (Socket/.close socket)+               nil))))))

src/net/bowmap/server/protocol/client.clj modified (view file)

@@ -3,4 +3,4 @@    [clojure.spec.alpha :as s]    [net.bowmap.server.protocol.phase :as phase])) -(s/def ::client (s/keys :opt [::phase/phase ::clientbound-packet-chan]))+(s/def ::client (s/keys :opt [::phase/phase]))

src/net/bowmap/server/runtime/connections.clj modified (view file)

@@ -1,44 +1,31 @@ (ns net.bowmap.server.runtime.connections   (:require-   [clojure.core.async :refer [<!! alts!! chan io-thread put!]]    [net.bowmap.server.network.connection :as connection]    [net.bowmap.server.network.server :as server]-   [net.bowmap.server.protocol.client :as client]    [net.bowmap.server.protocol.packet-serialization :as serialize]    [net.bowmap.server.protocol.phase :as phase]    [net.bowmap.server.runtime.packets :as packets])) -(defn client-step-  ([_] {::phase/phase ::phase/handshaking})-  ([client in x]-   (case in-     ::connection/serverbound-frame-     (let [[client' packets] (packets/apply-packet client (serialize/decode-frame client x))]-       [client' {::client/clientbound-packet-chan packets}])--     ::client/clientbound-packet-     [client {::connection/clientbound-frame-chan [(serialize/encode-packet client x)]}])))--(defn handle-connection! [{::connection/keys! [serverbound-frame-chan clientbound-frame-chan]}]-  (let [clientbound-packet-chan (chan 1024)]-    (io-thread-      (loop [client-state (client-step nil)]-        (let [[x ch] (alts!! [serverbound-frame-chan clientbound-packet-chan])-              in (condp = ch-                   serverbound-frame-chan ::connection/serverbound-frame-                   clientbound-packet-chan ::client/clientbound-packet)]-          (when (some? x)-            (let [[client' {frames ::connection/clientbound-frame-chan-                            packets ::client/clientbound-packet-chan}]-                  (client-step client-state in x)]-              (doseq [frame frames]-                (put! clientbound-frame-chan frame))-              (doseq [packet packets]-                (put! clientbound-packet-chan packet))-              (recur client'))))))))+(defn handle-connection! [connection]+  (let [client (atom {::phase/phase ::phase/handshaking})+        player (atom {})+        send-packet! (fn [packet]+                       (connection/send-frame! connection (serialize/encode-packet @client packet)))]+    (loop []+      (when-some [frame (connection/receive-frame!! connection)]+        (let [c @client+              packet (serialize/decode-frame c frame)+              [client' packets] (packets/apply-packet c packet)]+          (assert (compare-and-set! client c client'))+          (let [[player' packets] (packets/handle-packet @player packet)]+            (reset! player player')+            (run! send-packet! packets))+          (recur))))))  (defn handle-connections!   [server]   (loop []-    (handle-connection! (server/accept-connection!! server))-    (recur)))+    (let [connection (server/accept-connection!! server)]+      (Thread/startVirtualThread+        #(handle-connection! connection))+      (recur))))