Fork me on GitHub
#aleph
<
2021-12-18
>
mafcocinco03:12:11

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

mafcocinco03:12:20

state* is an atom. I’m trying to just create a stream that I can push data to and read from the connection object.

Matthew Davidson (kingmob)18:12:17

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.

mafcocinco18:12:17

Cool. I’ll get you a full example.

mafcocinco18:12:17

This could probably be slightly simpler but hopefully gives the general idea of what I’m trying to accomplish

Matthew Davidson (kingmob)18:12:50

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

mafcocinco19:12:24

yes, it is. And thanks, I will use comment going forward.

Matthew Davidson (kingmob)19:12:52

@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*

mafcocinco19:12:50

Let me revise.

mafcocinco19:12:25

ring.util.http-response is part of a metosin library. That should be easy to remove

Matthew Davidson (kingmob)19:12:49

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

Matthew Davidson (kingmob)19:12:22

Also, have you run the websocket examples in https://aleph.io/aleph/literate.html#aleph.examples.websocket ? Did they work ok?

mafcocinco19:12:39

yes, the examples worked for me.

mafcocinco19:12:57

the s/put! returns true but the s/take! from conn returns nil

Matthew Davidson (kingmob)20:12:00

OK, let me take another look. Which version of aleph are you on, btw?

Matthew Davidson (kingmob)09:12:59

^^^ @mafcocinco Which Aleph version (and other dep versions) are you using?

mafcocinco18:12:17

aleph 0.4.6, reitit vesion 0.4.2

mafcocinco18:12:34

sorry for the delay, out on holiday break

Matthew Davidson (kingmob)11:12:37

Thanks @mafcocinco I’ll take a look later

thumbsup_all 1
Matthew Davidson (kingmob)18:12:00

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

mafcocinco15:01:19

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 …)?

Matthew Davidson (kingmob)21:01:04

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

mafcocinco14:01:06

I’ll give that a try. Thank you for your help!

mafcocinco03:12:57

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.

Matthew Davidson (kingmob)18:12:00

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