⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ejabberd_http_poll.erl

📁 ejabberd-0.7.5 分布式Jabber服务器
💻 ERL
字号:
%%%----------------------------------------------------------------------%%% File    : ejabberd_http_poll.erl%%% Author  : Alexey Shchepin <alexey@sevcom.net>%%% Purpose : HTTP Polling support (JEP-0025)%%% Created :  4 Mar 2004 by Alexey Shchepin <alexey@sevcom.net>%%% Id      : $Id: ejabberd_http_poll.erl,v 1.6 2004/10/05 19:31:17 aleksey Exp $%%%-----------------------------------------------------------------------module(ejabberd_http_poll).-author('alexey@sevcom.net').-vsn('$Revision: 1.6 $ ').-behaviour(gen_fsm).%% External exports-export([start_link/2,	 init/1,	 handle_event/3,	 handle_sync_event/4,	 code_change/4,	 handle_info/3,	 terminate/3,	 send/2,	 recv/3,	 close/1,	 process_request/1]).-include("ejabberd.hrl").-include("jlib.hrl").-include("ejabberd_http.hrl").-record(http_poll, {id, pid}).-record(state, {id,		key,		output = "",		input = "",		waiting_input = false,		timer}).%-define(DBGFSM, true).-ifdef(DBGFSM).-define(FSMOPTS, [{debug, [trace]}]).-else.-define(FSMOPTS, []).-endif.-define(HTTP_POLL_TIMEOUT, 300000).-define(CT, {"Content-Type", "text/xml; charset=utf-8"}).-define(BAD_REQUEST, [?CT, {"Set-Cookie", "ID=-3:0; expires=-1"}]).%%%----------------------------------------------------------------------%%% API%%%----------------------------------------------------------------------start(ID, Key) ->    mnesia:create_table(http_poll,        		[{ram_copies, [node()]},        		 {attributes, record_info(fields, http_poll)}]),    supervisor:start_child(ejabberd_http_poll_sup, [ID, Key]).start_link(ID, Key) ->    gen_fsm:start_link(?MODULE, [ID, Key], ?FSMOPTS).send({http_poll, FsmRef}, Packet) ->    gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}).recv({http_poll, FsmRef}, _Length, Timeout) ->    gen_fsm:sync_send_all_state_event(FsmRef, recv, Timeout).close({http_poll, FsmRef}) ->    catch gen_fsm:sync_send_all_state_event(FsmRef, close).process_request(#request{path = [],			 data = Data} = Request) ->    case catch parse_request(Data) of	{ok, ID1, Key, NewKey, Packet} ->	    ID = if		     (ID1 == "0") or (ID1 == "mobile") ->			 NewID = sha:sha(term_to_binary({now(), make_ref()})),			 {ok, Pid} = start(NewID, ""),			 mnesia:transaction(			   fun() ->				   mnesia:write(#http_poll{id = NewID,							   pid = Pid})			   end),			 NewID;		     true ->			 ID1		 end,	    case http_put(ID, Key, NewKey, Packet) of		{error, not_exists} ->		    {200, ?BAD_REQUEST, ""};		{error, bad_key} ->		    {200, ?BAD_REQUEST, ""};		ok ->		    receive		    after 100 -> ok		    end,		    case http_get(ID) of			{error, not_exists} ->			    {200, [?BAD_REQUEST], ""};			{ok, OutPacket} ->			    if				ID == ID1 ->				    Cookie = "ID=" ++ ID ++ "; expires=-1",				    {200, [?CT, {"Set-Cookie", Cookie}],				     OutPacket};				ID1 == "mobile" ->				    {200, [?CT], [ID, $\n, OutPacket]};				true ->				    Cookie = "ID=" ++ ID ++ "; expires=-1",				    {200, [?CT, {"Set-Cookie", Cookie}],				     OutPacket}			    end		    end	    end;	_ ->	    {200, [?CT, {"Set-Cookie", "ID=-2:0; expires=-1"}], ""}    end;process_request(_Request) ->    {400, [], {xmlelement, "h1", [],	       [{xmlcdata, "400 Bad Request"}]}}.%%%----------------------------------------------------------------------%%% Callback functions from gen_fsm%%%----------------------------------------------------------------------%%----------------------------------------------------------------------%% Func: init/1%% Returns: {ok, StateName, StateData}          |%%          {ok, StateName, StateData, Timeout} |%%          ignore                              |%%          {stop, StopReason}                   %%----------------------------------------------------------------------init([ID, Key]) ->    ?INFO_MSG("started: ~p", [{ID, Key}]),    Opts = [], % TODO    ejabberd_c2s:start({?MODULE, {http_poll, self()}}, Opts),    Timer = erlang:start_timer(?HTTP_POLL_TIMEOUT, self(), []),    {ok, loop, #state{id = ID,		      key = Key,		      timer = Timer}}.%%----------------------------------------------------------------------%% Func: StateName/2%% Returns: {next_state, NextStateName, NextStateData}          |%%          {next_state, NextStateName, NextStateData, Timeout} |%%          {stop, Reason, NewStateData}                         %%----------------------------------------------------------------------%%----------------------------------------------------------------------%% Func: StateName/3%% Returns: {next_state, NextStateName, NextStateData}            |%%          {next_state, NextStateName, NextStateData, Timeout}   |%%          {reply, Reply, NextStateName, NextStateData}          |%%          {reply, Reply, NextStateName, NextStateData, Timeout} |%%          {stop, Reason, NewStateData}                          |%%          {stop, Reason, Reply, NewStateData}                    %%----------------------------------------------------------------------%state_name(Event, From, StateData) ->%    Reply = ok,%    {reply, Reply, state_name, StateData}.%%----------------------------------------------------------------------%% Func: handle_event/3%% Returns: {next_state, NextStateName, NextStateData}          |%%          {next_state, NextStateName, NextStateData, Timeout} |%%          {stop, Reason, NewStateData}                         %%----------------------------------------------------------------------handle_event(Event, StateName, StateData) ->    {next_state, StateName, StateData}.%%----------------------------------------------------------------------%% Func: handle_sync_event/4%% Returns: {next_state, NextStateName, NextStateData}            |%%          {next_state, NextStateName, NextStateData, Timeout}   |%%          {reply, Reply, NextStateName, NextStateData}          |%%          {reply, Reply, NextStateName, NextStateData, Timeout} |%%          {stop, Reason, NewStateData}                          |%%          {stop, Reason, Reply, NewStateData}                    %%----------------------------------------------------------------------handle_sync_event({send, Packet}, From, StateName, StateData) ->    Output = [StateData#state.output | Packet],    Reply = ok,    {reply, Reply, StateName, StateData#state{output = Output}};handle_sync_event(recv, From, StateName, StateData) ->    case StateData#state.input of	"" ->	    {next_state, StateName, StateData#state{waiting_input = From}};	Input ->	    Reply = {ok, list_to_binary(Input)},	    {reply, Reply, StateName, StateData#state{input = "",						      waiting_input = false}}    end;handle_sync_event(stop, From, StateName, StateData) ->    Reply = ok,    {stop, normal, Reply, StateData};handle_sync_event({http_put, Key, NewKey, Packet},		  From, StateName, StateData) ->    Allow = case StateData#state.key of		"" ->		    true;		OldKey ->		    NextKey = jlib:encode_base64(				binary_to_list(crypto:sha(Key))),		    if			OldKey == NextKey ->			    true;			true ->			    false		    end	    end,    if	Allow ->	    case StateData#state.waiting_input of		false ->		    Input = [StateData#state.input | Packet],		    Reply = ok,		    {reply, Reply, StateName, StateData#state{input = Input,							      key = NewKey}};		Receiver ->		    gen_fsm:reply(Receiver, {ok, list_to_binary(Packet)}),		    cancel_timer(StateData#state.timer),		    Timer = erlang:start_timer(?HTTP_POLL_TIMEOUT, self(), []),		    Reply = ok,		    {reply, Reply, StateName,		     StateData#state{waiting_input = false,				     key = NewKey,				     timer = Timer}}	    end;	true ->	    Reply = {error, bad_key},	    {reply, Reply, StateName, StateData}    end;handle_sync_event(http_get, From, StateName, StateData) ->    Reply = {ok, StateData#state.output},    {reply, Reply, StateName, StateData#state{output = ""}};handle_sync_event(Event, From, StateName, StateData) ->    Reply = ok,    {reply, Reply, StateName, StateData}.code_change(OldVsn, StateName, StateData, Extra) ->    {ok, StateName, StateData}.%%----------------------------------------------------------------------%% Func: handle_info/3%% Returns: {next_state, NextStateName, NextStateData}          |%%          {next_state, NextStateName, NextStateData, Timeout} |%%          {stop, Reason, NewStateData}                         %%----------------------------------------------------------------------handle_info({timeout, Timer, _}, StateName,	    #state{timer = Timer} = StateData) ->    {stop, normal, StateData};handle_info(_, StateName, StateData) ->    {next_state, StateName, StateData}.%%----------------------------------------------------------------------%% Func: terminate/3%% Purpose: Shutdown the fsm%% Returns: any%%----------------------------------------------------------------------terminate(Reason, StateName, StateData) ->    mnesia:transaction(      fun() ->	      mnesia:delete({http_poll, StateData#state.id})      end),    case StateData#state.waiting_input of	false ->	    ok;	Receiver ->	    gen_fsm:reply(Receiver, {error, closed})    end,    ok.%%%----------------------------------------------------------------------%%% Internal functions%%%----------------------------------------------------------------------http_put(ID, Key, NewKey, Packet) ->    case mnesia:dirty_read({http_poll, ID}) of	[] ->	    {error, not_exists};	[#http_poll{pid = FsmRef}] ->	    gen_fsm:sync_send_all_state_event(	      FsmRef, {http_put, Key, NewKey, Packet})    end.http_get(ID) ->    case mnesia:dirty_read({http_poll, ID}) of	[] ->	    {error, not_exists};	[#http_poll{pid = FsmRef}] ->	    gen_fsm:sync_send_all_state_event(FsmRef, http_get)    end.parse_request(Data) ->    Comma = string:chr(Data, $,),    Header = lists:sublist(Data, Comma - 1),    Packet = lists:nthtail(Comma, Data),    {ID, Key, NewKey} =	case string:tokens(Header, ";") of	    [ID1] ->		{ID1, "", ""};	    [ID1, Key1] ->		{ID1, Key1, Key1};	    [ID1, Key1, NewKey1] ->		{ID1, Key1, NewKey1}	end,    {ok, ID, Key, NewKey, Packet}.cancel_timer(Timer) ->    erlang:cancel_timer(Timer),    receive	{timeout, Timer, _} ->	    ok    after 0 ->	    ok    end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -