ac6158f

Branches > namespace-reorganization > ac6158f > files / src / net / bowmap

Handle clients with core.async

Grahp, 2026-03-12

Commit: ac6158f732589044faaf533be11d28751352dc39
Parent: a408573

3 changed files:

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

@@ -1,100 +1,51 @@ (ns net.bowmap.core   (:require-   [manifold.deferred :as d]-   [manifold.stream :as s]+   [clojure.core.async :refer [<!! >!! alt!! chan io-thread put! timeout]]    [net.bowmap.client.state :as state]    [net.bowmap.packet :as pk]    [net.bowmap.packet-handling :as handle]    [net.bowmap.packet.client :as cp]-   [net.bowmap.packet.read :as read]    [net.bowmap.packet.server :as sp]-   [net.bowmap.server :as server])-  (:import-   [io.netty.buffer ByteBuf Unpooled]))--(defn packet-framer-xf-  "Transducer that frames bytes from incoming byte arrays and outputs ByteBufs of-   framed serialized serverbound packets."-  [rf]-  (let [buf (Unpooled/buffer)]-    (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)-                 res' (rf res (ByteBuf/.copy (ByteBuf/.readRetainedSlice buf len)))]-             (ByteBuf/.discardReadBytes buf)-             (recur res'))-           res))))))+   [net.bowmap.server :as server]))  (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 (sp/decode-packet packet-buf (::state/state client))]-    (when (= (::pk/id pk) ::sp/finish-config)-      ; Because the return map is arbitrary, this can definitely be idk literally anywhere else lmao-      ; These 3 functions definitely need to change although I don't know what that looks like.-      (s/connect (s/periodically 5000 0 (fn []-                                          {::pk/id ::cp/keep-alive-                                           :id (long (* (rand) Long/MAX_VALUE))}))-                 (::packet-stream client)-                 {:downstream? false}))     (handle/response client pk))) -(defn handle-message-  "Handles either a serverbound or clientbound packet, returning the new client-   state, and sending either the clientbound packets it was given, or the-   packets that handling the serverbound packet it was given returned.-   Should only be used synchronously as serialization depends on client state!"-  [client msg]-  (let [{:keys [stream val]} msg]-    (case stream-      :serverbound-packets-      (let [{:keys [client response]} (handle-packet client val)]-        (reduce (fn [client pk]-                  (handle-message client {:stream :clientbound-packets :val pk}))-                client response))+(defn handle-something-or-other [client in packets-out out]+  (alt!!+    in ([buf]+        (when buf+          (let [response (handle-packet client buf)]+            (when (:keepalive response)+              (io-thread+                (loop []+                  (<!! (timeout 5000))+                  (when (>!! packets-out {::pk/id ::cp/keep-alive+                                          :id (long (* (rand) Long/MAX_VALUE))})+                    (recur)))))+            (doseq [pk (:response response)]+              (put! packets-out pk))+            (:client response))))+    packets-out ([pk]+                 (assert (>!! out (cp/encode-packet pk (::state/state client))))+                 client))) -      :clientbound-packets-      (let [pk (cp/encode-packet val (::state/state client))]-        @(s/put! (::stream client) pk)-        client))))--(defn feed-  "Sends all messages from the source to the sink with a transducer."-  [source xform sink]-  (let [stream (s/stream 1 xform)]-    (s/connect source stream)-    (s/connect stream sink {:upstream? false})))--(defn alt-onto-  "Takes a map of keywords to streams and returns a stream with vals {:stream keyword :val val-from-stream}."-  [chans]-  (let [out-stream (s/stream)]-    (doseq [[kw s] chans]-      (feed s

Show all 131 lines

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

@@ -55,6 +55,7 @@  (defmethod handle-packet ::sp/finish-config [pk client]   {:client (assoc client ::state/state ::state/play)+   :keepalive true    :response [{::pk/id ::cp/login               :entity-id 0 ;; TODO magic zero :p               :hardcore? false

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

@@ -1,13 +1,43 @@ (ns net.bowmap.server   (:require-   [aleph.tcp :as tcp])+   [aleph.tcp :as tcp]+   [clojure.core.async :refer [chan io-thread]]+   [manifold.stream :as s]+   [net.bowmap.packet.read :as read])   (:import    [io.netty.bootstrap ServerBootstrap]+   [io.netty.buffer ByteBuf Unpooled]    [io.netty.channel ChannelOption])) -(defn start-server!-  "Starts a TCP server at port 'port', calling 'handler' with each client, with TCP_NODELAY enabled."+(defn packet-framer-xf+  "Transducer that frames bytes from incoming byte arrays and outputs ByteBufs of+   framed serialized serverbound packets."+  [rf]+  (let [buf (Unpooled/buffer)]+    (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)+                 res' (rf res (ByteBuf/.copy (ByteBuf/.readRetainedSlice buf len)))]+             (ByteBuf/.discardReadBytes buf)+             (recur res'))+           res))))))++(defn- handle-client [handler stream info]+  (let [in (chan 1 packet-framer-xf)+        out (chan)]+    (s/connect stream in)+    (s/connect out stream)+    (io-thread (handler in out))))++; Could return a channel of clients?+(defn start-server2!   [& {:keys [handler port]}]-  (tcp/start-server handler+  (tcp/start-server (fn [stream info]+                      (handle-client handler stream info))                     {:port port                      :bootstrap-transform #(ServerBootstrap/.childOption % ChannelOption/TCP_NODELAY true)}))