Coder Social home page Coder Social logo

chord's People

Contributors

ageneau avatar charles-dyfis-net avatar cjohansen avatar giuliano108 avatar hadronzoo avatar jarohen avatar juliangamble avatar rosejn avatar rrichardson avatar tgetgood avatar timgluz avatar tlight avatar weavejester avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

chord's Issues

Server miss first message

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.

Problem with routing compojure

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

An obvious point in retrospect, but:

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.

How to handle connection attempts when server is not responding

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.

Problem on Ubuntu

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)

<IllegalArgumentException java.lang.IllegalArgumentException: No implementation of method: :take! of protocol: #'clojure.core.async.impl.protocols/ReadPort found for class: nil>

Do you have any idea whats wrong and what I can do to fix it?

No tests

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.

WARNING: Use of undeclared Var chord/chord at line 45

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 {
    // ...
    };

Bidirectional sockets complect sockets with channels.

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?

Serializing large message fails with {:format :edn}

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.

Including chord triggers core.typed initialization error

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?

Getting this error ``ERR_DISALLOWED_URL_SCHEME``

So I have cloned your project and everything is same. When I run lein figwheel also it doesn't give me any error also and it runs perfectly on http://localhost:3449/ but when I try to run on ws://localhost:3449/ws I'm getting this error
image

How do I use {:format :fression} on server side? (or: no method in multimethod for fression connection)

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?

Error with first time use

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?

Node.js

Would it be possible to use Node.js as server somehow? Or is my best bet to use something Node-native, like Socket.io?

with-channel without options doesn't work in 0.4.1

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.

tools.reader dependency

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.

0.5.0 fails to compile.

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.

Support immutant 2?

http-kit seems to be failing out of maintenance, whereas immutant is actively supported. Could chord support immutant, like sente did?

Error when using `chord.http` in ClojureScript

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.

Can't run with clojure 1.9.0

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.

Close received after close

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!

Equivalent of http-kit's on-close?

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

Unable to compile example project

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

Messages appear on server as TaggedObject rather than clojure value.

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"]}

Remove dependencyon com.cemerick/urls

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

Example suggestion

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. ๐Ÿ˜‰

Tab hangs the tab when connection is broken

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!

Example project - OutOfMemory error

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)

Opening a single socket to pass messages through

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.)

transducers on write-ch receive formatted value

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!

Clojure client?

I realize (looking at #20) that Clojure clients are not currently supported, but it would be a nice feature for the client API to work on Clojure as well. And just for the record (in regard to #20 again), http-kit does not have client-side websocket support, only server support.

How do I clean up after a client disconnects?

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?

Error when hitting ws endpoint from cljs

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:

https://github.com/colinkahn/foo/blob/8a40c80eba76797be7c94b6f4bcaded359fe75e7/src/cljs/foo/core.cljs#L53-L55

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.

Running lein dev on the examples gives an exception

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.

Strange exception while having :optimizations :none in cljsbuild

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?

Meeting user expectations at first encounter

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.