Jump to content

Clojure Programming/Examples/REPL Socket

From Wikibooks, open books for an open world

As of Clojure 1.8, a built-in socket server is available that offers REPL functionality, see the API documentation for the clojure.core.server namespace.

(import '(java.net ServerSocket Socket SocketException)
        '(java.io InputStreamReader OutputStreamWriter)
        '(clojure.lang LineNumberingPushbackReader))

(defn on-thread [f]
  (doto (new Thread f) (.start)))

(defn create-server 
  "creates and returns a server socket on port, will pass the client
  socket to accept-socket on connection" 
  [accept-socket port]
    (let [ss (new ServerSocket port)]
      (on-thread #(when-not (. ss (isClosed))
                    (try (accept-socket (. ss (accept)))
                         (catch SocketException e))
                    (recur)))
      ss))

(defn repl
  "runs a repl on ins and outs until eof"
  [ins outs]
    (binding [*ns* (create-ns 'user)
              *warn-on-reflection* false
              *out* (new OutputStreamWriter outs)]
      (let [eof (new Object)
            r (new LineNumberingPushbackReader (new InputStreamReader ins))]
        (loop [e (read r false eof)]
          (when-not (= e eof)
            (prn (eval e))
            (flush)
            (recur (read r false eof)))))))

(defn socket-repl 
  "starts a repl thread on the iostreams of supplied socket"
  [s] (on-thread #(repl (. s (getInputStream)) (. s (getOutputStream)))))

(def server (create-server socket-repl 13579))
(def client (new Socket "localhost" 13579))

(def rdr (new LineNumberingPushbackReader 
              (new InputStreamReader (. client (getInputStream)))))
(def wtr (new OutputStreamWriter (. client (getOutputStream))))

(binding [*out* wtr]
  (prn '(+ 1 2 3))
  (flush)
  (read rdr))

(. server (close))
(. client (close))