7d4734b

Branches > namespace-reorganization > 7d4734b > files

Pre-frame packets via transducer

Grahp, 2026-03-01

Commit: 7d4734b3f851cd987f290a78a24008eef943c29f
Parent: 4af8254

2 changed files:

src/net/bowmap/core.clj modified (view file)

@@ -1,6 +1,7 @@ (ns net.bowmap.core   (:require    [aleph.tcp :as tcp]+   [manifold.deferred :as d]    [manifold.stream :as s]    [net.bowmap.client.state :as state]    [net.bowmap.packet-handling :as handle]@@ -12,41 +13,40 @@    [io.netty.buffer ByteBuf Unpooled]    [io.netty.channel ChannelOption])) -(defn handle-packets-  "Handles all (zero or more) unhandled Minecraft protocol packets the client has sent.-   Returns a new client.-   Packets are parsed and handled synchronously as packet decoding can update-    client state, so is impure."-  [client]-  (let [{::keys [buf stream]} client]-    (loop [client client]-      (if (read/can-read-packet? buf)-        (let [pk (sp/decode-packet! buf (::state/state client))-              {:keys [::state/state response]} (handle/handle-packet pk client)-              client (cond-> client state (assoc ::state/state state))]-          (doseq [pk response]-            (s/put! stream (encode-packet pk (::state/state client))))-          (ByteBuf/.discardReadBytes buf)-          (recur client))-        client))))+(defn packet-framer-xf []+  (let [buf (Unpooled/buffer)]+    (fn [rf]+      (fn+        ([] (rf))+        ([res] (rf res))+        ([res input]+         (ByteBuf/.writeBytes buf input)+         (loop [res res]+           (if (read/can-read-packet? buf)+             (let [len (read/read-varint! buf)+                   ;; This copy is probably inefficient but fine for now.+                   res' (rf res (ByteBuf/.copy (ByteBuf/.readRetainedSlice buf len)))]+               (ByteBuf/.discardReadBytes buf)+               (recur res'))+             res))))))) -(defn handle-bytes-  "Takes a client and a byte array of one TCP packet, and handles all-    unhandled Minecraft protocol packets in the client's buffer.-   Returns the new client state, per 'handle-packets'."-  [client bs]-  (try-    (ByteBuf/.writeBytes (::buf client) bs)-    (handle-packets client)-    (catch Throwable e-      (prn "Exception in bytes:" e)-      (.close (::stream client)))))+(defn handle-packet+  "Handles one framed Minecraft protocol packet bytes."+  [client packet-buf]+  (let [pk (sp/decode-packet packet-buf (::state/state client))+        {:keys [::state/state response]} (handle/handle-packet pk client)+        client (cond-> client state (assoc ::state/state state))]+    (doseq [pk response]+      (s/put! (::stream client) (encode-packet pk (::state/state client))))+    client))  (defn client-handler [stream _]   (let [client {::state/state ::state/handshaking                 ::buf (Unpooled/buffer)                 ::stream stream}]-    (s/reduce #'handle-bytes client stream)))+    (d/catch (s/reduce #'handle-packet client (s/transform (packet-framer-xf) stream))+      (fn [e]+        (prn "Exception in client packets:" e)))))  (defn start-server! []   (tcp/start-server #'client-handler@@ -58,5 +58,6 @@   (println "Server Started"))  (comment+  (require 'dev.grahp.bytebuf)   (def server (start-server!))   (.close server))

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

@@ -71,21 +71,20 @@      ::known-packs []      ::ack-finish-config []})) -(defn decode-packet!-  "Decodes and returns one packet from ByteBuf 'buf', which should contain at least one readable packet.+#_"Decodes and returns one packet from ByteBuf 'buf', which should contain at least one readable packet.    The initial length field of the packet should not be stripped from 'buf'.    After calling, the buf will contain one less packet.    Can throw if:     1. No such packet with the packet id and state exists     2. 'buf' is not properly framed, and does not contain a full packet     3. The contents of 'buf' are not a valid packet"++(defn decode-packet+  ;; Pre-framed   [buf state]-  {:pre [(read/can-read-packet? buf)]}-  (let [length (read/read-varint! buf)-        packet (ByteBuf/.readSlice buf length)-        numeric-id (read/read-varint! packet)+  (let [numeric-id (read/read-varint! buf)         packet-id (packet-ids {::state/state state ::pk/numeric-id numeric-id})         dedec (packets packet-id)]     (if dedec-      (dedec packet)+      (dedec buf)       (raise "Failed to decode packet, no such packet with that id." {:id numeric-id :state state :packet-id packet-id}))))