This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-12-18
Channels
- # adventofcode (20)
- # aleph (25)
- # announcements (4)
- # babashka (117)
- # beginners (150)
- # calva (4)
- # cider (9)
- # clj-on-windows (2)
- # clojure (9)
- # clojure-europe (4)
- # clojure-italy (3)
- # clojuredesign-podcast (18)
- # clojurescript (16)
- # conjure (1)
- # core-async (35)
- # cursive (13)
- # datalevin (6)
- # datomic (6)
- # fulcro (8)
- # hyperfiddle (5)
- # malli (8)
- # nextjournal (4)
- # off-topic (51)
- # pathom (4)
- # reagent (21)
- # sci (14)
- # shadow-cljs (22)
- # specter (3)
- # testing (22)
- # tools-deps (8)
- # xtdb (7)
beginner question about using manifold.stream/connect
with a aleph.http/websocket-connection
. Here is a handler function I wrote to try to get the hang of things and push some primitive data through a websocket
state*
is an atom
. I’m trying to just create a stream that I can push data to and read from the connection object.
Hi @mafcocinco. I’d be happy to help, but I need a few more details. A minimal, but full, example would help.
For starters, are you passing the handler
fn directly into start-server
as is? Because Aleph handlers only accept a single request parameter, but your handler takes two.
Cool. I’ll get you a full example.
This could probably be slightly simpler but hopefully gives the general idea of what I’m trying to accomplish
@mafcocinco And is the commented code what you’re running to test it, when you get the error?
(For future reference, you probably want to put all that in a (comment ....)
block for ease of REPLing)
yes, it is. And thanks, I will use comment
going forward.
@mafcocinco Hey, can you run your minimal example and verify that it shows the error you expect? There’s several things going wrong that aren’t what you initially described 🙂
1. ring.util.http-response
isn’t a ring namespace.
2. I’m getting `SEVERE: cannot coerce clojure.lang.PersistentArrayMap into binary representation
java.lang.IllegalArgumentException: Don’t know how to convert class clojure.lang.PersistentArrayMap into class java.nio.ByteBuffer` when I try to put into the core.async channel, which is a totally different error
1. Why did you add core.async? Manifold’s s/put
, which you described using earlier, is correct. You can use it to write directly to the stream in state*
Let me revise.
ring.util.http-response
is part of a metosin
library. That should be easy to remove
Cool. Can you also remove the worker thread relaying from core.async to the websocket stream? I think we need to simplify this a bit
Also, have you run the websocket examples in https://aleph.io/aleph/literate.html#aleph.examples.websocket ? Did they work ok?
yes, the examples worked for me.
the s/put!
returns true
but the s/take!
from conn
returns nil
OK, let me take another look. Which version of aleph are you on, btw?
^^^ @mafcocinco Which Aleph version (and other dep versions) are you using?
aleph 0.4.6
, reitit vesion 0.4.2
sorry for the delay, out on holiday break
@mafcocinco I took another look, and your problem is due to making the websocket handler fn Ring-compatible. Websockets don’t transmit HTTP, and thus, aren’t turned into Ring request maps. If you check the spec (https://datatracker.ietf.org/doc/html/rfc6455#page-38), you’ll see Websockets transmit either binary data or UTF-8 text frames (plus some control frames you don’t care about). I ran a few tests to refresh my memory, and you can put strings on a websocket, or anything byte-streams can convert to a byte array. On the receiving side, it looks like you get either strings or plain byte arrays.
I understand conceptually what you are saying but not sure how to implement it. Would that basically mean not calling (ring/ring-handler default)
for any websocket routes? E.g. passing the result of (ring/router)
directly to (http/start-server …)
?
@mafcocinco I think so. And you may or may not be able to use ring/router
either, if it tries to transform data. You want something that directly routes data to the handler, with no attempt to interpret the data as HTTP at all, invoke middlewares, etc.
After the initial handshake, WebSockets ditches HTTP and is much lower-level, more like TCP sockets. Ring and HTTP don’t apply. Maybe try reitit’s default, non-ring router.
I’ll give that a try. Thank you for your help!
I create start up the server (similar to what is shown in the https://aleph.io/examples/literate.html#aleph.examples.websocket), create the connection object by calling the handler (i.e.
). I then try to push data by pulling the stream
object out of the atom and call (s/put! stream {:a 42})
. That appears to work successfully but when I try to retrieve the data with (s/take! conn)
via the websocket connection, I get nil
.
@mafcocinco I took another look, and your problem is due to making the websocket handler fn Ring-compatible. Websockets don’t transmit HTTP, and thus, aren’t turned into Ring request maps. If you check the spec (https://datatracker.ietf.org/doc/html/rfc6455#page-38), you’ll see Websockets transmit either binary data or UTF-8 text frames (plus some control frames you don’t care about). I ran a few tests to refresh my memory, and you can put strings on a websocket, or anything byte-streams can convert to a byte array. On the receiving side, it looks like you get either strings or plain byte arrays.