How to send data asynchronously via websocket with Cowboy?

I have a Cowboy server and I would like to register a gen_event that sends something through websocket. I should also be able to respond to regular synchronous requests using websocket_handle/3 . I did not see anything obvious in cowboy_http_websocket_handler.erl and cowboy_http_websocket: websocket_send / 3 is not exported. Am I missing an easy way to send something through an open socket?

+4
source share
2 answers

In the websocket handler example , websocket_info / 3 is used to send such things. Combine gen_event: add_sup_handler / 3 in the websocket initialization code with websocket_info / 3. Keep the connection pid in handler state and just send a message with an asynchronous event.

+3
source

@nmichaels answer pointed me in the right direction, and I successfully used gen_event in a cowboy app to send internal messages to websocket_info. But the answer is a little outdated and the cowboy has changed a lot, so I would like to add to it and provide a solution that will work with the latest version of the cowboy. Hope this helps someone new Erlan and the cowboy.

To implement gen_event in cowboys

You must complete three steps:
  • Run gen_event and register handlers

     start(_Type, _Args) -> Dispatch = cowboy_router:compile(wrinqle_routes:routes_configuration()), {ok, _} = cowboy:start_http(http, 100, [{port, 3000}], [{env, [{dispatch, Dispatch}]}]), pg2:start(), gen_event:start({global,my_events}), gen_event:add_handler({global,my_events},my_event_handler,[]). 

Here I logged an event called my_events globally (note: you can also log events locally) and a handler is added in the my_event_handler module

  • Create an event handler.

  • Now you can notify the event handler of events from anywhere in the cowboy. As an example, the code below raises events from websocket_handler

     { _,_ }-> gen_event: notify(global:whereis_name(my_events),{event_name,self()}), {ok,Req,State}; 

All this code makes a notification of an event registered in my_events around the world of the event. What is it.

Another problem OP was facing was how to send messages to open connections and connections for which pid is not known during initialization. To solve this problem, you can use pg2 , which registers the process identifier by channel. This is a very useful PID management module. So the above code can be converted to something like this

  [H|T] = pg2:get_members(Name) gen_event: notify(global:whereis_name(my_events),{event_name, H}). 

And in this way you can send a message to a specific pid and by extension to a specific socket.

+3
source

Source: https://habr.com/ru/post/1381300/


All Articles