jarohen / chord Goto Github PK
View Code? Open in Web Editor NEWA library designed to bridge the gap between the triad of CLJ/CLJS, web-sockets and core.async.
A library designed to bridge the gap between the triad of CLJ/CLJS, web-sockets and core.async.
It would be great if there were a minimal working example using chord
with http-kit
. The current example uses a lot of tools from several libraries, which is fine, but makes it difficult to understand at a basic level how to use this library. I'd be happy to send you a pull request of such an example but I'm having difficulty hooking it up. ๐
Hi!
When my server closes the websocket channel, the client throws an error:
WebSocket connection to 'ws://localhost:9009/gateways/0200000100000205/progress.ws' failed: Close received after close
and the ws-channel returns {:message nil}
.
I've boiled the server code down to:
(with-channel request ws-ch
{:format :json-kw}
(go
(>! ws-ch "testing")
(<! (timeout 1000))
(close! ws-ch)))
On the client I then first get {:message "testing"}
and after 1 second, I get the above error, then {:message nil}
.
My client code looks like this pared down:
(defn connect [uri]
(let [c (chan)]
(go
(let [{:keys [ws-channel error]} (<! (ws-ch (str "ws://" (.-host js/location) uri) {:format :json}))]
(when-not error
(loop []
(let [v (<! ws-channel)]
(prn v)
(if-let [{:keys [message error]} v]
(cond
error (do
(prn error)
(recur))
message (do
(>! c message)
(recur))
:else (close! c))
(close! c)))))))
c))
Any idea what's going on?
Thanks!
Hi James,
I can't see that chord actually uses anything from com.cemerick/urls, and it adds about 14MB of dependencies to uberjars built with a dependency on chord:
alexh@box:~/chord$ lein uberjar
Created /home/alexh/chord/target/chord-0.7.0.jar
Created /home/alexh/chord/target/chord-0.7.0-standalone.jar
alexh@box:~/chord$ ls -lh target/chord-0.7.0-standalone.jar
-rw-rw-r-- 1 alexh alexh 21M Feb 17 11:12 target/chord-0.7.0-standalone.jar
alexh@box:~/chord$ vim project.clj # REMOVE DEPENDENCY
alexh@box:~/chord$ lein uberjar
Created /home/alexh/chord/target/chord-0.7.0.jar
Created /home/alexh/chord/target/chord-0.7.0-standalone.jar
alexh@box:~/chord$ ls -lh target/chord-0.7.0-standalone.jar
-rw-rw-r-- 1 alexh alexh 7.2M Feb 17 11:13 target/chord-0.7.0-standalone.jar
Would be great to cut this down!
Thanks,
Alex
There's a problem with the with-channel
logic, specifically on lines 59 to 61:
opts (when opts? opts)
body (cond->> body
(not opts?) (cons opts))
If opts?
is false, then opts
is bound to nil
, and body
is bound to (cons nil body)
.
To fix this, the opts rebinding should come after the body rebinding.
Got a system going with {:format :transit-json}, but now when I try to switch to fression with code like this:
(defn ws-handler [{:keys [ws-channel] :as req}]
(go
(println (<! ws-channel))
(>! ws-channel {1 ["recieving you"]})))
...
(GET "/ws" []
(wrap-websocket-handler ws-handler {:format :fression}))
The wrap-socket-handler fails with:
java.lang.IllegalArgumentException: No method in multimethod 'formatter*' for dispatch value: :fression
Are there any docs or examples of working fression client/server connections?
As soon as I require [chord.client :refer [ws-ch]]
I get the following error
clojure.lang.ExceptionInfo : Referred var fressian-cljs.fns/lookup does not exist at line 1
file:/Users/ianp/.m2/repository/net/unit8/fressian-cljs/0.1.0/fressian-cljs-0.1.0.jar!/fressian_cljs/reader.cljs
Which is annoying as I don't plan on using Fressian. I think that keeping the chord-fressian and chord-transit formats as separate dependencies was a better approach that lumping everything together in one project, this would also make it easier to add additional formats later on.
Trying to run a project with chord (server-side) gives me the following error:
$ lein run
Exception in thread "main" clojure.lang.ExceptionInfo: Call to clojure.core/refer-clojure did not conform to spec:
In: [2 1] val: :as fails at: [:args :exclude :op :quoted-spec :spec] predicate: #{:exclude}
In: [2 1] val: :as fails at: [:args :only :op :quoted-spec :spec] predicate: #{:only}
In: [2 1] val: :as fails at: [:args :rename :op :quoted-spec :spec] predicate: #{:rename}
In: [2] val: (quote :as) fails at: [:args :exclude :op :spec] predicate: #{:exclude}
In: [2] val: (quote :as) fails at: [:args :only :op :spec] predicate: #{:only}
In: [2] val: (quote :as) fails at: [:args :rename :op :spec] predicate: #{:rename}
#:clojure.spec.alpha{:problems ({:path [:args :exclude :op :spec], :pred #{:exclude}, :val (quote :as), :via [], :in [2]} {:path [:args :exclude :op :quoted-spec :spec], :pred #{:exclude}, :val :as, :via [], :in [2 1]} {:path [:args :only :op :spec], :pred #{:only}, :val (quote :as), :via [], :in [2]} {:path [:args :only :op :quoted-spec :spec], :pred #{:only}, :val :as, :via [], :in [2 1]} {:path [:args :rename :op :spec], :pred #{:rename}, :val (quote :as), :via [], :in [2]} {:path [:args :rename :op :quoted-spec :spec], :pred #{:rename}, :val :as, :via [], :in [2 1]}), :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2436 0x17d76ebb "clojure.spec.alpha$regex_spec_impl$reify__2436@17d76ebb"], :value ((quote :exclude) (quote [reduce into merge map take partition partition-by]) (quote :as) (quote core)), :args ((quote :exclude) (quote [reduce into merge map take partition partition-by]) (quote :as) (quote core))}, compiling:(clojure/core/async.clj:9:1)
at clojure.lang.Compiler.checkSpecs(Compiler.java:6891)
at clojure.lang.Compiler.macroexpand1(Compiler.java:6907)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6989)
at clojure.lang.Compiler.analyze(Compiler.java:6773)
at clojure.lang.Compiler.analyze(Compiler.java:6729)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:6100)
at clojure.lang.Compiler$TryExpr$Parser.parse(Compiler.java:2307)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:7003)
at clojure.lang.Compiler.analyze(Compiler.java:6773)
at clojure.lang.Compiler.analyze(Compiler.java:6729)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:6100)
at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5460)
at clojure.lang.Compiler$FnExpr.parse(Compiler.java:4022)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:7001)
at clojure.lang.Compiler.analyze(Compiler.java:6773)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6991)
at clojure.lang.Compiler.analyze(Compiler.java:6773)
at clojure.lang.Compiler.analyze(Compiler.java:6729)
at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3813)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:7005)
at clojure.lang.Compiler.analyze(Compiler.java:6773)
at clojure.lang.Compiler.analyze(Compiler.java:6729)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:6100)
at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5460)
at clojure.lang.Compiler$FnExpr.parse(Compiler.java:4022)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:7001)
at clojure.lang.Compiler.analyze(Compiler.java:6773)
at clojure.lang.Compiler.eval(Compiler.java:7059)
at clojure.lang.Compiler.eval(Compiler.java:7051)
at clojure.lang.Compiler.load(Compiler.java:7514)
at clojure.lang.RT.loadResourceScript(RT.java:379)
at clojure.lang.RT.loadResourceScript(RT.java:370)
at clojure.lang.RT.load(RT.java:460)
at clojure.lang.RT.load(RT.java:426)
at clojure.core$load$fn__6548.invoke(core.clj:6046)
at clojure.core$load.invokeStatic(core.clj:6045)
at clojure.core$load.doInvoke(core.clj:6029)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5848)
at clojure.core$load_one.invoke(core.clj:5843)
at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
at clojure.core$load_lib.invokeStatic(core.clj:5887)
at clojure.core$load_lib.doInvoke(core.clj:5868)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$load_libs.invokeStatic(core.clj:5925)
at clojure.core$load_libs.doInvoke(core.clj:5909)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$require.invokeStatic(core.clj:5947)
at clojure.core$require.doInvoke(core.clj:5947)
at clojure.lang.RestFn.invoke(RestFn.java:457)
at chord.http_kit$eval2678$loading__6434__auto____2679.invoke(http_kit.clj:1)
at chord.http_kit$eval2678.invokeStatic(http_kit.clj:1)
at chord.http_kit$eval2678.invoke(http_kit.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:7062)
at clojure.lang.Compiler.eval(Compiler.java:7051)
at clojure.lang.Compiler.load(Compiler.java:7514)
at clojure.lang.RT.loadResourceScript(RT.java:379)
at clojure.lang.RT.loadResourceScript(RT.java:370)
at clojure.lang.RT.load(RT.java:460)
at clojure.lang.RT.load(RT.java:426)
at clojure.core$load$fn__6548.invoke(core.clj:6046)
at clojure.core$load.invokeStatic(core.clj:6045)
at clojure.core$load.doInvoke(core.clj:6029)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5848)
at clojure.core$load_one.invoke(core.clj:5843)
at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
at clojure.core$load_lib.invokeStatic(core.clj:5887)
at clojure.core$load_lib.doInvoke(core.clj:5868)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$load_libs.invokeStatic(core.clj:5925)
at clojure.core$load_libs.doInvoke(core.clj:5909)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$require.invokeStatic(core.clj:5947)
at clojure.core$require.doInvoke(core.clj:5947)
at clojure.lang.RestFn.invoke(RestFn.java:619)
at oeillade.core$eval166$loading__6434__auto____167.invoke(core.clj:1)
at oeillade.core$eval166.invokeStatic(core.clj:1)
at oeillade.core$eval166.invoke(core.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:7062)
at clojure.lang.Compiler.eval(Compiler.java:7051)
at clojure.lang.Compiler.load(Compiler.java:7514)
at clojure.lang.RT.loadResourceScript(RT.java:379)
at clojure.lang.RT.loadResourceScript(RT.java:370)
at clojure.lang.RT.load(RT.java:460)
at clojure.lang.RT.load(RT.java:426)
at clojure.core$load$fn__6548.invoke(core.clj:6046)
at clojure.core$load.invokeStatic(core.clj:6045)
at clojure.core$load.doInvoke(core.clj:6029)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5848)
at clojure.core$load_one.invoke(core.clj:5843)
at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
at clojure.core$load_lib.invokeStatic(core.clj:5887)
at clojure.core$load_lib.doInvoke(core.clj:5868)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$load_libs.invokeStatic(core.clj:5925)
at clojure.core$load_libs.doInvoke(core.clj:5909)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$require.invokeStatic(core.clj:5947)
at clojure.core$require.doInvoke(core.clj:5947)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at user$eval149$fn__153.invoke(form-init4136363307982951547.clj:1)
at user$eval149.invokeStatic(form-init4136363307982951547.clj:1)
at user$eval149.invoke(form-init4136363307982951547.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:7062)
at clojure.lang.Compiler.eval(Compiler.java:7052)
at clojure.lang.Compiler.load(Compiler.java:7514)
at clojure.lang.Compiler.loadFile(Compiler.java:7452)
at clojure.main$load_script.invokeStatic(main.clj:278)
at clojure.main$init_opt.invokeStatic(main.clj:280)
at clojure.main$init_opt.invoke(main.clj:280)
at clojure.main$initialize.invokeStatic(main.clj:311)
at clojure.main$null_opt.invokeStatic(main.clj:345)
at clojure.main$null_opt.invoke(main.clj:342)
at clojure.main$main.invokeStatic(main.clj:424)
at clojure.main$main.doInvoke(main.clj:387)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.lang.Var.applyTo(Var.java:702)
at clojure.main.main(main.java:37)
Caused by: clojure.lang.ExceptionInfo: Call to clojure.core/refer-clojure did not conform to spec:
In: [2 1] val: :as fails at: [:args :exclude :op :quoted-spec :spec] predicate: #{:exclude}
In: [2 1] val: :as fails at: [:args :only :op :quoted-spec :spec] predicate: #{:only}
In: [2 1] val: :as fails at: [:args :rename :op :quoted-spec :spec] predicate: #{:rename}
In: [2] val: (quote :as) fails at: [:args :exclude :op :spec] predicate: #{:exclude}
In: [2] val: (quote :as) fails at: [:args :only :op :spec] predicate: #{:only}
In: [2] val: (quote :as) fails at: [:args :rename :op :spec] predicate: #{:rename}
{:clojure.spec.alpha/problems ({:path [:args :exclude :op :spec], :pred #{:exclude}, :val (quote :as), :via [], :in [2]} {:path [:args :exclude :op :quoted-spec :spec], :pred #{:exclude}, :val :as, :via [], :in [2 1]} {:path [:args :only :op :spec], :pred #{:only}, :val (quote :as), :via [], :in [2]} {:path [:args :only :op :quoted-spec :spec], :pred #{:only}, :val :as, :via [], :in [2 1]} {:path [:args :rename :op :spec], :pred #{:rename}, :val (quote :as), :via [], :in [2]} {:path [:args :rename :op :quoted-spec :spec], :pred #{:rename}, :val :as, :via [], :in [2 1]}), :clojure.spec.alpha/spec #object[clojure.spec.alpha$regex_spec_impl$reify__2436 0x17d76ebb "clojure.spec.alpha$regex_spec_impl$reify__2436@17d76ebb"], :clojure.spec.alpha/value ((quote :exclude) (quote [reduce into merge map take partition partition-by]) (quote :as) (quote core)), :clojure.spec.alpha/args ((quote :exclude) (quote [reduce into merge map take partition partition-by]) (quote :as) (quote core))}
at clojure.core$ex_info.invokeStatic(core.clj:4739)
at clojure.core$ex_info.invoke(core.clj:4739)
at clojure.spec.alpha$macroexpand_check.invokeStatic(alpha.clj:689)
at clojure.spec.alpha$macroexpand_check.invoke(alpha.clj:681)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.lang.Var.applyTo(Var.java:702)
at clojure.lang.Compiler.checkSpecs(Compiler.java:6889)
... 125 more
What helped was this comment that suggested downgrading Clojure, so I'm sticking with 1.8.0 for now.
Dispatching a large payload (~800KB) from websocket server using {:format :edn}
results in {:error :invalid-format}
on the ws-channel
on the client side. I don't have this issue with a smaller payload.
I was able to work around this by changing to {:format :transit-json}
on client and server.
Requiring chord.http
in my ClojureScript application causes:
Caused by: clojure.lang.ExceptionInfo: Referred var fressian-cljs.fns/lookup does not exist at line 1 file:/Users/me/.m2/repository/net/unit8/fressian-cljs/0.1.0/fressian-cljs-0.1.0.jar!/fressian_cljs/reader.cljs
This is using version 0.5.0
EDIT: This also happens when I require chord.client
as well.
When trying to use core.typed, I get the following initialization error:
CompilerException java.io.FileNotFoundException: Could not locate cljs/env__init.class or cljs/env.clj on classpath., compiling:(cljs/jvm/tools/analyzer.clj:1:1)
I've fiddled with my project.clj file, and I by process of elimination, I determined that the error only occurs when I include a dependency to jarhohen/chord.
Do you know what is causing this?
I'm unable to compile the example project. Tried compiling in two different environments.
$ lein dev
Compiling ClojureScript.
Compiling "target/resources/js/chord-example.js" from ["src" "checkouts/chord/src" "checkouts/chord/target/generated/cljs"]...
Started nREPL server, port 7888
WARNING: Use of undeclared Var cljs.core.async/do-alts at line 62 file:/home/thomas/.m2/repository/org/clojure/core.async/0.1.301.0-deb34a-alpha/core.async-0.1.301.0-deb34a-alpha.jar!/cljs/core/async/impl/ioc_helpers.cljs
WARNING: Bad method signature in protocol implementation, impl/Handler does not declare method called lock-id at line 214 file:/home/thomas/.m2/repository/org/clojure/core.async/0.1.301.0-deb34a-alpha/core.async-0.1.301.0-deb34a-alpha.jar!/cljs/core/async.cljs
WARNING: Use of undeclared Var cljs.core.async.impl.protocols/lock-id at line 217 file:/home/thomas/.m2/repository/org/clojure/core.async/0.1.301.0-deb34a-alpha/core.async-0.1.301.0-deb34a-alpha.jar!/cljs/core/async.cljs
WARNING: Referred var fressian-cljs.fns/lookup does not exist at line 1 file:/home/thomas/.m2/repository/net/unit8/fressian-cljs/0.1.0/fressian-cljs-0.1.0.jar!/fressian_cljs/reader.cljs
WARNING: Referred var fressian-cljs.fns/lookup does not exist at line 1 file:/home/thomas/.m2/repository/net/unit8/fressian-cljs/0.1.0/fressian-cljs-0.1.0.jar!/fressian_cljs/writer.cljs
WARNING: No such namespace: str at line 12 file:/home/thomas/.m2/repository/net/unit8/fressian-cljs/0.1.0/fressian-cljs-0.1.0.jar!/fressian_cljs/core.cljs
WARNING: Use of undeclared Var str/replace at line 12 file:/home/thomas/.m2/repository/net/unit8/fressian-cljs/0.1.0/fressian-cljs-0.1.0.jar!/fressian_cljs/core.cljs
WARNING: Use of undeclared Var fressian-cljs.core/load-string at line 24 file:/home/thomas/.m2/repository/net/unit8/fressian-cljs/0.1.0/fressian-cljs-0.1.0.jar!/fressian_cljs/core.cljs
Compiling "target/resources/js/chord-example.js" failed.
java.io.FileNotFoundException: checkouts/chord/src (No such file or directory)
(Unknown Source) java.io.FileInputStream.open
FileInputStream.java:138 java.io.FileInputStream.<init>
io.clj:229 clojure.java.io/fn
io.clj:69 clojure.java.io/fn[fn]
io.clj:165 clojure.java.io/fn
io.clj:69 clojure.java.io/fn[fn]
io.clj:102 clojure.java.io/reader
RestFn.java:410 clojure.lang.RestFn.invoke
analyzer.clj:1611 cljs.analyzer/forms-seq
analyzer.clj:1609 cljs.analyzer/forms-seq
closure.clj:335 cljs.closure/compile-file
closure.clj:384 cljs.closure/eval3247[fn]
closure.clj:293 cljs.closure/eval3182[fn]
closure.clj:397 cljs.closure/eval3234[fn]
closure.clj:293 cljs.closure/eval3182[fn]
compiler.clj:44 cljsbuild.compiler.SourcePaths/fn
core.clj:2612 clojure.core/map[fn]
LazySeq.java:40 clojure.lang.LazySeq.sval
LazySeq.java:49 clojure.lang.LazySeq.seq
RT.java:485 clojure.lang.RT.seq
core.clj:135 clojure.core/seq
core.clj:626 clojure.core/apply
core.clj:2650 clojure.core/mapcat
RestFn.java:423 clojure.lang.RestFn.invoke
compiler.clj:44 cljsbuild.compiler/cljsbuild.compiler.SourcePaths
closure.clj:962 cljs.closure/build
closure.clj:928 cljs.closure/build
compiler.clj:58 cljsbuild.compiler/compile-cljs[fn]
compiler.clj:57 cljsbuild.compiler/compile-cljs
compiler.clj:159 cljsbuild.compiler/run-compiler
form-init3789115033671463737.clj:1 user/eval4204[fn]
form-init3789115033671463737.clj:1 user/eval4204[fn]
LazySeq.java:40 clojure.lang.LazySeq.sval
LazySeq.java:49 clojure.lang.LazySeq.seq
RT.java:485 clojure.lang.RT.seq
core.clj:135 clojure.core/seq
core.clj:3004 clojure.core/dorun
core.clj:3020 clojure.core/doall
form-init3789115033671463737.clj:1 user/eval4204
Compiler.java:6768 clojure.lang.Compiler.eval
Compiler.java:6758 clojure.lang.Compiler.eval
Compiler.java:6758 clojure.lang.Compiler.eval
Compiler.java:7195 clojure.lang.Compiler.load
Compiler.java:7151 clojure.lang.Compiler.loadFile
main.clj:274 clojure.main/load-script
main.clj:279 clojure.main/init-opt
main.clj:307 clojure.main/initialize
main.clj:342 clojure.main/null-opt
main.clj:420 clojure.main/main
RestFn.java:421 clojure.lang.RestFn.invoke
Var.java:383 clojure.lang.Var.invoke
AFn.java:156 clojure.lang.AFn.applyToHelper
Var.java:700 clojure.lang.Var.applyTo
main.java:37 clojure.main.main
Starting web server, port 3000
I'm getting the same error seen in issues #23 #21 when I hit my /ws
endpoint from cljs. Here is what my project look likes:
Server:
https://github.com/colinkahn/foo/blob/8a40c80eba76797be7c94b6f4bcaded359fe75e7/src/clj/foo/core.clj
Client:
Project:
https://github.com/colinkahn/foo/blob/8a40c80eba76797be7c94b6f4bcaded359fe75e7/project.clj
I'm running it using lein cljsbuild auto dev
in one terminal and lein ring server
in another.
Hey,
I really like the library, but bidirectional .async channels seem like a contradiction to me. As this basically means bidirectional queue.
To me it would be cleaner to expose the read-ch
and write-ch
in a {:in ch, :out ch, :error ch}
map. This way they would be means of communicating with the websocket (as a separate concept), instead of becoming the websocket. This would also separate data reading from error handling.
Thoughts?
I see that Chord seems to directly depend on tools.reader
but it is not listed in dependencies. Shouldn't it be? If EDN support is optional, I recommend moving it to chord.edn
to make that clearer.
I'm attempting to run the lein dev target on the example-project.
I get the following:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space, compiling:(deps/toolsanalyzerjvm/v0v6v6/clojure/tools/analyzer/passes/jvm/validate.clj:227:1)
Tried increasing the JVM mem options, but didn't solve it : /
Full stacktrace below:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space, compiling:(deps/toolsanalyzerjvm/v0v6v6/clojure/tools/analyzer/passes/jvm/validate.clj:217:1)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6730)
at clojure.lang.Compiler.analyze(Compiler.java:6524)
at clojure.lang.Compiler.eval(Compiler.java:6779)
at clojure.lang.Compiler.load(Compiler.java:7227)
at clojure.lang.RT.loadResourceScript(RT.java:371)
at clojure.lang.RT.loadResourceScript(RT.java:362)
at clojure.lang.RT.load(RT.java:446)
at clojure.lang.RT.load(RT.java:412)
at clojure.core$load$fn__5448.invoke(core.clj:5866)
at clojure.core$load.doInvoke(core.clj:5865)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5671)
at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
at clojure.core$load_lib.doInvoke(core.clj:5710)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$load_libs.doInvoke(core.clj:5753)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$require.doInvoke(core.clj:5832)
at clojure.lang.RestFn.invoke(RestFn.java:436)
at deps.toolsanalyzerjvm.v0v6v6.clojure.tools.analyzer.passes.jvm.box$eval30149$loading__5340__auto____30150.invoke(box.clj:9)
at deps.toolsanalyzerjvm.v0v6v6.clojure.tools.analyzer.passes.jvm.box$eval30149.invoke(box.clj:9)
at clojure.lang.Compiler.eval(Compiler.java:6782)
at clojure.lang.Compiler.eval(Compiler.java:6771)
at clojure.lang.Compiler.load(Compiler.java:7227)
at clojure.lang.RT.loadResourceScript(RT.java:371)
at clojure.lang.RT.loadResourceScript(RT.java:362)
at clojure.lang.RT.load(RT.java:446)
at clojure.lang.RT.load(RT.java:412)
at clojure.core$load$fn__5448.invoke(core.clj:5866)
at clojure.core$load.doInvoke(core.clj:5865)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5671)
at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
at clojure.core$load_lib.doInvoke(core.clj:5710)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$load_libs.doInvoke(core.clj:5753)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$require.doInvoke(core.clj:5832)
at clojure.lang.RestFn.invoke(RestFn.java:703)
at deps.toolsanalyzerjvm.v0v6v6.clojure.tools.analyzer.jvm$eval29107$loading__5340__auto____29108.invoke(jvm.clj:9)
at deps.toolsanalyzerjvm.v0v6v6.clojure.tools.analyzer.jvm$eval29107.invoke(jvm.clj:9)
at clojure.lang.Compiler.eval(Compiler.java:6782)
at clojure.lang.Compiler.eval(Compiler.java:6771)
at clojure.lang.Compiler.load(Compiler.java:7227)
at clojure.lang.RT.loadResourceScript(RT.java:371)
at clojure.lang.RT.loadResourceScript(RT.java:362)
at clojure.lang.RT.load(RT.java:446)
at clojure.lang.RT.load(RT.java:412)
at clojure.core$load$fn__5448.invoke(core.clj:5866)
at clojure.core$load.doInvoke(core.clj:5865)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5671)
at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
at clojure.core$load_lib.doInvoke(core.clj:5710)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$load_libs.doInvoke(core.clj:5749)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$require.doInvoke(core.clj:5832)
at clojure.lang.RestFn.invoke(RestFn.java:619)
at refactor_nrepl.analyzer$eval28873$loading__5340__auto____28874.invoke(analyzer.clj:1)
at refactor_nrepl.analyzer$eval28873.invoke(analyzer.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6782)
at clojure.lang.Compiler.eval(Compiler.java:6771)
at clojure.lang.Compiler.load(Compiler.java:7227)
at clojure.lang.RT.loadResourceScript(RT.java:371)
at clojure.lang.RT.loadResourceScript(RT.java:362)
at clojure.lang.RT.load(RT.java:446)
at clojure.lang.RT.load(RT.java:412)
at clojure.core$load$fn__5448.invoke(core.clj:5866)
at clojure.core$load.doInvoke(core.clj:5865)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5671)
at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
at clojure.core$load_lib.doInvoke(core.clj:5710)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$load_libs.doInvoke(core.clj:5753)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$require.doInvoke(core.clj:5832)
at clojure.lang.RestFn.invoke(RestFn.java:436)
at refactor_nrepl.find_symbol$eval28700$loading__5340__auto____28701.invoke(find_symbol.clj:1)
at refactor_nrepl.find_symbol$eval28700.invoke(find_symbol.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6782)
at clojure.lang.Compiler.eval(Compiler.java:6771)
at clojure.lang.Compiler.load(Compiler.java:7227)
at clojure.lang.RT.loadResourceScript(RT.java:371)
at clojure.lang.RT.loadResourceScript(RT.java:362)
at clojure.lang.RT.load(RT.java:446)
at clojure.lang.RT.load(RT.java:412)
at clojure.core$load$fn__5448.invoke(core.clj:5866)
at clojure.core$load.doInvoke(core.clj:5865)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5671)
at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
at clojure.core$load_lib.doInvoke(core.clj:5710)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$load_libs.doInvoke(core.clj:5753)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$require.doInvoke(core.clj:5832)
at clojure.lang.RestFn.invoke(RestFn.java:457)
at refactor_nrepl.middleware$eval26865$loading__5340__auto____26866.invoke(middleware.clj:1)
at refactor_nrepl.middleware$eval26865.invoke(middleware.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6782)
at clojure.lang.Compiler.eval(Compiler.java:6771)
at clojure.lang.Compiler.load(Compiler.java:7227)
at clojure.lang.RT.loadResourceScript(RT.java:371)
at clojure.lang.RT.loadResourceScript(RT.java:362)
at clojure.lang.RT.load(RT.java:446)
at clojure.lang.RT.load(RT.java:412)
at clojure.core$load$fn__5448.invoke(core.clj:5866)
at clojure.core$load.doInvoke(core.clj:5865)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5671)
at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
at clojure.core$load_lib.doInvoke(core.clj:5710)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$load_libs.doInvoke(core.clj:5749)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$require.doInvoke(core.clj:5832)
at clojure.lang.RestFn.invoke(RestFn.java:457)
at nrepl.embed$eval18670$loading__5340__auto____18671.invoke(embed.clj:1)
at nrepl.embed$eval18670.invoke(embed.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6782)
at clojure.lang.Compiler.eval(Compiler.java:6771)
at clojure.lang.Compiler.load(Compiler.java:7227)
at clojure.lang.RT.loadResourceScript(RT.java:371)
at clojure.lang.RT.loadResourceScript(RT.java:362)
at clojure.lang.RT.load(RT.java:446)
at clojure.lang.RT.load(RT.java:412)
at clojure.core$load$fn__5448.invoke(core.clj:5866)
at clojure.core$load.doInvoke(core.clj:5865)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5671)
at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
at clojure.core$load_lib.doInvoke(core.clj:5710)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$load_libs.doInvoke(core.clj:5749)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$require.doInvoke(core.clj:5832)
at clojure.lang.RestFn.invoke(RestFn.java:512)
at chord.example.main$eval1296$loading__5340__auto____1297.invoke(main.clj:1)
at chord.example.main$eval1296.invoke(main.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6782)
at clojure.lang.Compiler.eval(Compiler.java:6771)
at clojure.lang.Compiler.load(Compiler.java:7227)
at clojure.lang.RT.loadResourceScript(RT.java:371)
at clojure.lang.RT.loadResourceScript(RT.java:362)
at clojure.lang.RT.load(RT.java:446)
at clojure.lang.RT.load(RT.java:412)
at clojure.core$load$fn__5448.invoke(core.clj:5866)
at clojure.core$load.doInvoke(core.clj:5865)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5671)
at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
at clojure.core$load_lib.doInvoke(core.clj:5710)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$load_libs.doInvoke(core.clj:5749)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$require.doInvoke(core.clj:5832)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at user$eval1281$fn__1283.invoke(form-init7123732214773336505.clj:1)
at user$eval1281.invoke(form-init7123732214773336505.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6782)
at clojure.lang.Compiler.eval(Compiler.java:6772)
at clojure.lang.Compiler.load(Compiler.java:7227)
at clojure.lang.Compiler.loadFile(Compiler.java:7165)
at clojure.main$load_script.invoke(main.clj:275)
at clojure.main$init_opt.invoke(main.clj:280)
at clojure.main$initialize.invoke(main.clj:308)
at clojure.main$null_opt.invoke(main.clj:343)
at clojure.main$main.doInvoke(main.clj:421)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:383)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.main.main(main.java:37)
Caused by: java.lang.OutOfMemoryError: PermGen space
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
at clojure.lang.DynamicClassLoader.defineClass(DynamicClassLoader.java:46)
at clojure.lang.Compiler$ObjExpr.getCompiledClass(Compiler.java:4833)
at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3993)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6721)
at clojure.lang.Compiler.analyze(Compiler.java:6524)
at clojure.lang.Compiler.eval(Compiler.java:6779)
at clojure.lang.Compiler.load(Compiler.java:7227)
at clojure.lang.RT.loadResourceScript(RT.java:371)
at clojure.lang.RT.loadResourceScript(RT.java:362)
at clojure.lang.RT.load(RT.java:446)
at clojure.lang.RT.load(RT.java:412)
at clojure.core$load$fn__5448.invoke(core.clj:5866)
at clojure.core$load.doInvoke(core.clj:5865)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5671)
at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
at clojure.core$load_lib.doInvoke(core.clj:5710)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$load_libs.doInvoke(core.clj:5753)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:632)
at clojure.core$require.doInvoke(core.clj:5832)
at clojure.lang.RestFn.invoke(RestFn.java:436)
at deps.toolsanalyzerjvm.v0v6v6.clojure.tools.analyzer.passes.jvm.box$eval30149$loading__5340__auto____30150.invoke(box.clj:9)
at deps.toolsanalyzerjvm.v0v6v6.clojure.tools.analyzer.passes.jvm.box$eval30149.invoke(box.clj:9)
at clojure.lang.Compiler.eval(Compiler.java:6782)
at clojure.lang.Compiler.eval(Compiler.java:6771)
at clojure.lang.Compiler.load(Compiler.java:7227)
http-kit seems to be failing out of maintenance, whereas immutant is actively supported. Could chord support immutant, like sente did?
I get the following exception while building with :optimizations :none:
java.lang.IllegalArgumentException: character to be escaped is missing
at java.util.regex.Matcher.appendReplacement(Matcher.java:809)
at java.util.regex.Matcher.replaceAll(Matcher.java:955)
at clojure.string$replace.invoke(string.clj:104)
at cljs.closure$lib_rel_path.invoke(closure.clj:1202)
at cljs.closure$rel_output_path.invoke(closure.clj:1221)
at cljs.closure$write_javascript.invoke(closure.clj:1342)
at cljs.closure$source_on_disk.invoke(closure.clj:1375)
at cljs.closure$output_unoptimized$fn__3879.invoke(closure.clj:1409)
at clojure.core$map$fn__4553.invoke(core.clj:2624)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:507)
at clojure.core$seq__4128.invoke(core.clj:137)
at clojure.core$filter$fn__4580.invoke(core.clj:2679)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:507)
at clojure.core$seq__4128.invoke(core.clj:137)
at clojure.core$map$fn__4553.invoke(core.clj:2616)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.Cons.next(Cons.java:39)
at clojure.lang.RT.next(RT.java:674)
at clojure.core$next__4112.invoke(core.clj:64)
at clojure.core$str$fn__4188.invoke(core.clj:530)
at clojure.core$str.doInvoke(core.clj:528)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invoke(core.clj:630)
at cljs.closure$deps_file.invoke(closure.clj:1102)
at cljs.closure$output_deps_file.invoke(closure.clj:1122)
at cljs.closure$output_unoptimized.doInvoke(closure.clj:1417)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invoke(core.clj:632)
at cljs.closure$build.invoke(closure.clj:1714)
at cljs.closure$build.invoke(closure.clj:1627)
at cljsbuild.compiler$compile_cljs$fn__4085.invoke(compiler.clj:81)
at cljsbuild.compiler$compile_cljs.invoke(compiler.clj:80)
at cljsbuild.compiler$run_compiler.invoke(compiler.clj:187)
at user$eval4219$iter__4255__4259$fn__4260$fn__4278.invoke(form-init2688236187975739560.clj:1)
at user$eval4219$iter__4255__4259$fn__4260.invoke(form-init2688236187975739560.clj:1)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:507)
at clojure.core$seq__4128.invoke(core.clj:137)
at clojure.core$dorun.invoke(core.clj:3009)
at clojure.core$doall.invoke(core.clj:3025)
at user$eval4219.invoke(form-init2688236187975739560.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6782)
at clojure.lang.Compiler.eval(Compiler.java:6772)
at clojure.lang.Compiler.load(Compiler.java:7227)
at clojure.lang.Compiler.loadFile(Compiler.java:7165)
at clojure.main$load_script.invoke(main.clj:275)
at clojure.main$init_opt.invoke(main.clj:280)
at clojure.main$initialize.invoke(main.clj:308)
at clojure.main$null_opt.invoke(main.clj:343)
at clojure.main$main.doInvoke(main.clj:421)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:383)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.main.main(main.java:37)
Subprocess failed
Importing only [chord.client :refer [ws-ch]] procs this issue. However, with :optimizations :whitespace it successfully compiles. What am I missing?
As per Henrik Eneroth's comment on Clojure group https://groups.google.com/d/msg/clojure/rnDBK-tcnOQ/I2itOgc33CUJ
I have an issue with the lib. There's a simple code handling websocket messages from server.
; if response is neither nil nor error - put it into another chan
(defn handle-server-msg [{:keys [error message] :as resp} handler-ch]
(when resp
(println "Received from server" resp)
(if error
(println "Got error from server" error)
(let [{:keys [messages]} message]
(doall (map #(put! handler-ch %) messages))))))
; install receiver which just calls function above
(defn install! [handler-ch]
(go
(let [ws-url (str "ws://" (.-host js/location) "/sync")
{:keys [ws-channel error] :as r} (<! (ws-ch ws-url {:format :json}))]
(if error
(println "Error opening websocket" error)
(do
(set! *ws-chan* ws-channel)
(go-loop []
(handle-server-msg (<! *ws-chan*) handler-ch)
(recur)))))))
It works fine but when i turn down the server - chrome tab just hangs. Chrome task manager shows CPU consumption for this tab around 100% (Mac). It looks like ws-channel when connection breaks infinitely returns nil (tried println
in first line of handle-server-msg
) and it causes tab to hang.
How should i handle cases like this? Maybe introduce some timer on receiving nil and query chan on timer tick? Thanks in advance!
In Clojure, is there a way to open a websocket connection to a foreign server?
Thanks.
Hey again, James!
I'm experimenting with trying to get the client to reconnect to the server upon connection failure. My results are so-so, no doubt due to my inexperience with core.async.
If the server is not running, it seems that (<! (ws-ch address))
will wait indefinitely, even after server is running. What's the appropriate way to handle this? Can I provide a timeout to the initial channel, forcing it to close if it hasn't delivered the 2-way websocket-channel within x seconds? If placed in, for example, a go-loop
block, then connection attempts could be handled in this manner.
Hello! This is a "how does your awesome library work" question, not a bug or an issue. So:
I have single-repo Clojure server with a ClojureScript front-end. All the routes are Compojure in the server; the server, then, needs to be able to respond to a set of routes by passing data in to the client so it can respond correctly.
What I imagine doing, then, is having a single route for the client to hit to open its socket, then a handler on the server for routes that need to pass messages. Something like;
;; Server
(defroutes app-routes
(GET "/ws" [] somehow-return-a-web-socket)
(GET "/api/:foo [foo]" (pass-message-through-socket foo))
(GET "/api/auth/:bar" [bar] (pass-message-through-socket bar)))
The client opens a go-loop on "/ws", then listens to whatever is dispatched through it. What I can't tell is: does chord
support this? If so, what would somehow-return-a-web-socket
look like? (The other option I see is to have every route that needs to talk to the client open a different socket, and on the client listen to all of them using alts!
-- but somehow I find that less... pleasing.)
As a general public service, it might be worth mentioning this here: until tonight, I've been using the jetty
ring adapter for serving http -- as, I suspect many other folk do. (The Heroku docs all assume this, for instance). But: ring-jetty-adapter
is based on jetty... 7.
Which doesn't have websockets.
The errors one gets are comically unhelpful. Compojure barfs Render
errors. All your sockets are mysteriously nil
. Cool story, Jetty 7.
Anywho, a word to people using websockets, and by extention, chord: http-kit.
Thank you for writing this library.
I ran the example project to explore chord
, a first encounter if you will.
Anything I type in the text box yields the following message:
{:error :invalid-json, :invalid-msg "{:received \"You passed: '\\\"Hi there\\\"' at Wed Mar 26 16:28:23 IST 2014.\"}"}
Granted, I can see that a bidirectional communication channel is established, which is the most important thing I expect from a websockets library. I suppose you will explain that data needs to be passed a certain way. Still, I'm not expecting to see format errors in the demo. Alternatively, please provide instructions on the example page.
Hey, James!
I catch error -
When server get first web socket (after restart) and this message really fast one like:
socket.onopen = e => { socket.send("hi"); };
than server side miss it for some reason.
Sorry, I didn't spend time to investigate it. I didn't use ClojureScript for project, so I rewrite everything just with http-kit
with plain on-receive
.
Maybe you have a clue about it. If not, I'll spend some time this or next weekend.
I am trying to create a chat-room websocket services with the help of example code in this https://github.com/jarohen/chord , the problem i don't able to create a different channel with respect to id. and i don't have good knowledge on clojure.core.async here is my code
(ns cljs-lein-project.mychat
(:require [compojure.core :refer [GET defroutes]]
[compojure.handler :refer [site]]
[chord.http-kit :refer [wrap-websocket-handler]]
[org.httpkit.server :refer [run-server]]
[clojure.core.async :as a])
(:gen-class))
(defn ws-handler
[id {:keys [ws-channel] :as req} {:keys [chat-ch chat-mult]}]
(let [tapped-ch (a/chan)
room-id id]
(a/tap chat-mult tapped-ch)
(a/go
(a/>! chat-ch {:type :user-joined :room-id room-id})
(loop []
(a/alt!
tapped-ch ([message]
(if message
(do
(a/>! ws-channel message)
(recur))
(a/close! ws-channel)))
ws-channel ([ws-message]
(if ws-message
(do
(println ws-message)
(a/>! chat-ch
{:type :message
:message (:message ws-message)
:room-id room-id})
(recur))
(do
(a/untap chat-mult tapped-ch)
(a/>! chat-ch
{:type :user-left
:room-id room-id})))))))))
(def with-chat-chs1
(let [chat-ch (a/chan)
chat-mult (a/mult chat-ch)]
{:chat-ch chat-ch
:chat-mult chat-mult}))
(def with-chat-chs2
(let [chat-ch (a/chan)
chat-mult (a/mult chat-ch)]
{:chat-ch chat-ch
:chat-mult chat-mult}))
(defroutes chat-routes
(GET "/user-chat/:id" [id]
(-> #(ws-handler id % with-chat-chs1)
(wrap-websocket-handler {:format :transit-json})))
(GET "/admin-chat/:id" [id]
(-> #(ws-handler id % with-chat-chs2)
(wrap-websocket-handler {:format :transit-json}))))
(defn run-chat []
(run-server
(site #'chat-routes)
{:port 3008}))
If i connect to ws://localhost:3008/user-chat/235 and ws://localhost:3008/user-chat/236 Here the both routes are different right but massages are visible in both uri so please give me any idea to overtake this issue. I think the problem with my def's
Hi,
I have trouble running chord on Ubuntu (seems to work fine on mac). When running the example project i get the following stack trace when accessing the /ws service.
java.lang.IllegalArgumentException: No implementation of method: :render of protocol: #'compojure.response/Renderable found for class: clojure.core.async.impl.channels.ManyToManyChannel
at clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:544)
at compojure.response$eval313$fn__314$G__304__321.invoke(response.clj:10)
at compojure.response$eval352$fn__353.invoke(response.clj:27)
at compojure.response$eval313$fn__314$G__304__321.invoke(response.clj:10)
at compojure.core$make_route$fn__488.invoke(core.clj:93)
at compojure.core$if_route$fn__472.invoke(core.clj:39)
at compojure.core$if_method$fn__465.invoke(core.clj:24)
at compojure.core$routing$fn__494.invoke(core.clj:106)
at clojure.core$some.invoke(core.clj:2515)
at compojure.core$routing.doInvoke(core.clj:106)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invoke(core.clj:626)
at compojure.core$routes$fn__498.invoke(core.clj:111)
at org.httpkit.server.HttpHandler.run(RingHandler.java:91)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Do you have any idea whats wrong and what I can do to fix it?
Would it be possible to use Node.js as server somehow? Or is my best bet to use something Node-native, like Socket.io?
When running lein dev
on the example-project
, I get the following exception.
SEVERE: Error compiling CLJS...
clojure.lang.ExceptionInfo: failed compiling file:ui-src/chord/example/front_end.cljs {:file #object[java.io.File 0x44e4c991 "ui-src/chord/example/front_end.cljs"]}
at clojure.core$ex_info.invoke(core.clj:4593)
at cljs.compiler$compile_file$fn__11304.invoke(compiler.cljc:1146)
at cljs.compiler$compile_file.invoke(compiler.cljc:1109)
at cljs.compiler$compile_root.invoke(compiler.cljc:1181)
at cljs.closure$compile_dir.invoke(closure.clj:385)
at cljs.closure$eval11670$fn__11671.invoke(closure.clj:425)
at cljs.closure$eval11623$fn__11624$G__11614__11631.invoke(closure.clj:331)
at cljs.closure$eval11683$fn__11684.invoke(closure.clj:439)
at cljs.closure$eval11623$fn__11624$G__11614__11631.invoke(closure.clj:331)
at yoyo.cljs$compile_cljs_BANG_$reify__12087$fn__12088.invoke(cljs.clj:55)
at clojure.core$map$fn__4553.invoke(core.clj:2622)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:507)
at clojure.core$seq__4128.invoke(core.clj:137)
at clojure.core$apply.invoke(core.clj:630)
at clojure.core$mapcat.doInvoke(core.clj:2660)
at clojure.lang.RestFn.invoke(RestFn.java:423)
at yoyo.cljs$compile_cljs_BANG_$reify__12087._compile(cljs.clj:55)
at cljs.closure$build.invoke(closure.clj:1476)
at yoyo.cljs$compile_cljs_BANG_$fn__12091.invoke(cljs.clj:61)
at yoyo.cljs$compile_cljs_BANG_.invoke(cljs.clj:60)
at yoyo.cljs$watch_cljs_BANG_.invoke(cljs.clj:90)
at yoyo.cljs$with_cljs_compiler.invoke(cljs.clj:142)
at chord.example.main$with_cljs_compiler.invoke(main.clj:31)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.lang.AFunction$1.doInvoke(AFunction.java:29)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at yoyo.system$make_system$fn__30294$fn__30295$fn__30296.invoke(system.clj:37)
at yoyo.system$make_system$fn__30294$fn__30295$fn__30296$fn__30300.invoke(system.clj:39)
at yoyo.system$constant_value$fn__30262.invoke(system.clj:8)
at yoyo.system$make_system$fn__30294$fn__30295$fn__30296.invoke(system.clj:37)
at yoyo.system$make_system$fn__30294.invoke(system.clj:44)
at yoyo.system$with_system_put_to$fn__30330.invoke(system.clj:57)
at clojure.lang.Var.invoke(Var.java:379)
at yoyo$run_system_BANG_$fn__28808.invoke(yoyo.clj:46)
at clojure.core$binding_conveyor_fn$fn__4444.invoke(core.clj:1916)
at clojure.lang.AFn.call(AFn.java:18)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: clojure.lang.ExceptionInfo: No such namespace: chord.http, could not locate chord/http.cljs, chord/http.cljc, or Closure namespace "chord.http" at line 1 ui-src/chord/example/front_end.cljs {:file "ui-src/chord/example/front_end.cljs", :line 1, :column 1, :tag :cljs/analysis-error}
at clojure.core$ex_info.invoke(core.clj:4593)
at cljs.analyzer$error.invoke(analyzer.cljc:384)
at cljs.analyzer$error.invoke(analyzer.cljc:382)
at cljs.analyzer$analyze_deps.invoke(analyzer.cljc:1293)
at cljs.analyzer$eval9926$fn__9928.invoke(analyzer.cljc:1545)
at clojure.lang.MultiFn.invoke(MultiFn.java:251)
at cljs.analyzer$analyze_seq.invoke(analyzer.cljc:1900)
at cljs.analyzer$analyze$fn__10176.invoke(analyzer.cljc:1992)
at cljs.analyzer$analyze.invoke(analyzer.cljc:1985)
at cljs.compiler$compile_file_STAR_$fn__11272.invoke(compiler.cljc:1027)
at cljs.compiler$with_core_cljs.invoke(compiler.cljc:968)
at cljs.compiler$compile_file_STAR_.invoke(compiler.cljc:988)
at cljs.compiler$compile_file$fn__11304.invoke(compiler.cljc:1129)
... 41 more
I'll submit a pull request for a fix now.
Some recent changes in #8 caused compilation to fail. There are no tests or CI that
should have caught this.
Chord tests can start a temporary http-kit server and talking to it over a Java WebSocket client (e.g. Jetty has one). Not sure how CLJS can be tested in the same suite but CLJS compilation can be part of the CI nonetheless.
Thanks for making chord - websockets and core.async is a great match. :-)
One issue: Are there any notifications or callbacks for when a client disconnects? In particular for this websocket endpoint that only sends data, and doesn't receive any. Or do I have to create some manual ACK from the client along with timeouts?
Hi James,
I currently have a small web service, using http-kit's websocket support, which broadcasts messages to a number of clients.
My connection handler looks like this:
(defn update-handler [request]
(with-channel request channel
(swap! clients conj channel)
(on-close channel (fn [status]
(swap! clients disj channel)
(println "channel closed: " status)))))
I want to convert my program to use chord so I don't have to do my own transit handling, but I'm not sure how to handle client disconnections to remove dead channels from clients
. As far as I can see on-close
isn't exposed. Am I just thinking about this wrong? Is there some better way of doing what I want?
Sorry if this is dumb, I'm very new.
Cheers,
Alex
When making a websocket connection to my server, chrod/client.cljs:35
is giving me the error mssage.
WebSocket connection to 'ws://localhost:8080/streaming' failed: Invalid frame header
What does this mean and how can I fix it? Thanks.
Hi there again!
So after getting fressian transport working, what I've found is when you send a message from the server to the client, the message appears on the client close to what was sent (a vector turns into a sequence), but when sending from the client to the server, instead of getting either, I seem to get an org.fressian.TaggedObject Object instead of a clj collection.
example project here: https://github.com/retrogradeorbit/multiplayer
After client connects it sends [:login :test] down the channel. On receipt, the server prints what it gets and the following appears:
message was org.fressian.TaggedObject@e272218
Note, this is embedded inside the hashmap response. Printing the whole message pulled from the channel:
{:message #object[org.fressian.TaggedObject 0x2f5285c "org.fressian.TaggedObject@2f5285c"]}
I'm getting a warning when compiling chord with ClojureScript 0.0-1913 and core.async 0.1.242.0-44b1e3-alpha:
WARNING: Use of undeclared Var chord/chord at line 45 file:/[...]/jarohen/chord/0.1.1/chord-0.1.1.jar!/chord.cljs
Attempting to execute the following ClojureScript:
(ns chord-test.client
(:require [chord :refer [ws-ch]]
[cljs.core.async :refer [<! >! put! close!]])
(:require-macros [cljs.core.async.macros :refer [go]]))
(go
(let [ws (<! (ws-ch "ws://localhost:8080/ws"))
{:keys [message error]} (<! ws)]
(if error
(js/console.log "Uh oh:" error)
(js/console.log "Hooray! Message:" message))))
Causes a JS exception:
Uncaught TypeError: Cannot read property 't10254' of undefined main.js:28472
combine_chs main.js:28472
ws_ch main.js:28524
(anonymous function)
(ws-ch "ws://localhost:8080/ws")
is failing. The exception occurs because chord.chord
is undefined in the generated Javascript:
chord.combine_chs = function combine_chs(ws, read_ch, write_ch) {
if(typeof chord.chord.t10254 !== "undefined") {
}else {
// ...
};
Here's the error I got, similar to an earlier report:
Opened channel from 127.0.0.1
Exception in thread "async-dispatch-1" java.lang.IllegalArgumentException: No implementation of method: :take! of protocol: #'clojure.core.async.impl.protocols/ReadPort found for
class: nil
at clojure.core$cache_protocol_fn.invoke(core_deftype.clj:544)
at clojure.core.async.impl.protocols$eval9453$fn__9454$G__9444__9461.invoke(protocols.clj:15)
at clojure.core.async.impl.ioc_macros$take_BANG.invoke(ioc_macros.clj:955)
at pts.server$ws_handler$fn__12878$state_machine__10798__auto____12879$fn__12881.invoke(server.clj:346)
at pts.server$ws_handler$fn__12878$state_machine__10798__auto____12879.invoke(server.clj:346)
at clojure.core.async.impl.ioc_macros$run_state_machine.invoke(ioc_macros.clj:945)
at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invoke(ioc_macros.clj:949)
at pts.server$ws_handler$fn__12878.invoke(server.clj:346)
at clojure.lang.AFn.run(AFn.java:22)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
java.lang.IllegalArgumentException: No implementation of method: :render of protocol: #'compojure.response/Renderable found for class: clojure.core.async.impl.channels.ManyToMany
Channel
Unfortunately, that user said he had no problems on Mac, which is what I'm using.
Any ideas?
I want to apply a transformation to everything I send up my websocket, so I thought I could pass a channel with a mapping transducer as write-ch.
This doesn't work as I'd hoped because my transducer sees messages after formatting, not before. So I have to thaw, apply the transformation, and freeze again in my transducer.
Ideally, I think the formatting would occur as the last thing before writing to and the first thing after reading from the websocket connection - so read-from-ws!
and write-from-ws!
would take a formatter, and apply thaw and freeze respectively, rather than involving core.async at all.
That way the user-supplied channels will always be dealing with unformatted values, which I suspect will be what people want/expect almost all the time, and we lose a bit of core.async overhead inside of chord. This would break backwards compatibility in that the change could break anyone passing a channel with a transducer as write-ch. However I suspect most uses of read-ch and write-ch are to apply buffering as all mine were until today :)
Happy to make this pull request if you like the idea!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.