server.clj

Branches > client-handling-rewrite > 45c0952 > 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-server-process!
  "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."
  [port]
  (let [server (ServerSocket. port)
        clients (chan 64)
        shutdown (promise)]
    (io-thread
      (try
        (loop []
          ; TODO TCP_NODELAY
          (let [socket (ServerSocket/.accept server)]
            (if (>!! clients (new-client socket))
              (recur)
              (do (Closeable/.close socket)
                  (deliver shutdown :shutdown)))))
        (catch Throwable t
          (close! clients)
          (deliver shutdown :shutdown)
          (throw t))))
    {::client-chan clients
     ::shutdown shutdown}))

(defn start-tcp-server! [& {:keys! [port]}]
  (start-server-process! port))