aboutsummaryrefslogtreecommitdiff
path: root/src/web/ejabberd_http_wsjson.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/web/ejabberd_http_wsjson.erl')
-rw-r--r--src/web/ejabberd_http_wsjson.erl235
1 files changed, 104 insertions, 131 deletions
diff --git a/src/web/ejabberd_http_wsjson.erl b/src/web/ejabberd_http_wsjson.erl
index 2abd12b3b..1a07252e8 100644
--- a/src/web/ejabberd_http_wsjson.erl
+++ b/src/web/ejabberd_http_wsjson.erl
@@ -24,196 +24,169 @@
%%%
%%%----------------------------------------------------------------------
--module (ejabberd_http_wsjson).
+-module(ejabberd_http_wsjson).
+
-author('ecestari@process-one.net').
-behaviour(gen_fsm).
% External exports
--export([
- start/1,
- start_link/1,
- init/1,
- handle_event/3,
- handle_sync_event/4,
- code_change/4,
- handle_info/3,
- terminate/3,
- send_xml/2,
- setopts/2,
- sockname/1, peername/1,
- controlling_process/2,
- become_controller/2,
+-export([start/1, start_link/1, init/1, handle_event/3,
+ handle_sync_event/4, code_change/4, handle_info/3,
+ terminate/3, send_xml/2, setopts/2, sockname/1,
+ peername/1, controlling_process/2, become_controller/2,
close/1]).
-include("ejabberd.hrl").
+
-include("jlib.hrl").
+
-include("ejabberd_http.hrl").
--record(state, {
- socket,
- timeout,
- timer,
- input = [],
- waiting_input = false, %% {ReceiverPid, Tag}
- last_receiver,
- ws}).
+-define(WEBSOCKET_TIMEOUT, 300).
+
+-record(state,
+ {socket :: ejabberd_http_ws:ws_socket(),
+ timeout = ?WEBSOCKET_TIMEOUT :: pos_integer(),
+ timer = make_ref() :: reference(),
+ input = [] :: list(),
+ waiting_input = false :: false | pid(),
+ last_receiver :: pid(),
+ ws :: atom()}).
%-define(DBGFSM, true).
-ifdef(DBGFSM).
+
-define(FSMOPTS, [{debug, [trace]}]).
+
-else.
+
-define(FSMOPTS, []).
+
-endif.
--define(WEBSOCKET_TIMEOUT, 300000).
-%
-%
-%%%%----------------------------------------------------------------------
-%%%% API
-%%%%----------------------------------------------------------------------
start(WS) ->
supervisor:start_child(ejabberd_wsloop_sup, [WS]).
start_link(WS) ->
- gen_fsm:start_link(?MODULE, [WS],?FSMOPTS).
+ gen_fsm:start_link(?MODULE, [WS], ?FSMOPTS).
send_xml({http_ws, FsmRef, _IP}, Packet) ->
- gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}).
+ gen_fsm:sync_send_all_state_event(FsmRef,
+ {send, Packet}).
setopts({http_ws, FsmRef, _IP}, Opts) ->
case lists:member({active, once}, Opts) of
- true ->
- gen_fsm:send_all_state_event(FsmRef, {activate, self()});
- _ ->
- ok
+ true ->
+ gen_fsm:send_all_state_event(FsmRef,
+ {activate, self()});
+ _ -> ok
end.
-sockname(_Socket) ->
- {ok, {{0, 0, 0, 0}, 0}}.
+sockname(_Socket) -> {ok, {{0, 0, 0, 0}, 0}}.
-peername({http_ws, _FsmRef, IP}) ->
- {ok, IP}.
+peername({http_ws, _FsmRef, IP}) -> {ok, IP}.
-controlling_process(_Socket, _Pid) ->
- ok.
+controlling_process(_Socket, _Pid) -> ok.
become_controller(FsmRef, C2SPid) ->
- gen_fsm:send_all_state_event(FsmRef, {become_controller, C2SPid}).
+ gen_fsm:send_all_state_event(FsmRef,
+ {become_controller, C2SPid}).
close({http_ws, FsmRef, _IP}) ->
- catch gen_fsm:sync_send_all_state_event(FsmRef, close).
-
-%%% Internal
+ catch gen_fsm:sync_send_all_state_event(FsmRef, close).
+%%% Internal
init([WS]) ->
- %% Read c2s options from the first ejabberd_c2s configuration in
- %% the config file listen section
- %% TODO: We should have different access and shaper values for
- %% each connector. The default behaviour should be however to use
- %% the default c2s restrictions if not defined for the current
- %% connector.
- Opts = [{xml_socket, true}|ejabberd_c2s_config:get_c2s_limits()],
-
- WSTimeout = case ejabberd_config:get_local_option({websocket_timeout,
- ?MYNAME}) of
- %% convert seconds of option into milliseconds
- Int when is_integer(Int) -> Int*1000;
- undefined -> ?WEBSOCKET_TIMEOUT
- end,
-
+ Opts = [{xml_socket, true}
+ | ejabberd_c2s_config:get_c2s_limits()],
+ WSTimeout = ejabberd_config:get_local_option(
+ {websocket_timeout, ?MYNAME},
+ fun(I) when is_integer(I), I>0 -> I end,
+ ?WEBSOCKET_TIMEOUT) * 1000,
Socket = {http_ws, self(), WS:get(ip)},
- ?DEBUG("Client connected through websocket ~p", [Socket]),
- ejabberd_socket:start(ejabberd_c2s, ?MODULE, Socket, Opts),
+ ?DEBUG("Client connected through websocket ~p",
+ [Socket]),
+ ejabberd_socket:start(ejabberd_c2s, ?MODULE, Socket,
+ Opts),
Timer = erlang:start_timer(WSTimeout, self(), []),
- {ok, loop, #state{
- socket = Socket,
- timeout = WSTimeout,
- timer = Timer,
- ws = WS}}.
+ {ok, loop,
+ #state{socket = Socket, timeout = WSTimeout,
+ timer = Timer, ws = WS}}.
handle_event({activate, From}, StateName, StateData) ->
case StateData#state.input of
- [] ->
- {next_state, StateName,
- StateData#state{waiting_input = {From, ok}}};
- Input ->
- Receiver = From,
- lists:reverse(lists:map(fun(Packet)->
- Receiver ! {tcp, StateData#state.socket, [Packet]}
- end, Input)),
- {next_state, StateName, StateData#state{input = "",
- waiting_input = false,
- last_receiver = Receiver
- }}
+ [] ->
+ {next_state, StateName,
+ StateData#state{waiting_input = From}};
+ Input ->
+ Receiver = From,
+ lists:reverse(lists:map(fun (Packet) ->
+ Receiver !
+ {tcp, StateData#state.socket,
+ [Packet]}
+ end,
+ Input)),
+ {next_state, StateName,
+ StateData#state{input = [], waiting_input = false,
+ last_receiver = Receiver}}
end.
-handle_sync_event({send, Packet}, _From, StateName, #state{ws = WS} = StateData) ->
+handle_sync_event({send, Packet}, _From, StateName,
+ #state{ws = WS} = StateData) ->
EJson = xmpp_json:to_json(Packet),
- Json = mochijson2:encode(EJson),
- WS:send(iolist_to_binary(Json)),
+ Json = jiffy:encode(EJson),
+ WS:send(Json),
{reply, ok, StateName, StateData};
-
-handle_sync_event(close, _From, _StateName, StateData) ->
- Reply = ok,
- {stop, normal, Reply, StateData}.
-
-handle_info({browser, <<"\n">>}, StateName, StateData)->
+handle_sync_event(close, _From, _StateName,
+ StateData) ->
+ Reply = ok, {stop, normal, Reply, StateData}.
+
+handle_info({browser, <<"\n">>}, StateName,
+ StateData) ->
NewState = case StateData#state.waiting_input of
- false ->
- ok;
- {Receiver, _Tag} ->
- Receiver ! {tcp, StateData#state.socket,<<"\n">>},
- cancel_timer(StateData#state.timer),
- Timer = erlang:start_timer(StateData#state.timeout, self(), []),
- StateData#state{waiting_input = false,
- last_receiver = Receiver,
- timer = Timer}
- end,
- {next_state, StateName, NewState};
-handle_info({browser, JsonPacket}, StateName, StateData)->
+ false -> ok;
+ Receiver ->
+ Receiver ! {tcp, StateData#state.socket, <<"\n">>},
+ cancel_timer(StateData#state.timer),
+ Timer = erlang:start_timer(StateData#state.timeout,
+ self(), []),
+ StateData#state{waiting_input = false,
+ last_receiver = Receiver, timer = Timer}
+ end,
+ {next_state, StateName, NewState};
+handle_info({browser, JsonPacket}, StateName,
+ StateData) ->
NewState = case StateData#state.waiting_input of
- false ->
- EJson = mochijson2:decode(JsonPacket),
- Packet = xmpp_json:from_json(EJson),
- Input = [Packet | StateData#state.input],
- StateData#state{input = Input};
- {Receiver, _Tag} ->
- %?DEBUG("Received from browser : ~p", [JsonPacket]),
- EJson = mochijson2:decode(JsonPacket),
- %?DEBUG("decoded : ~p", [EJson]),
- Packet = xmpp_json:from_json(EJson),
- %?DEBUG("sending to c2s : ~p", [Packet]),
- Receiver ! {tcp, StateData#state.socket,[Packet]},
- cancel_timer(StateData#state.timer),
- Timer = erlang:start_timer(StateData#state.timeout, self(), []),
- StateData#state{waiting_input = false,
- last_receiver = Receiver,
- timer = Timer}
- end,
- {next_state, StateName, NewState};
-
-
+ false ->
+ EJson = jiffy:decode(JsonPacket),
+ Packet = xmpp_json:from_json(EJson),
+ Input = [Packet | StateData#state.input],
+ StateData#state{input = Input};
+ Receiver ->
+ EJson = jiffy:decode(JsonPacket),
+ Packet = xmpp_json:from_json(EJson),
+ Receiver ! {tcp, StateData#state.socket, [Packet]},
+ cancel_timer(StateData#state.timer),
+ Timer = erlang:start_timer(StateData#state.timeout,
+ self(), []),
+ StateData#state{waiting_input = false,
+ last_receiver = Receiver, timer = Timer}
+ end,
+ {next_state, StateName, NewState};
handle_info({timeout, Timer, _}, _StateName,
#state{timer = Timer} = StateData) ->
{stop, normal, StateData};
-
handle_info(_, StateName, StateData) ->
{next_state, StateName, StateData}.
-
code_change(_OldVsn, StateName, StateData, _Extra) ->
- {ok, StateName, StateData}.
-
+ {ok, StateName, StateData}.
+
terminate(_Reason, _StateName, _StateData) -> ok.
cancel_timer(Timer) ->
erlang:cancel_timer(Timer),
- receive
- {timeout, Timer, _} ->
- ok
- after 0 ->
- ok
- end.
+ receive {timeout, Timer, _} -> ok after 0 -> ok end.