server.clj

Branches > main > 84b2f10 > files / src / net / bowmap / network / server.clj

(ns net.bowmap.network.server
  (:require
   [clojure.core.async :refer [<!! >!! chan close! io-thread]]
   [net.bowmap.network.stream :as stream])
  (:import
   [java.io Closeable]
   [java.net ServerSocket Socket]))

#_(defn- handle-client [client-chan stream info]
    (let [packets-in (chan 1 pk/packet-framer-xf)
          packets-out (chan)]
      (s/connect stream packets-in)
      (s/connect packets-out stream)
      (put! client-chan {::packets-in packets-in
                         ::packets-out packets-out})))

(defn new-client [socket]
  (let [packets-in (chan)
        packets-out (chan)]
    (io-thread
      (loop []
        (try (let [frame (stream/read-frame!! (Socket/.getInputStream socket))]
               (>!! packets-in frame))
             (catch Exception _
               ; Disconnect packet?
               (Socket/.close socket)))
        (recur)))

    (io-thread
      (loop []
        (let [frame (<!! packets-out)]
          (stream/write-frame!! frame (Socket/.getOutputStream socket)))
        (recur)))
    {::packets-in packets-in
     ::packets-out packets-out}))

(defn start-tcp-server!
  "Starts a TCP server at the given port. Returns a channel of clients as they connect.
   When the server closes, client channel will be closed, and vice versa."
  [& {:keys! [port]}]
  (let [server (ServerSocket. port)
        clients (chan 64)]
    (io-thread
      (try
        (loop []
          ; TODO TCP_NODELAY
          (let [socket (ServerSocket/.accept server)]
            (if (>!! clients (new-client socket))
              (recur)
              (Closeable/.close socket))))
        (catch Throwable t
          (close! clients)
          (throw t))))
    clients))