a35eba5
Branches > main > a35eba5 > files / .gitignore
Remove core.async from connections
Commit: a35eba5a4cfdae3c37f2ae028d97d81ba8aee7be
Parent: 8ee8c07
3 changed files:
src/net/bowmap/protocol/server.clj view file
@@ -1,6 +1,5 @@ (ns net.bowmap.protocol.server (:require- [clojure.core.async :refer [<!! io-thread put!]] [net.bowmap.protocol.handle :as handle] [net.bowmap.server.logic :as logic] [net.bowmap.server.player :as player]@@ -9,23 +8,21 @@ [net.bowmap.transport.connection :as connection] [net.bowmap.transport.server :as mc])) -(defn handle-response [clientbound-packets {:keys [packets events]}]+(defn handle-response [send-packet {:keys [packets events]}] (doseq [packet packets]- (put! clientbound-packets packet))+ (send-packet packet)) (doseq [event events] (execute-effects! (logic/handle-events event)))) (defn handle-connection [connection]- (let [{::connection/keys! [close-fn serverbound-packets clientbound-packets closed]} connection]- (io-thread- (when-let [uuid @closed]- (execute-effects! (logic/handle-events {::event/id ::event/player-left ::player/uuid uuid}))))+ (let [{::connection/keys! [close-fn send-packet receive-packet]} connection] (try (loop []- (handle-response clientbound-packets (handle/interpret-packet (<!! serverbound-packets)))+ (handle-response send-packet (handle/interpret-packet (assoc (receive-packet) ::connection/connection connection))) (recur)) (finally- (close-fn)))))+ (when-let [uuid (close-fn)]+ (execute-effects! (logic/handle-events {::event/id ::event/player-left ::player/uuid uuid}))))))) (defn start-server! [port] (mc/start-server! port #'handle-connection))src/net/bowmap/stormbow/effect_execution.clj view file
@@ -1,6 +1,5 @@ (ns net.bowmap.stormbow.effect-execution (:require- [clojure.core.async :refer [put!]] [net.bowmap.protocol.packet :as pk] [net.bowmap.protocol.packet.clientbound :as clientbound] [net.bowmap.server.player :as player]@@ -14,9 +13,9 @@ (defmethod execute-effect! ::effect/send-chat-message [{::player/keys! [uuid] :keys! [message]}] (let [{::connection/keys! [connection]} (@server/players uuid)- {::connection/keys! [clientbound-packets]} connection]- (put! clientbound-packets {::pk/id ::clientbound/system-chat-message- :message message})))+ {::connection/keys! [send-packet]} connection]+ (send-packet {::pk/id ::clientbound/system-chat-message+ :message message}))) (defn execute-effects! [effects] (run! execute-effect! effects))src/net/bowmap/transport/connection.clj view file
@@ -1,84 +1,69 @@ (ns net.bowmap.transport.connection "A connection to the Minecraft server." (:require- [clojure.core.async :refer [<!! chan close! io-thread put! timeout]]+ [clojure.core.async :refer [io-thread]] [net.bowmap.protocol.packet :as pk] [net.bowmap.protocol.packet.clientbound :as clientbound] [net.bowmap.protocol.packet.serverbound :as serverbound]- [net.bowmap.transport.phase :as phase] [net.bowmap.server.player :as player] [net.bowmap.transport.packets :refer [decode-packet! encode-packet!]]+ [net.bowmap.transport.phase :as phase] [net.bowmap.transport.streams :as streams]) (:import [java.io EOFException] [java.net Socket SocketException])) -(defn handle-serverbound-frame!- [state conn frame]- (let [{::phase/keys! [phase]} @state- packet (decode-packet! frame phase)]- (when-let [{::pk/keys! [id]} packet]- (case id- ::serverbound/handshaking (swap! state assoc ::phase/phase (req! packet ::phase/phase))- ::serverbound/login-acknowledged (swap! state assoc ::phase/phase ::phase/config)- ::serverbound/finish-config (swap! state assoc ::phase/phase ::phase/play)- ::serverbound/login-start- (let [{:keys! [username uuid]} packet]- (swap! state assoc ::player/username username ::player/uuid uuid))- nil)- ; Just kinda crudely passing the connection into the serverbound packet right now- (merge packet {::connection conn} (select-keys @state [::player/uuid])))))- (defn connection "Creates a connection object from a java.net.Socket Connections have a channel of serverbound packets, and a channel of clientbound packets. Connections can be closed with ::close-fn, and the promise at ::closed will deliver with the connection's known uuid, or nil if the connection does not have one." [socket]- (let [serverbound-packets (chan 64)- clientbound-packets (chan 64)- input-stream (Socket/.getInputStream socket)+ (let [input-stream (Socket/.getInputStream socket) output-stream (Socket/.getOutputStream socket) state (atom {::phase/phase ::phase/handshaking}) closed-promise (promise)- conn {::close-fn (fn []- (Socket/.close socket)- (close! serverbound-packets)- (close! clientbound-packets))- ::closed closed-promise- ::serverbound-packets serverbound-packets- ::clientbound-packets clientbound-packets}]-+ close (fn []+ (Socket/.close socket)+ (deliver closed-promise (@state ::player/uuid))+ (@state ::player/uuid))+ conn {::close-fn close+ ::send-packet (fn [packet]+ (when (Socket/.isClosed socket)+ (throw (ex-info "Tried to send packet to a disconnected client" {:packet packet})))+ (try+ (streams/write-frame!! (encode-packet! packet (req! @state ::phase/phase)) output-stream)+ (catch Throwable t+ (close)+ (when-not (instance? SocketException t)+ (throw t)))))+ ::receive-packet (fn []+ (when (Socket/.isClosed socket)+ (throw (Exception. "Tried to read packet from a disconnected client")))+ (try+ (let [frame (streams/read-frame!! input-stream)+ {::phase/keys! [phase]} @state+ packet (decode-packet! frame phase)]+ (when-let [{::pk/keys! [id]} packet]+ (case id+ ::serverbound/handshaking (swap! state assoc ::phase/phase (req! packet ::phase/phase))+ ::serverbound/login-acknowledged (swap! state assoc ::phase/phase ::phase/config)+ ::serverbound/finish-config (swap! state assoc ::phase/phase ::phase/play)+ ::serverbound/login-start+ (let [{:keys! [username uuid]} packet]+ (swap! state assoc ::player/uuid uuid))+ nil)+ (merge packet (select-keys @state [::player/uuid]))))+ (catch Throwable t+ (close)+ (when-not (or (instance? SocketException t) (instance? EOFException t))+ (throw t)))))}] (io-thread (loop []- (when (= ::not-closed (deref closed-promise 0 ::not-closed))- (<!! (timeout 15000))- (when (#{::phase/config ::phase/play} (::phase/phase @state))- (put! clientbound-packets- {::pk/id ::clientbound/keep-alive- :id (rand-int Integer/MAX_VALUE)}))- (recur))))-- (io-thread- (try- (loop []- (when-let [packet (handle-serverbound-frame! state conn (streams/read-frame!! input-stream))]- (put! serverbound-packets packet))- (recur))- (catch EOFException _)- (catch SocketException _)- (finally- (close! serverbound-packets)- (deliver closed-promise (@state ::player/uuid))- (Socket/.close socket))))-- (io-thread- (try- (loop []- (when-some [packet (<!! clientbound-packets)]- (streams/write-frame!! (encode-packet! packet (req! @state ::phase/phase)) output-stream)- (recur)))- (catch SocketException _)- (finally- (close! clientbound-packets))))+ (Thread/sleep 15000)+ (when (#{::phase/config ::phase/play} (::phase/phase @state))+ ((::send-packet conn)+ {::pk/id ::clientbound/keep-alive+ :id (rand-int Integer/MAX_VALUE)}))+ (recur))) conn))