How to handle ``on("message"`` for both binary and json messages
marwie opened this issue · 8 comments
Prerequisites
- I have written a descriptive issue title
- I have searched existing issues to ensure the issue has not already been raised
Issue
Hello,
I'm having an issue where I'm sending both json strings as well as flatbuffer/uin8 arrays to my websocket connection.
In on("message"
I'm calling toString
but that doesnt work for the Uint8Arrays being sent. How should I handle both message types / is there a flag to enable?
Current version: 4.2.2
error when calling toString
on a message that is actually an Uint8Array
SyntaxError: Unexpected token ¶ in JSON at position 0
at JSON.parse (<anonymous>)
at C:\git\needle-tiny-networking-package\packages\websocket\src\networking.js:52:28
at WebSocket.<anonymous> (C:\git\needle-tiny-networking-package\packages\websocket\src\proxy.js:31:17)
at WebSocket.emit (events.js:388:22)
at Receiver.receiverOnMessage (C:\git\needle-tiny-networking-package\packages\websocket\node_modules\fastify-websocket\node_modules\ws\lib\websocket.js:1137:20)
at Receiver.emit (events.js:376:20)
at Receiver.dataMessage (C:\git\needle-tiny-networking-package\packages\websocket\node_modules\fastify-websocket\node_modules\ws\lib\receiver.js:513:14)
at Receiver.getData (C:\git\needle-tiny-networking-package\packages\websocket\node_modules\fastify-websocket\node_modules\ws\lib\receiver.js:446:17)
at Receiver.startLoop (C:\git\needle-tiny-networking-package\packages\websocket\node_modules\fastify-websocket\node_modules\ws\lib\receiver.js:148:22)
at Receiver._write (C:\git\needle-tiny-networking-package\packages\websocket\node_modules\fastify-websocket\node_modules\ws\lib\receiver.js:83:10)
at writeOrBuffer (internal/streams/writable.js:358:12)
at Receiver.Writable.write (internal/streams/writable.js:303:10)
at Socket.socketOnData (C:\git\needle-tiny-networking-package\packages\websocket\node_modules\fastify-websocket\node_modules\ws\lib\websocket.js:1231:35)
at Socket.emit (events.js:376:20)
at addChunk (internal/streams/readable.js:309:12)
at readableAddChunk (internal/streams/readable.js:284:9)
Ok found a workround - instead of subscribing to connection.socket.on("message
i'm now setting a callback receiver to connection.socket.onmessage
and pass evt.data
through:
this.ws.socket.onmessage = (evt) => {
callback(evt.data);
};
That being said: info on if there is a better/official/recommended way on doing this correctly would be appreciated still :)
I think no matter what you're going to need to do some detection in your application to figure out which message type it is -- fastify-websocket can only just hand you the data that was sent from the client. With your workaround, don't you still need to do a check somehow to figure out which type it is, and then only try to JSON parse if it is a string?
Yes - the check somehow is where I didnt know how.
When using the evt.data like above it is either a string or a buffer so I can just pass it on to be handled in my core (where a buffer is always treated as a flatbuffer message right now) - but when I was using connection.on("message", data =>
I didnt know how to check wether the data
buffer was a actually json string so I can call toString
safely or a flatbuffer byte array.
fastify-websocket
just uses the underlying ws
library's Connection
and WebSocket
objects -- we don't do anything to the message data as it comes through. See https://github.com/fastify/fastify-websocket/blob/master/index.js#L61 for where we create the objects you're working with. I am pretty sure that connection.socket.onmessage
and connection.socket.on("message
will actually get passed the exact same data, and that regardless of which one you use you'll have to do an instanceof Buffer
check or something like that to figure out which type of data you're dealing with. Regardless, I think fastify-websocket
has no opinion on what data you should pump through the websocket and doesn't touch it, so I don't think this is a flag or something we'd add to the library if that makes sense. Not even really sure what flag you might expect. Gonna close this but if you think the library is messing with your data feel free to reopen.
What I mean is this:
this.ws.socket.on("message", (data) => {
console.log("ws.socket.on", data);
});
this.ws.socket.onmessage = evt => {
console.log("ws.socket.onmessage", evt.data);
};
As you can see in one event I'm getting a json string and in the other event im getting a buffer object (for the same message event)
socket.onmessage
is made for Web API compatibility, so it returns the Event
like object.
https://github.com/websockets/ws/blob/master/lib/event-target.js#L193-L200
socket.on('message')
is the actual Node EventEmitter
implementation. It receive the raw data (e.g. Buffer
, ArrayBuffer
, etc).
The ws
document already give you the hint on how to handle your case.
socket.on('message', function(data, isBinary) {
// it is sent with binary
if(isBinary) {
const buf = Buffer.from(data)
} else {
const json = JSON.parse(Buffer.from(data).toString())
}
})
@climba03003 thanks for explaining! that's probably what I was missing :)