7

I'm trying to send a MessagePack-encoded message from Cowboy to a browser over WebSocket, and received data is always empty or invalid. I'm able to send binary data from JS to my cowboy handler, but not vice versa. I'm using Cowboy 1.0.4 with official msgpack-erlang application. I also use msgpack-lite for my in-browser javascript.

Examples:

websocket_handler:

websocket_handle({text, <<"return encoded">>}, Req, State) ->
    %% sends encoded message to client. Client is unable to decode and fails
    {reply, {binary, msgpack:pack(<<"message">>)}, Req, State};
websocket_handle({binary, Encoded}, Req, State) ->
    %% Works as expected
    lager:info("Received encoded message: ~p", [msgpack:unpack(Encoded)]),
    {ok, Req, State};

JS:

var host = "ws://" + window.location.host + "/websocket";
window.socket = new WebSocket(host);
socket.binaryType = 'arraybuffer';
socket.onmessage = function(event) {
    var message = msgpack.decode(event.data);
    console.log(message);
};

Browser returns an error inside msgpack.min.js:

Error: Invalid type: undefined
...ion n(t){var r=i(t),e=f[r];if(!e)throw new Error("Invalid type: "+(r?"0x"+r.toSt...

If I try to output raw event.data to console, here's what I'm getting:

 ArrayBuffer {}

It seems to be empty for some reason. I'm new both to erlang and msgpack, and don't know what is going wrong. Thanks for your help!

Hynek -Pichi- Vychodil
  • 26,174
  • 5
  • 52
  • 73

3 Answers3

6

Found the reason of my problem. The way how I tried to decode message on the client was wrong:

socket.onmessage = function(event) {
  var message = msgpack.decode(event.data);
  console.log(message);
};

The right way:

socket.onmessage = function(event) {
    var raw_binary_data = new Uint8Array(event.data);
    var message = msgpack.decode(raw_binary_data);
    console.log(message);
};
0

It seems like msgpack-lite doesn't support binary type. Try pack your data as a string.

{binary, msgpack:pack("message", [{enable_str, true}])}
Hynek -Pichi- Vychodil
  • 26,174
  • 5
  • 52
  • 73
  • Thanks but it doesn't help. I think the main reason is empty ArrayBuffer value. Something wrong with configuration, but I don't know what :( – Constantine EmeraldMaster Mar 22 '16 at 14:48
  • @ConstantineEmeraldMaster: Did you tried and verified WebSocket communication working as you expect? I suspect you don't get anything on JS side at all. Just send string unpacked first. – Hynek -Pichi- Vychodil Mar 22 '16 at 15:15
  • Communication works in both directions using text mode, also works in 1 direction (from client to server) in binary mode. JS client is not able to receive binary messages from server – Constantine EmeraldMaster Mar 22 '16 at 15:33
  • @ConstantineEmeraldMaster: Is there content in `event.data`? – Hynek -Pichi- Vychodil Mar 22 '16 at 16:20
  • `event.data` returns an empty `ArrayBuffer {}` – Constantine EmeraldMaster Mar 22 '16 at 16:37
  • @ConstantineEmeraldMaster: So the problem is in WebSocket and not in msgpack. Check if there is some binary as output from `msgpack:pack(<<"message">>)`. It should be `<<196,7,109,101,115,115,97,103,101>>`. Then there could be wrong something in `{binary, _}` or `socket.binaryType = 'arraybuffer'`. I don't know. You should be able to send ordinary binary in that way. – Hynek -Pichi- Vychodil Mar 22 '16 at 23:41
0

Using Uint8Array is a valid solution for client side issue. On server to pack strings use:

msgpack:pack(<<"message">>,[{pack_str,from_binary}])

Source : Article

JSingh
  • 26
  • 1
  • 1