@ -0,0 +1,77 @@ | |||
-module(agSslAgencyExm). | |||
-compile(inline). | |||
-compile({inline_size, 128}). | |||
-export([ | |||
start_link/3 | |||
, init_it/3 | |||
, system_code_change/4 | |||
, system_continue/3 | |||
, system_get_state/1 | |||
, system_terminate/4 | |||
]). | |||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% genExm start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |||
-spec start_link(module(), term(), [proc_lib:spawn_option()]) -> {ok, pid()}. | |||
start_link(ServerName, Args, SpawnOpts) -> | |||
proc_lib:start_link(?MODULE, init_it, [ServerName, self(), Args], infinity, SpawnOpts). | |||
init_it(ServerName, Parent, Args) -> | |||
case safeRegister(ServerName) of | |||
true -> | |||
process_flag(trap_exit, true), | |||
moduleInit(Parent, Args); | |||
{false, Pid} -> | |||
proc_lib:init_ack(Parent, {error, {already_started, Pid}}) | |||
end. | |||
-spec system_code_change(term(), module(), undefined | term(), term()) -> {ok, term()}. | |||
system_code_change(MiscState, _Module, _OldVsn, _Extra) -> | |||
{ok, MiscState}. | |||
-spec system_continue(pid(), [], {module(), term(), term()}) -> ok. | |||
system_continue(_Parent, _Debug, {Parent, SrvState, CliState}) -> | |||
loop(Parent, SrvState, CliState). | |||
-spec system_get_state(term()) -> {ok, term()}. | |||
system_get_state({_Parent, SrvState, _CliState}) -> | |||
{ok, SrvState}. | |||
-spec system_terminate(term(), pid(), [], term()) -> none(). | |||
system_terminate(Reason, _Parent, _Debug, {_Parent, SrvState, CliState}) -> | |||
terminate(Reason, SrvState, CliState). | |||
safeRegister(ServerName) -> | |||
try register(ServerName, self()) of | |||
true -> true | |||
catch | |||
_:_ -> {false, whereis(ServerName)} | |||
end. | |||
moduleInit(Parent, Args) -> | |||
case agSslAgencyIns:init(Args) of | |||
{ok, SrvState, CliState} -> | |||
proc_lib:init_ack(Parent, {ok, self()}), | |||
loop(Parent, SrvState, CliState); | |||
{stop, Reason} -> | |||
proc_lib:init_ack(Parent, {error, Reason}), | |||
exit(Reason) | |||
end. | |||
loop(Parent, SrvState, CliState) -> | |||
receive | |||
{system, From, Request} -> | |||
sys:handle_system_msg(Request, From, Parent, ?MODULE, [], {Parent, SrvState, CliState}); | |||
{'EXIT', Parent, Reason} -> | |||
terminate(Reason, SrvState, CliState); | |||
Msg -> | |||
{ok, NewSrvState, NewCliState} = agSslAgencyIns:handleMsg(Msg, SrvState, CliState), | |||
loop(Parent, NewSrvState, NewCliState) | |||
end. | |||
terminate(Reason, SrvState, CliState) -> | |||
agSslAgencyIns:terminate(Reason, SrvState, CliState), | |||
exit(Reason). | |||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% genExm end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
@ -0,0 +1,213 @@ | |||
-module(agSslAgencyIns). | |||
-include("agHttpCli.hrl"). | |||
-compile(inline). | |||
-compile({inline_size, 128}). | |||
-export([ | |||
%% 内部行为API | |||
init/1 | |||
, handleMsg/3 | |||
, terminate/3 | |||
]). | |||
-record(srvState, { | |||
poolName :: poolName(), | |||
serverName :: serverName(), | |||
userPassWord :: binary(), | |||
host :: binary(), | |||
rn :: binary:cp(), | |||
rnrn :: binary:cp(), | |||
reconnectState :: undefined | reconnectState(), | |||
socket :: undefined | ssl:sslsocket(), | |||
timerRef :: undefined | reference() | |||
}). | |||
-type srvState() :: #srvState{}. | |||
-spec init(term()) -> no_return(). | |||
init({PoolName, AgencyName, AgencyOpts}) -> | |||
BacklogSize = ?GET_FROM_LIST(backlogSize, AgencyOpts, ?DEFAULT_BACKLOG_SIZE), | |||
ReconnectState = agAgencyUtils:initReconnectState(AgencyOpts), | |||
self() ! ?miDoNetConnect, | |||
{ok, #srvState{poolName = PoolName, serverName = AgencyName, rn = binary:compile_pattern(<<"\r\n">>), rnrn = binary:compile_pattern(<<"\r\n\r\n">>), reconnectState = ReconnectState}, #cliState{backlogSize = BacklogSize}}. | |||
-spec handleMsg(term(), srvState(), cliState()) -> {ok, term(), term()}. | |||
handleMsg({miRequest, FromPid, _Method, _Path, _Headers, _Body, RequestId, _OverTime}, | |||
#srvState{socket = undefined} = SrvState, | |||
CliState) -> | |||
agAgencyUtils:agencyReply(FromPid, RequestId, undefined, {error, no_socket}), | |||
{ok, SrvState, CliState}; | |||
handleMsg({miRequest, FromPid, Method, Path, Headers, Body, RequestId, OverTime} = MiRequest, | |||
#srvState{serverName = ServerName, host = Host, userPassWord = UserPassWord, socket = Socket} = SrvState, | |||
#cliState{backlogNum = BacklogNum, backlogSize = BacklogSize, requestsIn = RequestsIn, status = Status} = CliState) -> | |||
case BacklogNum >= BacklogSize of | |||
true -> | |||
?WARN(ServerName, ":backlog full curNum:~p Total: ~p ~n", [BacklogNum, BacklogSize]), | |||
agAgencyUtils:agencyReply(FromPid, RequestId, undefined, {error, backlog_full}), | |||
{ok, SrvState, CliState}; | |||
_ -> | |||
case Status of | |||
leisure -> %% 空闲模式 | |||
Request = agHttpProtocol:request(Method, Host, Path, [{<<"Authorization">>, UserPassWord} | Headers], Body), | |||
case ssl:send(Socket, Request) of | |||
ok -> | |||
TimerRef = | |||
case OverTime of | |||
infinity -> | |||
undefined; | |||
_ -> | |||
erlang:start_timer(OverTime, self(), waiting, [{abs, true}]) | |||
end, | |||
{ok, SrvState, CliState#cliState{status = waiting, backlogNum = BacklogNum + 1, curInfo = {FromPid, RequestId, TimerRef}}}; | |||
{error, Reason} -> | |||
?WARN(ServerName, ":send error: ~p~n", [Reason]), | |||
ssl:close(Socket), | |||
agAgencyUtils:agencyReply(FromPid, RequestId, undefined, {error, socket_send_error}), | |||
dealClose(SrvState, CliState, {error, socket_send_error}) | |||
end; | |||
_ -> | |||
agAgencyUtils:addQueue(RequestsIn, MiRequest), | |||
{ok, SrvState, CliState#cliState{requestsIn = RequestsIn + 1, backlogNum = BacklogNum + 1}} | |||
end | |||
end; | |||
handleMsg({ssl, Socket, Data}, | |||
#srvState{serverName = ServerName, rn = Rn, rnrn = RnRn, socket = Socket} = SrvState, | |||
#cliState{backlogNum = BacklogNum, curInfo = CurInfo, requestsOut = RequestsOut, recvState = RecvState} = CliState) -> | |||
try agHttpProtocol:response(RecvState, Rn, RnRn, Data) of | |||
{done, #recvState{statusCode = StatusCode, contentLength = ContentLength, body = Body}} -> | |||
agAgencyUtils:agencyReply(CurInfo, #requestRet{statusCode = StatusCode, contentLength = ContentLength, body = Body}), | |||
case agAgencyUtils:getQueue(RequestsOut + 1) of | |||
undefined -> | |||
{ok, SrvState, CliState#cliState{backlogNum = BacklogNum - 1, status = leisure, curInfo = undefined, recvState = undefined}}; | |||
MiRequest -> | |||
dealQueueRequest(MiRequest, SrvState, CliState#cliState{backlogNum = BacklogNum - 1, status = leisure, curInfo = undefined, recvState = undefined}) | |||
end; | |||
{ok, NewRecvState} -> | |||
{ok, SrvState, CliState#cliState{recvState = NewRecvState}}; | |||
{error, Reason} -> | |||
?WARN(ServerName, "handle ssl data error: ~p~n", [Reason]), | |||
ssl:close(Socket), | |||
dealClose(SrvState, CliState, {error, ssl_data_error}) | |||
catch | |||
E:R:S -> | |||
?WARN(ServerName, "handle ssl data crash: ~p:~p~n~p~n", [E, R, S]), | |||
ssl:close(Socket), | |||
dealClose(SrvState, CliState, {{error, agency_handledata_error}}) | |||
end; | |||
handleMsg({timeout, TimerRef, waiting}, | |||
#srvState{socket = Socket} = SrvState, | |||
#cliState{backlogNum = BacklogNum, curInfo = {FromPid, RequestId, TimerRef}} = CliState) -> | |||
agAgencyUtils:agencyReply(FromPid, RequestId, undefined, {error, timeout}), | |||
%% 之前的数据超时之后 要关闭ssl 然后重新建立连接 以免后面该ssl收到该次超时数据 影响后面请求的接收数据 导致数据错乱 | |||
ssl:close(Socket), | |||
timer:sleep(1000), | |||
self() ! ?miDoNetConnect, | |||
{ok, SrvState, CliState#cliState{backlogNum = BacklogNum - 1}}; | |||
handleMsg({ssl_closed, Socket}, | |||
#srvState{socket = Socket, serverName = ServerName} = SrvState, | |||
CliState) -> | |||
?WARN(ServerName, "connection closed~n", []), | |||
dealClose(SrvState, CliState, {error, ssl_closed}); | |||
handleMsg({ssl_error, Socket, Reason}, | |||
#srvState{socket = Socket, serverName = ServerName} = SrvState, | |||
CliState) -> | |||
?WARN(ServerName, "connection error: ~p~n", [Reason]), | |||
ssl:close(Socket), | |||
dealClose(SrvState, CliState, {error, ssl_error}); | |||
handleMsg(?miDoNetConnect, | |||
#srvState{poolName = PoolName, serverName = ServerName, reconnectState = ReconnectState} = SrvState, | |||
#cliState{requestsOut = RequestsOut} = CliState) -> | |||
case ?agBeamPool:get(PoolName) of | |||
#poolOpts{hostname = HostName, port = Port, host = Host, userPassword = UserPassword} -> | |||
case dealConnect(ServerName, HostName, Port, ?DEFAULT_SOCKET_OPTS) of | |||
{ok, Socket} -> | |||
NewReconnectState = agAgencyUtils:resetReconnectState(ReconnectState), | |||
%% 新建连接之后 需要重置之前的buff之类状态数据 | |||
NewCliState = CliState#cliState{status = leisure, recvState = undefined, curInfo = undefined}, | |||
case agAgencyUtils:getQueue(RequestsOut + 1) of | |||
undefined -> | |||
{ok, SrvState#srvState{userPassWord = UserPassword, host = Host, reconnectState = NewReconnectState, socket = Socket}, NewCliState}; | |||
MiRequest -> | |||
dealQueueRequest(MiRequest, SrvState#srvState{socket = Socket}, NewCliState) | |||
end; | |||
{error, _Reason} -> | |||
reconnectTimer(SrvState, CliState) | |||
end; | |||
_Ret -> | |||
?WARN(ServerName, "deal connect not found agBeamPool:get(~p) ret ~p is error ~n", [PoolName, _Ret]) | |||
end; | |||
handleMsg(Msg, #srvState{serverName = ServerName} = SrvState, CliState) -> | |||
?WARN(ServerName, "unknown msg: ~p~n", [Msg]), | |||
{ok, SrvState, CliState}. | |||
-spec terminate(term(), srvState(), cliState()) -> ok. | |||
terminate(_Reason, | |||
#srvState{timerRef = TimerRef}, | |||
_CliState) -> | |||
agAgencyUtils:cancelTimer(TimerRef), | |||
agAgencyUtils:agencyReplyAll({error, shutdown}), | |||
ok. | |||
dealConnect(ServerName, HostName, Port, SocketOptions) -> | |||
case inet:getaddrs(HostName, inet) of | |||
{ok, IPList} -> | |||
Ip = agMiscUtils:randomElement(IPList), | |||
case ssl:connect(Ip, Port, SocketOptions, ?DEFAULT_CONNECT_TIMEOUT) of | |||
{ok, Socket} -> | |||
{ok, Socket}; | |||
{error, Reason} -> | |||
?WARN(ServerName, "connect error: ~p~n", [Reason]), | |||
{error, Reason} | |||
end; | |||
{error, Reason} -> | |||
?WARN(ServerName, "getaddrs error: ~p~n", [Reason]), | |||
{error, Reason} | |||
end. | |||
dealClose(SrvState, ClientState, Reply) -> | |||
agAgencyUtils:agencyReplyAll(Reply), | |||
reconnectTimer(SrvState, ClientState). | |||
reconnectTimer(#srvState{reconnectState = undefined} = SrvState, CliState) -> | |||
{ok, {SrvState#srvState{socket = undefined}, CliState}}; | |||
reconnectTimer(#srvState{reconnectState = ReconnectState} = SrvState, CliState) -> | |||
#reconnectState{current = Current} = MewReconnectState = agAgencyUtils:updateReconnectState(ReconnectState), | |||
TimerRef = erlang:send_after(Current, self(), ?miDoNetConnect), | |||
{ok, SrvState#srvState{reconnectState = MewReconnectState, socket = undefined, timerRef = TimerRef}, CliState}. | |||
dealQueueRequest({miRequest, FromPid, Method, Path, Headers, Body, RequestId, OverTime}, | |||
#srvState{serverName = ServerName, host = Host, userPassWord = UserPassWord, socket = Socket} = SrvState, | |||
#cliState{requestsOut = RequestsOut} = CliState) -> | |||
agAgencyUtils:delQueue(RequestsOut + 1), | |||
case erlang:system_time(millisecond) > OverTime of | |||
true -> | |||
%% 超时了 | |||
case agAgencyUtils:getQueue(RequestsOut + 2) of | |||
undefined -> | |||
{ok, SrvState, CliState#cliState{status = waiting, requestsOut = RequestsOut + 1}}; | |||
MiRequest -> | |||
dealQueueRequest(MiRequest, SrvState, CliState#cliState{requestsOut = RequestsOut + 1}) | |||
end; | |||
_ -> | |||
Request = agHttpProtocol:request(Method, Host, Path, [{<<"Authorization">>, UserPassWord} | Headers], Body), | |||
case ssl:send(Socket, Request) of | |||
ok -> | |||
TimerRef = | |||
case OverTime of | |||
infinity -> | |||
undefined; | |||
_ -> | |||
erlang:start_timer(OverTime, self(), waiting, [{abs, true}]) | |||
end, | |||
{ok, SrvState, CliState#cliState{status = waiting, requestsOut = RequestsOut + 1, curInfo = {FromPid, RequestId, TimerRef}}}; | |||
{error, Reason} -> | |||
?WARN(ServerName, ":send error: ~p~n", [Reason]), | |||
ssl:close(Socket), | |||
agAgencyUtils:agencyReply(FromPid, RequestId, undefined, {error, socket_send_error}), | |||
dealClose(SrvState, CliState, {error, socket_send_error}) | |||
end | |||
end. | |||
@ -1,322 +0,0 @@ | |||
-module(agSslAgency). | |||
-include("shackle_internal.hrl"). | |||
-compile(inline). | |||
-compile({inline_size, 512}). | |||
-export([ | |||
start_link/3, | |||
init_it/3, | |||
system_code_change/4, | |||
system_continue/3, | |||
system_get_state/1, | |||
system_terminate/4, | |||
init/3, | |||
handleMsg/2, | |||
terminate/2 | |||
]). | |||
-record(state, { | |||
client :: client(), | |||
init_options :: init_options(), | |||
ip :: inet:ip_address() | inet:hostname(), | |||
name :: server_name(), | |||
parent :: pid(), | |||
poolName :: poolName(), | |||
port :: inet:port_number(), | |||
reconnect_state :: undefined | reconnect_state(), | |||
socket :: undefined | ssl:sslsocket(), | |||
socket_options :: [ssl:connect_option()], | |||
timer_ref :: undefined | reference() | |||
}). | |||
-type init_opts() :: {poolName(), client(), client_options()}. | |||
-type state() :: #state {}. | |||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% genActor start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |||
-spec start_link(module(), atom(), term(), [proc_lib:spawn_option()]) -> {ok, pid()}. | |||
start_link(Name, Args, SpawnOpts) -> | |||
proc_lib:start_link(?MODULE, init_it, [Name, self(), Args], infinity, SpawnOpts). | |||
init_it(Name, Parent, Args) -> | |||
case safeRegister(Name) of | |||
true -> | |||
process_flag(trap_exit, true), | |||
moduleInit(Parent, Args); | |||
{false, Pid} -> | |||
proc_lib:init_ack(Parent, {error, {already_started, Pid}}) | |||
end. | |||
%% sys callbacks | |||
-spec system_code_change(term(), module(), undefined | term(), term()) -> {ok, term()}. | |||
system_code_change(State, _Module, _OldVsn, _Extra) -> | |||
{ok, State}. | |||
-spec system_continue(pid(), [], {module(), atom(), pid(), term()}) -> ok. | |||
system_continue(_Parent, _Debug, {Parent, State}) -> | |||
loop(Parent, State). | |||
-spec system_get_state(term()) -> {ok, term()}. | |||
system_get_state(State) -> | |||
{ok, State}. | |||
-spec system_terminate(term(), pid(), [], term()) -> none(). | |||
system_terminate(Reason, _Parent, _Debug, _State) -> | |||
exit(Reason). | |||
safeRegister(Name) -> | |||
try register(Name, self()) of | |||
true -> true | |||
catch | |||
_:_ -> {false, whereis(Name)} | |||
end. | |||
moduleInit(Parent, Args) -> | |||
case ?MODULE:init(Args) of | |||
{ok, State} -> | |||
proc_lib:init_ack(Parent, {ok, self()}), | |||
loop(Parent, State); | |||
{stop, Reason} -> | |||
proc_lib:init_ack(Parent, {error, Reason}), | |||
exit(Reason) | |||
end. | |||
loop(Parent, State) -> | |||
receive | |||
{system, From, Request} -> | |||
sys:handle_system_msg(Request, From, Parent, ?MODULE, [], {Parent, State}); | |||
{'EXIT', Parent, Reason} -> | |||
terminate(Reason, State); | |||
Msg -> | |||
{ok, NewState} = ?MODULE:handleMsg(Msg, State), | |||
loop(Parent, NewState) | |||
end. | |||
terminate(Reason, State) -> | |||
?MODULE:terminate(Reason, State), | |||
exit(Reason). | |||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% genActor end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |||
%% metal callbacks | |||
-spec init(server_name(), pid(), init_opts()) -> | |||
no_return(). | |||
init(Name, Parent, Opts) -> | |||
{PoolName, Client, ClientOptions} = Opts, | |||
self() ! ?MSG_CONNECT, | |||
InitOptions = ?LOOKUP(init_options, ClientOptions, | |||
?DEFAULT_INIT_OPTS), | |||
Ip = ?LOOKUP(ip, ClientOptions, ?DEFAULT_IP), | |||
Port = ?LOOKUP(port, ClientOptions), | |||
ReconnectState = agAgencyUtils:initReconnectState(ClientOptions), | |||
SocketOptions = ?LOOKUP(socket_options, ClientOptions, | |||
?DEFAULT_SOCKET_OPTS), | |||
{ok, {#state { | |||
client = Client, | |||
init_options = InitOptions, | |||
ip = Ip, | |||
name = Name, | |||
parent = Parent, | |||
poolName = PoolName, | |||
port = Port, | |||
reconnect_state = ReconnectState, | |||
socket_options = SocketOptions | |||
}, undefined}}. | |||
-spec handle_msg(term(), {state(), client_state()}) -> | |||
{ok, term()}. | |||
handle_msg({_, #cast {} = Cast}, {#state { | |||
socket = undefined, | |||
name = Name | |||
} = State, ClientState}) -> | |||
agAgencyUtils:agencyReply(Name, {error, no_socket}, Cast), | |||
{ok, {State, ClientState}}; | |||
handle_msg({Request, #cast { | |||
timeout = Timeout | |||
} = Cast}, {#state { | |||
client = Client, | |||
name = Name, | |||
poolName = PoolName, | |||
socket = Socket | |||
} = State, ClientState}) -> | |||
try agAgencyUtils:handleRequest(Request, ClientState) of | |||
{ok, ExtRequestId, Data, ClientState2} -> | |||
case ssl:send(Socket, Data) of | |||
ok -> | |||
Msg = {timeout, ExtRequestId}, | |||
TimerRef = erlang:send_after(Timeout, self(), Msg), | |||
shackle_queue:add(ExtRequestId, Cast, TimerRef), | |||
{ok, {State, ClientState2}}; | |||
{error, Reason} -> | |||
?WARN(PoolName, "send error: ~p", [Reason]), | |||
ssl:close(Socket), | |||
agAgencyUtils:agencyReply(Name, {error, socket_closed}, Cast), | |||
close(State, ClientState2) | |||
end | |||
catch | |||
?EXCEPTION(E, R, Stacktrace) -> | |||
?WARN(PoolName, "handleRequest crash: ~p:~p~n~p~n", | |||
[E, R, ?GET_STACK(Stacktrace)]), | |||
agAgencyUtils:agencyReply(Name, {error, client_crash}, Cast), | |||
{ok, {State, ClientState}} | |||
end; | |||
handle_msg({ssl, Socket, Data}, {#state { | |||
client = Client, | |||
name = Name, | |||
poolName = PoolName, | |||
socket = Socket | |||
} = State, ClientState}) -> | |||
try agAgencyUtils:handleData(Data, ClientState) of | |||
{ok, Replies, ClientState2} -> | |||
agAgencyUtils:agencyResponses(Replies, Name), | |||
{ok, {State, ClientState2}}; | |||
{error, Reason, ClientState2} -> | |||
?WARN(PoolName, "handleData error: ~p", [Reason]), | |||
ssl:close(Socket), | |||
close(State, ClientState2) | |||
catch | |||
?EXCEPTION(E, R, Stacktrace) -> | |||
?WARN(PoolName, "handleData crash: ~p:~p~n~p~n", | |||
[E, R, ?GET_STACK(Stacktrace)]), | |||
ssl:close(Socket), | |||
close(State, ClientState) | |||
end; | |||
handle_msg({timeout, ExtRequestId}, {#state { | |||
name = Name | |||
} = State, ClientState}) -> | |||
case shackle_queue:remove(Name, ExtRequestId) of | |||
{ok, Cast, _TimerRef} -> | |||
agAgencyUtils:agencyReply(Name, {error, timeout}, Cast); | |||
{error, not_found} -> | |||
ok | |||
end, | |||
{ok, {State, ClientState}}; | |||
handle_msg({ssl_closed, Socket}, {#state { | |||
socket = Socket, | |||
poolName = PoolName | |||
} = State, ClientState}) -> | |||
?WARN(PoolName, "connection closed", []), | |||
close(State, ClientState); | |||
handle_msg({ssl_error, Socket, Reason}, {#state { | |||
socket = Socket, | |||
poolName = PoolName | |||
} = State, ClientState}) -> | |||
?WARN(PoolName, "connection error: ~p", [Reason]), | |||
ssl:close(Socket), | |||
close(State, ClientState); | |||
handle_msg(?MSG_CONNECT, {#state { | |||
client = Client, | |||
init_options = Init, | |||
ip = Ip, | |||
poolName = PoolName, | |||
port = Port, | |||
reconnect_state = ReconnectState, | |||
socket_options = SocketOptions | |||
} = State, ClientState}) -> | |||
case connect(PoolName, Ip, Port, SocketOptions) of | |||
{ok, Socket} -> | |||
ClientState2 = agHttpProtocol:binPatterns(), | |||
ReconnectState2 = agAgencyUtils:resetReconnectState(ReconnectState), | |||
{ok, {State#state { | |||
reconnect_state = ReconnectState2, | |||
socket = Socket | |||
}, ClientState2}}; | |||
{error, _Reason} -> | |||
reconnect(State, ClientState) | |||
end; | |||
handle_msg(Msg, {#state { | |||
poolName = PoolName | |||
} = State, ClientState}) -> | |||
?WARN(PoolName, "unknown msg: ~p", [Msg]), | |||
{ok, {State, ClientState}}. | |||
-spec terminate(term(), term()) -> | |||
ok. | |||
terminate(_Reason, {#state { | |||
client = Client, | |||
name = Name, | |||
poolName = PoolName, | |||
timer_ref = TimerRef | |||
}, ClientState}) -> | |||
agAgencyUtils:cancel_timer(TimerRef), | |||
try agAgencyUtils:terminate(ClientState) | |||
catch | |||
?EXCEPTION(E, R, Stacktrace) -> | |||
?WARN(PoolName, "terminate crash: ~p:~p~n~p~n", | |||
[E, R, ?GET_STACK(Stacktrace)]) | |||
end, | |||
agAgencyUtils:agencyReplyAll(Name, {error, shutdown}), | |||
ok. | |||
%% private | |||
close(#state {name = Name} = State, ClientState) -> | |||
agAgencyUtils:agencyReplyAll(Name, {error, socket_closed}), | |||
reconnect(State, ClientState). | |||
connect(PoolName, Ip, Port, SocketOptions) -> | |||
case inet:getaddrs(Ip, inet) of | |||
{ok, Addrs} -> | |||
Ip2 = agMiscUtils:randomElement(Addrs), | |||
case ssl:connect(Ip2, Port, SocketOptions, | |||
?DEFAULT_CONNECT_TIMEOUT) of | |||
{ok, Socket} -> | |||
{ok, Socket}; | |||
{error, Reason} -> | |||
?WARN(PoolName, "connect error: ~p", [Reason]), | |||
{error, Reason} | |||
end; | |||
{error, Reason} -> | |||
?WARN(PoolName, "getaddrs error: ~p", [Reason]), | |||
{error, Reason} | |||
end. | |||
reconnect(State, undefined) -> | |||
reconnect_timer(State, undefined); | |||
reconnect(#state { | |||
client = Client, | |||
poolName = PoolName | |||
} = State, ClientState) -> | |||
try agAgencyUtils:terminate(ClientState) | |||
catch | |||
?EXCEPTION(E, R, Stacktrace) -> | |||
?WARN(PoolName, "terminate crash: ~p:~p~n~p~n", | |||
[E, R, ?GET_STACK(Stacktrace)]) | |||
end, | |||
reconnect_timer(State, ClientState). | |||
reconnect_timer(#state { | |||
reconnect_state = undefined | |||
} = State, ClientState) -> | |||
{ok, {State#state { | |||
socket = undefined | |||
}, ClientState}}; | |||
reconnect_timer(#state { | |||
reconnect_state = ReconnectState | |||
} = State, ClientState) -> | |||
ReconnectState2 = shackle_backoff:timeout(ReconnectState), | |||
#reconnect_state {current = Current} = ReconnectState2, | |||
TimerRef = erlang:send_after(Current, self(), ?MSG_CONNECT), | |||
{ok, {State#state { | |||
reconnect_state = ReconnectState2, | |||
socket = undefined, | |||
timer_ref = TimerRef | |||
}, ClientState}}. |
@ -1,90 +0,0 @@ | |||
-module(genActor). | |||
-compile(inline). | |||
-compile([{inline_size, 512}, nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]). | |||
-export([ | |||
start_link/3, | |||
init_it/3, | |||
system_code_change/4, | |||
system_continue/3, | |||
system_get_state/1, | |||
system_terminate/4 | |||
]). | |||
-spec start_link(term(), term(), list()) -> {ok, pid()} | {error, term()}. | |||
start_link(Name, Args, SpawnOpts) -> | |||
proc_lib:start_link(?MODULE, init_it, [Name, self(), Args], infinity, SpawnOpts). | |||
init_it(Name, Parent, Args) -> | |||
case safeRegister(Name) of | |||
true -> | |||
process_flag(trap_exit, true), | |||
moduleInit(Parent, Args); | |||
{false, Pid} -> | |||
proc_lib:init_ack(Parent, {error, {already_started, Pid}}) | |||
end. | |||
-spec system_code_change(term(), module(), undefined | term(), term()) -> {ok, term()}. | |||
system_code_change(State, _Module, _OldVsn, _Extra) -> | |||
{ok, State}. | |||
-spec system_continue(pid(), [], {module(), atom(), pid(), term()}) -> ok. | |||
system_continue(_Parent, _Debug, {Parent, State}) -> | |||
loop(Parent, State). | |||
-spec system_get_state(term()) -> {ok, term()}. | |||
system_get_state(State) -> | |||
{ok, State}. | |||
-spec system_terminate(term(), pid(), [], term()) -> none(). | |||
system_terminate(Reason, _Parent, _Debug, _State) -> | |||
exit(Reason). | |||
safeRegister(Name) -> | |||
try register(Name, self()) of | |||
true -> true | |||
catch | |||
_:_ -> {false, whereis(Name)} | |||
end. | |||
moduleInit(Parent, Args) -> | |||
case ?MODULE:init(Args) of | |||
{ok, State} -> | |||
proc_lib:init_ack(Parent, {ok, self()}), | |||
loop(Parent, State); | |||
{stop, Reason} -> | |||
proc_lib:init_ack(Parent, {error, Reason}), | |||
exit(Reason) | |||
end. | |||
loop(Parent, State) -> | |||
receive | |||
{system, From, Request} -> | |||
sys:handle_system_msg(Request, From, Parent, ?MODULE, [], {Parent, State}); | |||
{'EXIT', Parent, Reason} -> | |||
doTerminate(Reason, State); | |||
Msg -> | |||
{ok, NewState} = ?MODULE:handleMsg(Msg, State), | |||
loop(Parent, NewState) | |||
end. | |||
doTerminate(Reason, State) -> | |||
?MODULE:terminate(Reason, State), | |||
exit(Reason). | |||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% need %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |||
-spec init(Args :: term()) -> {ok, term()}. | |||
init(Args) -> | |||
{ok, {}}. | |||
-spec handleMsg(Msg :: term(), State :: term()) -> {ok, term()}. | |||
handleMsg(Msg, State) -> | |||
{ok, term}. | |||
-spec terminate(Reason :: term(), State :: term()) -> ok. | |||
terminate(Reason, State) -> | |||
ok. |