Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
334 views
in Technique[技术] by (71.8m points)

Chat room in erlang with cowboy and websocket

I'm trying to create a chatroom with cowboy websocket handler. I want that messages those come from every will be forwarded to other sockets as well, just like a chat group. I don't have any idea how to implement this? And I don't know how to save sockets that are connected to websocket so we can send messages to them. I have this cowboy handler:

-module(chat_conn).

-export([ init/2
    , websocket_init/1
    , websocket_handle/2
    , websocket_info/2
    , terminate/3
    ]).

-include("chat.hrl").

init(Req, [WsConnIdleTimeout]) ->
    ?LOG_DEBUG("[CHAT-CONN] New HTTP Request on: /api , Pid: ~p", [self()]),
    WsOpts = #{idle_timeout => WsConnIdleTimeout},
    State = #{counter => 0},
    {cowboy_websocket, Req, State, WsOpts}.

websocket_init(State0) ->
    ?LOG_DEBUG("[FOOZI-CONN] HTTP Upgraded to WebSocketm pid: ~p", [self()]),
    NewState = State0,
    {ok, NewState}.

websocket_handle({text, PlainRequest}, #{counter := Counter0} = State) ->
    ?LOG_DEBUG("[HIGGS-CONN] Receive New Message: ~p, Pid: ~p" , [PlainRequest, self()]),
    NewCounter = Counter0 + 1,
    Reply = list_to_binary("Counter is: " ++ integer_to_list(NewCounter)),
    NewState = #{counter => NewCounter},
    {reply, {text, Reply}, NewState};
    %{ok, State};
websocket_handle(Frame, State) ->
    ?LOG_INFO("[HIGGS-CONN] Invalid Frame => ~p", [Frame]),
    {stop, State}.

websocket_info(Message, State) ->
    ?LOG_INFO("[CONN-INFO] Unhandled message! => Message: ~p", [Message]),
    {reply, {text, list_to_binary(Message)}, State}.
    %{ok, State}.

terminate(Reason, _, State) ->
    ?LOG_INFO("[CONN-TERMINATE] Terminated! => Pid: ~p, Reason: ~p, State: ~p", [self(), Reason, State]),
    ok.
question from:https://stackoverflow.com/questions/66059636/chat-room-in-erlang-with-cowboy-and-websocket

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I don't know how to save sockets that are connected to websocket so we can send messages to them

In erlang, gen_servers can be used to store state, so you can create a gen_server that the websocket handlers employ to save the client pids. When a client sends a "start chat" message to your cowboy server using a specific route, the associated websocket handler will be called. Inside that handler, self() will be the pid of the websocket process for that client. You can save that pid in your gen_server by calling gen_server:cast(chat_room, {arrive, self()}), then inside chat_room:handle_cast() adding the pid to the list of pids stored in the State variable.

When the cowboy server receives a chat message from a client browser, the client's websocket process will handle the message, and inside the appropriate websocket handler you can query the gen_server to get a list of the pids for the connected clients. Then you can use ! to send each of them the message. In turn, each client's websocket_info() handler will handle the message, which it can relay through the websocket back to the client by returning: {reply, {text, Text}, State}.

For your gen_server, you will also need to implement a leave() function that the appropriate websocket handler will call to update the list of clients stored in the gen_server, e.g. gen_server:cast(chat_room, {leave, self()}).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...