-module(wsio_handler). -export([init/2]). -export([websocket_handle/2]). -export([websocket_init/1]). -export([websocket_info/2]). -define(TTL_PING, 10000). init(R, _) -> {cowboy_websocket, R, #{}}. websocket_init(S) -> Ref = st:lookup(wsbus), {ok, S#{wsbus => nil, ref_wsbus => Ref}}. websocket_handle({text, <>}, S) -> case jsx:is_json(Data) of true -> websocket_handle({json, jsx:decode(Data)}, S); false -> {ok, S} end; websocket_handle({json, #{<<"ref">> := Ref}}, #{wsbus := nil} = S) -> {[{text, jsx:encode(#{<<"ref">> => Ref, <<"wsio-code">> => 0})}], S}; websocket_handle({json, Data}, #{wsbus := BUS} = S) -> gen_server:cast(BUS, {call, Data, self()}), {ok, S}; websocket_handle(_, State) -> {ok, State}. websocket_info(close, S) -> {[close], S}; websocket_info(ping, S) -> erlang:send_after(?TTL_PING, self(), ping), {[ping], S}; websocket_info({send, #{} = Map}, S) -> {[{text, jsx:encode(Map)}], S}; websocket_info({send, <>}, S) -> {[{text, Bin}], S}; websocket_info({send, List}, S) when is_list(List) -> {List, S}; websocket_info({_, {Ref, {error, notfound}}}, #{ref_wsbus := Ref} = S) -> {ok, S#{ref_wsbus => st:lookup(wsbus)}}; websocket_info({_, {Ref, {ok, PID}}}, #{ref_wsbus := Ref} = S) -> {ok, maps:remove(ref_wsbus, S#{wsbus => PID})}; websocket_info(_, S) -> {ok, S}.