I'm trying to run clojure.core.server/start-server
but instead of using the repl I want a custom function as accept option. I'm following this post where a repl server is executed as
clojure -X clojure.core.server/start-server :name '"server"' :port 5555 :accept clojure.core.server/repl :server-daemon false
What requirements do I need to pass a function to accept opt? What if I only want to print the request from any connection? Using something like clojure.core/println
didn't work
clojure -X clojure.core.server/start-server :name '"server"' :port 5555 :accept clojure.core/println :server-daemon false
btw, I can't even run start-server
on the repl itself, I've got the error everytime a made a request. Is it possible to run it from the repl?
(clojure.core.server/start-server {:name "server" :port 9000 :accept clojure.core.server/repl :server-daemon false})
#object[java.net.ServerSocket 0x25b865b5 "ServerSocket[addr=localhost/127.0.0.1,localport=9000]"]
user=> Exception in thread "Clojure Connection server 1" java.lang.ClassCastException: class clojure.core.server$repl cannot be cast to class clojure.lang.Named (clojure.core.server$repl and clojure.lang.Named are in unnamed module of loader 'app')
at clojure.core$namespace.invokeStatic(core.clj:1612)
at clojure.core.server$accept_connection.invokeStatic(server.clj:73)
at clojure.core.server$start_server$fn__8998$fn__8999$fn__9001.invoke(server.clj:117)
at clojure.lang.AFn.run(AFn.java:22)
at java.base/java.lang.Thread.run(Thread.java:833)
The start-server
function states, that :accept
must be a namespaced
symbol (so this is the reason, why you see the error in your REPL
(you are passing a variable; use 'clojure.core/println
instead --
note the leading '
).
As for passing your own function, it helps to take a look at the
function clojure.core.server/accept-connection
, what is actually going
on. So basically your :accept
function gets called with *in*
,
*out*
, *err*
redirected (and also a binding of *session*
with some
book-keeping) and the :args
. So you want to read/write on
stdin/stdout in your function and parameterize with the given arguments.
E.g. create a file src/so.clj
with the following content:
(ns so)
(defn accept
[prefix]
(loop []
(println prefix (read-line))
(recur)))
Then start the server from the same root:
clojure -X clojure.core.server/start-server :name '"server"' :port 5555 \
:accept so/accept \
:args '[">>>"]' \
:server-daemon false
Note the :accept
symbol (it's coming from the shell, so Clojure reads
that as a symbol) points to the namespace and the function within. Make
sure, things match up with the class-path (src
is a default source
path for the Clojure CLI).
Also note the passing of the :args
represented as an EDN array.
Inside accept-connection
the call to your function is then (apply accept args)
, so you can assume regular arguments in your accept-fn.
Then test your server with e.g. telnet
:
% telnet localhost 5555
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello
>>> hello
world
>>> world