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.

kingmob18: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

kingmob18: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.

kingmob19: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

kingmob19: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

kingmob19: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

kingmob20:12:00

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

kingmob09: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

kingmob11:12:37

Thanks @mafcocinco I’ll take a look later

thumbsup_all 1
kingmob18: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 …)?

kingmob21: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.

kingmob18: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.