2017-11-22 13 views
2

websocket接続を受け取るws_handlerがあります。Cowboy Websocketハンドラの状態を更新すると、クラッシュしたりサイレントに無視されます。

このプロセスは、ログインするために<<"hで始まる入力を待ちます。

それは、デフォルトのWebSocketの状態、(現在のPIDを参照して起動され)プレーヤプロセスID、および送信トレイメッセージ、 `< < "turn1" >>

websocket_handle({text, <<"h", Name/binary>>}, State) -> 
    {ok, PID} = player:go(self(), <<"profiledata", Name/binary>>), 
    erlang:start_timer(1000, self(), <<"Hello!">>), 
    {reply, {text, <<"You joined, ", Name/binary>>}, {State, PID, <<"turn1">>}}; 

Iを節約しますこの別個のプレーヤープロセスからのデータフローを制御したい場合、私のwebsocketハンドラにメッセージを取り出して、Outbox要素を介してそのクライアントに渡すようにします。

だから私は手動でメッセージトリガするには、これを追加します。私はこれが呼び出されることを期待戻るws_handlerで

handle_call(myscreen, _, {WS, Profile, Cab}) -> 
    gen_server:cast(WS, myscreenupdate), 
    {reply, ok, {WS, Profile, Cab}}; 

websocket_handle({text, <<"myscreen">>}, S = {_, P, _}) -> 
    gen_server:call(P, myscreen), 
    {ok, S}; 

とplayer.erl中を:

websocket_info(myscreenupdate, State = {St,P, _}) -> 
    {reply, {text, <<"My screen update">>}, {St, P, <<"turn2">>}}; 

私のブラウザのwebsocket出力は、の代わりにturn1を連続して印刷します。

gen_server:callplayer.erlに入れてみましたが、タイムアウトが発生しました。私はws_handlerwebsocket_handle{replyタプルのWebSocketに返信することになっているので、これがあると思います..しかし、それが本当だったら、私は、データが更新されることを期待したい:

websocket_info(myscreenupdate, State = {St,P, _}) -> 
    {reply, {text, <<"My screen update">>}, {St, P, <<"turn2">>}}; 

だから、私はここで何が起きているのかは不明です。

Playerプロセスから状態を更新し、WebSocketハンドラでその状態を取得して接続に送信するにはどうすればよいですか?

ws_handler.erl: 

-module(ws_handler). 

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

init(Req, Opts) -> 
    {cowboy_websocket, Req, Opts}. 

websocket_init(State) -> 
    {ok, State}. 

websocket_handle({text, <<"h", Name/binary>>}, State) -> 
    {ok, PID} = player:go(self(), <<"profiledata", Name/binary>>), 
    erlang:start_timer(1000, self(), <<"Hello!">>), 
    {reply, {text, <<"You joined, ", Name/binary>>}, {State, PID, <<"turn1">>}}; 

websocket_handle({text, <<"myscreen">>}, S = {_, P, _}) -> 
    gen_server:call(P, myscreen), 
    {ok, S}; 

websocket_handle({text, <<"auth", Auth/binary>>}, S = {_St, P, _}) -> 
    case s:s(P, Auth) of 
    {ok, Valid} -> {reply, {text, << "Authorized">>}, S}; 
    _ -> {reply, {text, <<"Error">>}, S} 
    end; 
websocket_handle({text, Msg}, S = {_St, P, Outbox}) -> 
    {reply, {text, Outbox}, S}; 
websocket_handle(_Data, State) -> 
    {ok, State}. 

websocket_info(myscreenupdate, State = {St,P, _}) -> 
    {reply, {text, <<"My screen update">>}, {St, P, <<"turn2">>}}; 

websocket_info({timeout, _Ref, _Ignored}, State = {_, P, Outbox}) -> 
    erlang:start_timer(1000, self(), <<"This is ignored">>), 
    Msg = Outbox, 
    {reply, {text, Msg}, State}; 
websocket_info(_Info, State) -> 
    {ok, State}. 

player.erl:

-module(player). 
-compile(export_all). 

handle_call(myscreen, _, {WS, Profile, Cab}) -> 
    gen_server:cast(WS, myscreenupdate), 
    {reply, ok, {WS, Profile, Cab}}; 
handle_call(get_profile, _, State = {_WSPID, Profile, _}) -> 
    {reply, Profile, State}. 

init([WSPID, Profile]) -> 
    {ok, {WSPID, Profile, null}}; 
init([WSPID, Profile, CabinetPID]) -> 
    {ok, {WSPID, Profile, CabinetPID}}. 

go(WSPID, Profile, CabinetPID) -> 
    gen_server:start_link(?MODULE, [WSPID, Profile, CabinetPID], []). 
go(WSPID, Profile) -> 
    gen_server:start_link(?MODULE, [WSPID, Profile], []). 
+0

ここで役立つ情報があれば、https://github.com/7stud/Programming-Erlang-Exercises-Solutions-Answers/blob/master/Chapter%2018/simple_exampleをご覧ください。md – 7stud

答えて

1

問題はカウボーイのwebsocket_info/2ハンドラのみ同等のerlang内蔵のメッセージオペレータ!(またはを使用してのWebSocketプロセスに送信されたメッセージ、受信するということですerlang:send/{2,3}関数)。

だから、あなたが行う必要があります。

WS ! myscreenupdate

代わりの

gen_server:cast(WS, myscreenupdate)

あなたがgen_server:castを使用する場合、それは認識されたメッセージではありませんので、メッセージはおそらくカウボーイメッセージループによって破棄されます。 gen_server:callを使用すると、デッドロックが発生します。

+0

有効な答え。ありがとう、洞察に感謝します。 – quantumpotato

関連する問題