Clojure Programming/Examples/REPL Socket
Appearance
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))