c2b86ae
Branches > facts > c2b86ae > files
Move client I/O connection to an agent
Commit: c2b86ae820c25e5ea6944e421995cea1e9d6b2f4
Parent: 754557c
5 changed files:
src/net/bowmap/network/client.clj view file
@@ -1,35 +1,19 @@ (ns net.bowmap.network.client (:require [clojure.spec.alpha :as s]- [net.bowmap.network.packets.clientbound :refer [encode-packet!]]- [net.bowmap.network.packets.serverbound :refer [decode-packet!]]+ [net.bowmap.network.connection :as connection] [net.bowmap.network.state :as state]- [net.bowmap.network.streams :as streams] [net.bowmap.server.entity :as entity]- [net.bowmap.server.server :as server])- (:import- [java.net Socket]))+ [net.bowmap.server.server :as server])) -(s/def ::client (s/keys :opt [::state/connection-state ::socket]))+(s/def ::client (s/keys :opt [::state/connection-state ::connection/connection])) (defn client [socket] (ref {::state/connection-state ::state/handshaking- ::socket socket}))--(defn read-packet! [client-ref]- (let [{:keys! [::socket ::state/connection-state]} @client-ref- frame (streams/read-frame!! (Socket/.getInputStream socket))]- (decode-packet! frame connection-state)))--; TODO handle errors here as well to disconnect client?-(defn send-packet! [client-ref packet]- (let [{:keys! [::socket ::state/connection-state]} @client-ref]- #_(println "sending packet out: " packet)- (streams/write-frame!! (encode-packet! packet connection-state) (Socket/.getOutputStream socket))- client))+ ::connection/connection (connection/connection socket)})) (defn leave! [client-ref]- (let [{:keys! [::socket] :keys [::playing? ::entity/uuid]} @client-ref]+ (let [{:keys! [::connection/connection] :keys [::playing? ::entity/uuid]} @client-ref] (try (dosync (when playing?@@ -37,4 +21,4 @@ ; Probably should come up with a better solution (commute server/players dissoc uuid))) (finally- (Socket/.close socket)))))+ (send connection connection/close!)))))src/net/bowmap/network/connection.clj view file
@@ -0,0 +1,30 @@+(ns net.bowmap.network.connection+ (:require+ [net.bowmap.network.packets.clientbound :refer [encode-packet!]]+ [net.bowmap.network.streams :as streams])+ (:import+ [java.net Socket]))++; Connection can be sent and received frames?+; It is the I/O part of the client+; Clients are then I/O free++(defn connection [socket]+ (agent {::socket socket+ ::input-stream (Socket/.getInputStream socket)+ ::output-stream (Socket/.getOutputStream socket)}))++(defn read-frame! [input-stream]+ (let [{:keys! [::input-stream]} connection]+ (streams/read-frame!! input-stream))+ connection)++(defn send-frame-action! [connection frame]+ (let [{:keys! [::output-stream]} connection]+ (streams/write-frame!! frame output-stream)+ connection))++(defn keep-alive-action! [connection])++(defn close! [connection]+ (Socket/.close (req! connection ::socket)))src/net/bowmap/network/handle.clj view file
@@ -1,9 +1,8 @@ (ns net.bowmap.network.handle (:require- [clojure.core.async :refer [io-thread]] [net.bowmap.network.chunk :as chunk]- [net.bowmap.network.client :refer [send-packet!]] [net.bowmap.network.client :as client]+ [net.bowmap.network.connection :as connection] [net.bowmap.network.packet :as pk] [net.bowmap.network.packets.clientbound :as clientbound] [net.bowmap.network.packets.registry :as registry]@@ -176,16 +175,9 @@ :keepalive? true})) (defn handle!! [client-ref packet]- (let [{:keys! [client packets] :keys [keepalive?]} (handle-packet @client-ref packet)]- (dosync- (ref-set client-ref client))- (doseq [pk packets]- (send-packet! client-ref pk))- (when keepalive?- (io-thread- (loop []- (Thread/sleep 20000)- (client/send-packet! client-ref {::pk/id ::clientbound/keep-alive- :id (long (* (rand) Long/MAX_VALUE))})- (recur))))- client))+ (dosync+ (let [{:keys! [client packets] :keys [keepalive?]} (handle-packet @client-ref packet)]+ (ref-set client-ref client)+ (let [{:keys! [::connection/connection ::state/connection-state]} @client-ref]+ (doseq [pk packets]+ (send connection connection/send-frame-action! (clientbound/encode-packet! pk connection-state)))))))src/net/bowmap/network/packets/clientbound.clj view file
@@ -283,6 +283,7 @@ (def packet-ids (build-packet-id-index packet-order)) (def packet-encoders (build-packet-encode-functions packets)) +; TODO update docstring (defn encode-packet! "Encodes a message into a packet. Like decoding, encoding a packet requires the connection state, as packetsrc/net/bowmap/network/server.clj view file
@@ -2,20 +2,27 @@ (:require [clojure.core.async :refer [io-thread]] [net.bowmap.network.client :as client :refer [leave!]]- [net.bowmap.network.handle :as handle])+ [net.bowmap.network.handle :as handle]+ [net.bowmap.network.packets.serverbound :refer [decode-packet!]]+ [net.bowmap.network.state :as state]+ [net.bowmap.network.streams :as streams]) (:import [java.io EOFException]- [java.net ServerSocket SocketException]))+ [java.net ServerSocket Socket SocketException])) (defn start-server! [port] (let [server (ServerSocket. port)] (loop [] (let [socket (ServerSocket/.accept server)+ input-stream (Socket/.getInputStream socket) client-ref (client/client socket)] (io-thread (try (loop []- (handle/handle!! client-ref (client/read-packet! client-ref))+ (let [frame (streams/read-frame!! input-stream)]+ (dosync+ (->> (decode-packet! frame (::state/connection-state @client-ref))+ (handle/handle!! client-ref)))) (recur)) (catch EOFException _) (catch SocketException _)