[quote=“reneboer, post:17, topic:200471”]Hi,
Got some testing done and basically I get the following on the intercept function. It basically seems to work as documented on Vera. That is:
- call intercept
- call write
- call read
What does not make a difference is to call intercept on just receiving. In my example I read the WebSocket protocol that is a few header bytes including the payload length and then that payload. So I tried to have the incoming handler process the header, and then use luup.io.read to read the payload. That basically does not work, and adding intercept makes no difference. I have to use the incoming handler to process the payload bytes.
The luup.io.is_connected is no good indication for an open connection. After the peer closes the socket from their end, is_connected still returns true. In my case the peer starts replying with an HTTP 500 message, so I could use that to restore the connection.
Next test is openLuup.
Rene, my testing (also doing WebSocket) pretty much concurs. Trying identical things (using io.read() to get the payload data once I have the length) came to similar conclusions: switching to luup.io.read() for the payload yielded no benefit performance wise. I was able to get it to work using intercept() first, and noted that if I didn’t call intercept() first, a deadlock often resulted. IMPORTANT: this is specifically from within the handler. In other code, skipping the intercept() call does not result in a io.read() hang, you just run the risk of missing data.
That said, I have successfully used luup.io.read(), intercept() and together, like this (in “raw” mode) to handle getting the connection upgraded to WebSocket:
- Call luup.io.intercept();
- Use luup.io.write() to send the HTTP request with headers to upgrade to Websocket;
- Use luup.io.read() to gather response data, scanning for end of headers (consecutive cr/lf/crlf);
- Celebrate successful conversion to WebSocket;
- Send a WebSocket request (no-op is fine); this is necessary to reset the effect of the previous intercept();
- Use from that point forward.
I imagine this is similar to what you are doing.
But have you noticed the performance? Really, really poor. Appalling, actually. I removed all processing and just counted bytes and returned immediately from my incoming handler, trying to see how fast it would pass a 32KB JSON from the WebSocket endpoint, and the best I could do (on my Vera3) was just shy of 1800 bytes per second (18 seconds for the 32KB response–awful, just terrible). Receiving one byte at a time is just way too much overhead. I’ve already sent a note to Sorin requesting a “rawblock” protocol to return the entirety of a larger socket.receive() (e.g. 1024 bytes, connection MTU, or something even larger). But of course, that will be far off, if they agree to do it at all. For my application, as it is today it’s a non-starter, as it takes 15-20 seconds to receive the average payload, but updates come every 5 seconds or less on an active endpoint–it can’t keep up, not even close.
@akbooer, it would be great for openLuup if we could set a switch somewhere (openluup.longrawread = true?) to have the raw protocol return sock:recv(1024) or larger as described. At least then, performance on openLuup would shine over Vera (again).
Note: I also can’t stress enough that, as a best practice, string concatenation should not be used to reassemble the packet in an incoming handler. String concats in Lua are slowwww, and get worse as the string grows. It’s much faster to insert the data into a table, and then concat the table to a string when you have the entire payload.