nREPL websocket transport

108 views
Skip to first unread message

Jony Hudson

unread,
Feb 18, 2014, 7:09:59 AM2/18/14
to clojur...@googlegroups.com
Hi All,

 I'm trying to put together a websocket transport for nREPL, and have run aground. I think the problem is that I don't really understand much about transports, or the mysterious handle* function, and am guessing based on stuff I've found on Github! Maybe someone can give me a pointer in the right direction?

The code I've got at the moment:

(ns gorilla-repl.websocket-transport
  (:require [org.httpkit.server :as server]
            [clojure.tools.nrepl.server :as nrepl-server]
            [clojure.tools.nrepl.transport :as transport]
            [cheshire.core :as json]))

(defn send-json-over-ws
  [channel data]
  (println "Sent:" data)
  (server/send! channel (json/generate-string data)))

(defn process-message
  [handler transport data]
  (println "Recieved:" data)
  (let [parsed-message (json/parse-string data true)]
    (nrepl-server/handle* parsed-message handler transport)))

(defn ring-handler
  [request]
  (let [handler (nrepl-server/default-handler)]
    (server/with-channel
      request
      channel
      (let [transport (transport/fn-transport nil (partial send-json-over-ws channel))]
        (server/on-receive channel (partial process-message handler transport))))))
 
This sort of works, in the sense that I can send an {:op :clone} message, and it returns a sensible reply from which I can capture the new session. But if I then send an {:op :eval ...} message then I get a stack overflow error, which looks something like this:

Exception in thread "nREPL-worker-0" java.lang.StackOverflowError

at clojure.lang.RT.boundedLength(RT.java:1654)

at clojure.lang.AFn.applyToHelper(AFn.java:155)

at clojure.lang.AFn.applyTo(AFn.java:151)

at clojure.core$apply.invoke(core.clj:619)

at clojure.core$partial$fn__4190.doInvoke(core.clj:2396)

at clojure.lang.RestFn.invoke(RestFn.java:408)

at clojure.core$map$fn__4207.invoke(core.clj:2487)

at clojure.lang.LazySeq.sval(LazySeq.java:42)

at clojure.lang.LazySeq.seq(LazySeq.java:60)

at clojure.lang.RT.seq(RT.java:484)

at clojure.core$seq.invoke(core.clj:133)

at clojure.core.protocols$seq_reduce.invoke(protocols.clj:30)

at clojure.core.protocols$fn__6026.invoke(protocols.clj:54)

at clojure.core.protocols$fn__5979$G__5974__5992.invoke(protocols.clj:13)

at clojure.core$reduce.invoke(core.clj:6177)

at clojure.core$into.invoke(core.clj:6229)

at clojure.walk$walk.invoke(walk.clj:47)

at clojure.walk$postwalk.invoke(walk.clj:56)

at clojure.walk$stringify_keys.invoke(walk.clj:105)

at clojure.tools.nrepl.transport.FnTransport.send(transport.clj:28)

at clojure.tools.nrepl.middleware.pr_values$pr_values$fn$reify__2359.send(pr_values.clj:23)

at clojure.tools.nrepl.middleware.session$session_out$fn__2443.invoke(session.clj:51)

at clojure.tools.nrepl.middleware.session.proxy$java.io.Writer$0.flush(Unknown Source)

at clojure.tools.nrepl.middleware.session$session_out$fn__2450.doInvoke(session.clj:44)

at clojure.lang.RestFn.invoke(RestFn.java:460)

at clojure.tools.nrepl.middleware.session.proxy$java.io.Writer$0.write(Unknown Source)

at java.io.PrintWriter.write(PrintWriter.java:456)

at java.io.PrintWriter.write(PrintWriter.java:473)

at clojure.core$fn__5420.invoke(core_print.clj:187)

at clojure.lang.MultiFn.invoke(MultiFn.java:231)

at clojure.core$pr_on.invoke(core.clj:3322)

at clojure.core$print_map$fn__5428.invoke(core_print.clj:200)

at clojure.core$print_sequential.invoke(core_print.clj:58)

at clojure.core$print_map.invoke(core_print.clj:203)

at clojure.core$fn__5431.invoke(core_print.clj:207)

at clojure.lang.MultiFn.invoke(MultiFn.java:231)

at clojure.core$pr_on.invoke(core.clj:3322)

at clojure.core$pr.invoke(core.clj:3334)

at clojure.lang.AFn.applyToHelper(AFn.java:161)

at clojure.lang.RestFn.applyTo(RestFn.java:132)

at clojure.core$apply.invoke(core.clj:617)

at clojure.core$pr.doInvoke(core.clj:3340)

at clojure.lang.RestFn.applyTo(RestFn.java:139)

at clojure.core$apply.invoke(core.clj:617)

at clojure.core$prn.doInvoke(core.clj:3367)

at clojure.lang.RestFn.applyTo(RestFn.java:137)

at clojure.core$apply.invoke(core.clj:617)

at clojure.core$println.doInvoke(core.clj:3387)

at clojure.lang.RestFn.invoke(RestFn.java:421)

at gorilla_repl.websocket_transport$send_json_over_ws.invoke(websocket_transport.clj:9)

at clojure.lang.AFn.applyToHelper(AFn.java:163)

at clojure.lang.AFn.applyTo(AFn.java:151)

at clojure.core$apply.invoke(core.clj:619)

at clojure.core$partial$fn__4190.doInvoke(core.clj:2396)

at clojure.lang.RestFn.invoke(RestFn.java:408)

at clojure.tools.nrepl.transport.FnTransport.send(transport.clj:28)

at clojure.tools.nrepl.middleware.pr_values$pr_values$fn$reify__2359.send(pr_values.clj:23)

at clojure.tools.nrepl.middleware.session$session_out$fn__2443.invoke(session.clj:51)

at clojure.tools.nrepl.middleware.session.proxy$java.io.Writer$0.flush(Unknown Source)

at clojure.tools.nrepl.middleware.session$session_out$fn__2450.doInvoke(session.clj:44)


It probably doesn't help that I don't understand sessions properly still either! I don't know if there are any high-level documents that I've missed, but at the moment I don't think the structure of nREPL has clicked in my head from reading the source code.

So, if anyone could give me a pointer that would be great :-)

Thanks,


Jony
Reply all
Reply to author
Forward
0 new messages