communicating between http handler and websocket h

2019-07-07 10:11发布

问题:

I'd like to create a websocket app in Cowboy that gets its data from another Cowboy handler. Let's say that I want to combine the Echo_get example from cowboy: https://github.com/ninenines/cowboy/tree/master/examples/echo_get/src

with websocket example

https://github.com/ninenines/cowboy/tree/master/examples/websocket/src

in such a way that a GET request to Echo should send a "push" via websocket handler to the html page in that example.

What is the least complicated way to do it? Can I use "pipe" operator in some easy way ? Do I need to create and intermediate gen_something to pass messages between them? I would appreciate an answer with sample code that shows the glue code for the handlers - I do not really know where to start plumbing the two handlers together.

回答1:

A websocket handler in cowboy is a long lived request process to which you can send websocket or erlang messages.

In your case, there are 2 types of processes:

  • websocket processes: websocket handlers with a websocket connection opened to clients.
  • echo processes: processes when a client access the echo handler with a parameter.

The idea is that the echo process sends an erlang message to the websocket processes, that in turn will send a message to the client.

For your echo process can send a message to your websocket processes, you need to keep a list of websocket processes to which you want to send messages. Gproc is a quite useful library for that purpose.

You can register processes to gproc pubsub with gproc_ps:subscribe/2, and send messages to the registered processes with gproc_ps:publish/3.

Cowboy websocket processes receive erlang messages with the websocket_info/3 function.

So for example, the websocket handler could be like this:

websocket_init(_, Req, _Opts) ->
  ...
  % l is for local process registration
  % echo is the name of the event you register the process to
  gproc_ps:subscribe(l, echo),
  ...

websocket_info({gproc_ps_event, echo, Echo}, Req, State) ->
  % sending the Echo to the client
  {reply, {text, Echo}, Req, State};

And the echo handler like this:

echo(<<"GET">>, Echo, Req) ->
    % sending the echo message to the websockets handlers
    gproc_ps:publish(l, echo, Echo),
    cowboy_req:reply(200, [
        {<<"content-type">>, <<"text/plain; charset=utf-8">>}
    ], Echo, Req);