I am trying to use cowboy to send a notification to multiple clients using the socket connected to them. The problem is that I cannot find anything in the documentation about the argument to be passed to the function, the one I used in the code seems to be incorrect.
The socket is saved in a variable called Req that is given when a new client connects in the init function:
% Called to know how to dispatch a new connection.
init(Req, _Opts) ->
?LOG_INFO("New client"),
?LOG_DEBUG("Request: ~p", [Req]),
% "upgrade" every request to websocket,
% we're not interested in serving any other content.
Req2=Req,
{cowboy_websocket, Req, #state{socket = Req2}}.
The sockets are used in this way
send_message_to_sockets([Socket | Sockets], Msg) ->
cowboy_websocket:websocket_send(Socket, {text, Msg}),
send_message_to_sockets(Sockets, Msg).
This is the error: Error in process <0.202.0> with exit value: {undef,[{cowboy_websocket,websocket_send, [#{bindings => #{},...}
I have tried different argument to be passed to the function websocket_send but nothing worked.
Here is the code of the websocket_send:
transport_send(#state{socket=Stream={Pid, _}, transport=undefined}, IsFin, Data) ->
Pid ! {Stream, {data, IsFin, Data}},
ok;
transport_send(#state{socket=Socket, transport=Transport}, _, Data) ->
Transport:send(Socket, Data).
-spec websocket_send(cow_ws:frame(), #state{}) -> ok | stop | {error, atom()}.
websocket_send(Frames, State) when is_list(Frames) ->
websocket_send_many(Frames, State, []);
websocket_send(Frame, State) ->
Data = frame(Frame, State),
case is_close_frame(Frame) of
true ->
_ = transport_send(State, fin, Data),
stop;
false ->
transport_send(State, nofin, Data)
end.
websocket_send_many([], State, Acc) ->
transport_send(State, nofin, lists:reverse(Acc));
websocket_send_many([Frame|Tail], State, Acc0) ->
Acc = [frame(Frame, State)|Acc0],
case is_close_frame(Frame) of
true ->
_ = transport_send(State, fin, lists:reverse(Acc)),
stop;
false ->
websocket_send_many(Tail, State, Acc)
end.
I don't think that is true. In Nine Nine's Cowboy User Guide, there is a section titled Getting Started, which shows this code:
In that code,
init()is passed a map that is assigned/bound to the Req0 variable. You can read about the Request map here:https://ninenines.eu/docs/en/cowboy/2.9/guide/req/
The map contains the usual HTTP Request information, e.g. the HTTP Request method, the HTTP version number, scheme, host, port, path, etc. Then the docs say:
Generally, a socket is defined like this:
And:
https://docs.oracle.com/javase/tutorial/networking/sockets/definition.html
In this line:
websocket_send() is defined to take a
cow_ws:frame()type as the first argument:In the cow_ws module, the
frame()type is defined like this:...which is a tuple with the first element being an atom and possibly a second element being an
iodata()type, which is a built in erlang type that is a binary or a list (containing integers, binaries and other lists), and it is defined here:I'm not sure how you go from a Request map to a two-tuple.