Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

213 rindas
10 KiB

pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
pirms 5 gadiem
  1. -module(agTcpAgencyIns).
  2. -include("agHttpCli.hrl").
  3. -compile(inline).
  4. -compile({inline_size, 512}).
  5. -export([
  6. %% 内部行为API
  7. init/1
  8. , handleMsg/3
  9. , terminate/3
  10. ]).
  11. -record(srvState, {
  12. poolName :: poolName(),
  13. serverName :: serverName(),
  14. userPassWord :: binary(),
  15. host :: binary(),
  16. rn :: binary:cp(),
  17. rnrn :: binary:cp(),
  18. reconnectState :: undefined | reconnectState(),
  19. socket :: undefined | inet:socket(),
  20. timerRef :: undefined | reference()
  21. }).
  22. -type srvState() :: #srvState{}.
  23. -spec init(term()) -> no_return().
  24. init({PoolName, AgencyName, AgencyOpts}) ->
  25. BacklogSize = ?GET_FROM_LIST(backlogSize, AgencyOpts, ?DEFAULT_BACKLOG_SIZE),
  26. ReconnectState = agAgencyUtils:initReconnectState(AgencyOpts),
  27. self() ! ?miDoNetConnect,
  28. {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}}.
  29. -spec handleMsg(term(), srvState(), cliState()) -> {ok, term(), term()}.
  30. handleMsg({miRequest, FromPid, _Method, _Path, _Headers, _Body, RequestId, _OverTime},
  31. #srvState{socket = undefined} = SrvState,
  32. CliState) ->
  33. agAgencyUtils:agencyReply(FromPid, RequestId, undefined, {error, no_socket}),
  34. {ok, SrvState, CliState};
  35. handleMsg({miRequest, FromPid, Method, Path, Headers, Body, RequestId, OverTime} = MiRequest,
  36. #srvState{serverName = ServerName, host = Host, userPassWord = UserPassWord, socket = Socket} = SrvState,
  37. #cliState{backlogNum = BacklogNum, backlogSize = BacklogSize, requestsIn = RequestsIn, status = Status} = CliState) ->
  38. case BacklogNum >= BacklogSize of
  39. true ->
  40. ?WARN(ServerName, ":backlog full curNum:~p Total: ~p ~n", [BacklogNum, BacklogSize]),
  41. agAgencyUtils:agencyReply(FromPid, RequestId, undefined, {error, backlog_full}),
  42. {ok, SrvState, CliState};
  43. _ ->
  44. case Status of
  45. leisure -> %% 空闲模式
  46. Request = agHttpProtocol:request(Method, Host, Path, [{<<"Authorization">>, UserPassWord} | Headers], Body),
  47. case gen_tcp:send(Socket, Request) of
  48. ok ->
  49. TimerRef =
  50. case OverTime of
  51. infinity ->
  52. undefined;
  53. _ ->
  54. erlang:start_timer(OverTime, self(), waiting, [{abs, true}])
  55. end,
  56. {ok, SrvState, CliState#cliState{status = waiting, backlogNum = BacklogNum + 1, curInfo = {FromPid, RequestId, TimerRef}}};
  57. {error, Reason} ->
  58. ?WARN(ServerName, ":send error: ~p~n", [Reason]),
  59. gen_tcp:close(Socket),
  60. agAgencyUtils:agencyReply(FromPid, RequestId, undefined, {error, socket_send_error}),
  61. dealClose(SrvState, CliState, {error, socket_send_error})
  62. end;
  63. _ ->
  64. agAgencyUtils:addQueue(RequestsIn, MiRequest),
  65. {ok, SrvState, CliState#cliState{requestsIn = RequestsIn + 1, backlogNum = BacklogNum + 1}}
  66. end
  67. end;
  68. handleMsg({tcp, Socket, Data},
  69. #srvState{serverName = ServerName, rn = Rn, rnrn = RnRn, socket = Socket} = SrvState,
  70. #cliState{backlogNum = BacklogNum, curInfo = CurInfo, requestsOut = RequestsOut, recvState = RecvState} = CliState) ->
  71. try agHttpProtocol:response(RecvState, Rn, RnRn, Data) of
  72. {done, #recvState{statusCode = StatusCode, contentLength = ContentLength, body = Body}} ->
  73. agAgencyUtils:agencyReply(CurInfo, #requestRet{statusCode = StatusCode, contentLength = ContentLength, body = Body}),
  74. case agAgencyUtils:getQueue(RequestsOut + 1) of
  75. undefined ->
  76. {ok, SrvState, CliState#cliState{backlogNum = BacklogNum - 1, status = leisure, curInfo = undefined, recvState = undefined}};
  77. MiRequest ->
  78. dealQueueRequest(MiRequest, SrvState, CliState#cliState{backlogNum = BacklogNum - 1, status = leisure, curInfo = undefined, recvState = undefined})
  79. end;
  80. {ok, NewRecvState} ->
  81. {ok, SrvState, CliState#cliState{recvState = NewRecvState}};
  82. {error, Reason} ->
  83. ?WARN(ServerName, "handle tcp data error: ~p~n", [Reason]),
  84. gen_tcp:close(Socket),
  85. dealClose(SrvState, CliState, {error, tcp_data_error})
  86. catch
  87. E:R:S ->
  88. ?WARN(ServerName, "handle tcp data crash: ~p:~p~n~p~n", [E, R, S]),
  89. gen_tcp:close(Socket),
  90. dealClose(SrvState, CliState, {{error, agency_handledata_error}})
  91. end;
  92. handleMsg({timeout, TimerRef, waiting},
  93. #srvState{socket = Socket} = SrvState,
  94. #cliState{backlogNum = BacklogNum, curInfo = {FromPid, RequestId, TimerRef}} = CliState) ->
  95. agAgencyUtils:agencyReply(FromPid, RequestId, undefined, {error, timeout}),
  96. %% 之前的数据超时之后 要关闭tcp 然后重新建立连接 以免后面该tcp收到该次超时数据 影响后面请求的接收数据 导致数据错乱
  97. gen_tcp:close(Socket),
  98. timer:sleep(1000),
  99. self() ! ?miDoNetConnect,
  100. {ok, SrvState, CliState#cliState{backlogNum = BacklogNum - 1}};
  101. handleMsg({tcp_closed, Socket},
  102. #srvState{socket = Socket, serverName = ServerName} = SrvState,
  103. CliState) ->
  104. ?WARN(ServerName, "connection closed~n", []),
  105. dealClose(SrvState, CliState, {error, tcp_closed});
  106. handleMsg({tcp_error, Socket, Reason},
  107. #srvState{socket = Socket, serverName = ServerName} = SrvState,
  108. CliState) ->
  109. ?WARN(ServerName, "connection error: ~p~n", [Reason]),
  110. gen_tcp:close(Socket),
  111. dealClose(SrvState, CliState, {error, tcp_error});
  112. handleMsg(?miDoNetConnect,
  113. #srvState{poolName = PoolName, serverName = ServerName, reconnectState = ReconnectState} = SrvState,
  114. #cliState{requestsOut = RequestsOut} = CliState) ->
  115. case ?agBeamPool:get(PoolName) of
  116. #poolOpts{hostname = HostName, port = Port, host = Host, userPassword = UserPassword} ->
  117. case dealConnect(ServerName, HostName, Port, ?DEFAULT_SOCKET_OPTS) of
  118. {ok, Socket} ->
  119. NewReconnectState = agAgencyUtils:resetReconnectState(ReconnectState),
  120. %% 新建连接之后 需要重置之前的buff之类状态数据
  121. NewCliState = CliState#cliState{status = leisure, recvState = undefined, curInfo = undefined},
  122. case agAgencyUtils:getQueue(RequestsOut + 1) of
  123. undefined ->
  124. {ok, SrvState#srvState{userPassWord = UserPassword, host = Host, reconnectState = NewReconnectState, socket = Socket}, NewCliState};
  125. MiRequest ->
  126. dealQueueRequest(MiRequest, SrvState#srvState{socket = Socket}, NewCliState)
  127. end;
  128. {error, _Reason} ->
  129. reconnectTimer(SrvState, CliState)
  130. end;
  131. _Ret ->
  132. ?WARN(ServerName, "deal connect not found agBeamPool:get(~p) ret ~p is error ~n", [PoolName, _Ret])
  133. end;
  134. handleMsg(Msg, #srvState{serverName = ServerName} = SrvState, CliState) ->
  135. ?WARN(ServerName, "unknown msg: ~p~n", [Msg]),
  136. {ok, SrvState, CliState}.
  137. -spec terminate(term(), srvState(), cliState()) -> ok.
  138. terminate(_Reason,
  139. #srvState{timerRef = TimerRef},
  140. _CliState) ->
  141. agAgencyUtils:cancelTimer(TimerRef),
  142. agAgencyUtils:agencyReplyAll({error, shutdown}),
  143. ok.
  144. dealConnect(ServerName, HostName, Port, SocketOptions) ->
  145. case inet:getaddrs(HostName, inet) of
  146. {ok, IPList} ->
  147. Ip = agMiscUtils:randomElement(IPList),
  148. case gen_tcp:connect(Ip, Port, SocketOptions, ?DEFAULT_CONNECT_TIMEOUT) of
  149. {ok, Socket} ->
  150. {ok, Socket};
  151. {error, Reason} ->
  152. ?WARN(ServerName, "connect error: ~p~n", [Reason]),
  153. {error, Reason}
  154. end;
  155. {error, Reason} ->
  156. ?WARN(ServerName, "getaddrs error: ~p~n", [Reason]),
  157. {error, Reason}
  158. end.
  159. dealClose(SrvState, ClientState, Reply) ->
  160. agAgencyUtils:agencyReplyAll(Reply),
  161. reconnectTimer(SrvState, ClientState).
  162. reconnectTimer(#srvState{reconnectState = undefined} = SrvState, CliState) ->
  163. {ok, {SrvState#srvState{socket = undefined}, CliState}};
  164. reconnectTimer(#srvState{reconnectState = ReconnectState} = SrvState, CliState) ->
  165. #reconnectState{current = Current} = MewReconnectState = agAgencyUtils:updateReconnectState(ReconnectState),
  166. TimerRef = erlang:send_after(Current, self(), ?miDoNetConnect),
  167. {ok, SrvState#srvState{reconnectState = MewReconnectState, socket = undefined, timerRef = TimerRef}, CliState}.
  168. dealQueueRequest({miRequest, FromPid, Method, Path, Headers, Body, RequestId, OverTime},
  169. #srvState{serverName = ServerName, host = Host, userPassWord = UserPassWord, socket = Socket} = SrvState,
  170. #cliState{requestsOut = RequestsOut} = CliState) ->
  171. agAgencyUtils:delQueue(RequestsOut + 1),
  172. case erlang:system_time(millisecond) > OverTime of
  173. true ->
  174. %% 超时了
  175. case agAgencyUtils:getQueue(RequestsOut + 2) of
  176. undefined ->
  177. {ok, SrvState, CliState#cliState{status = waiting, requestsOut = RequestsOut + 1}};
  178. MiRequest ->
  179. dealQueueRequest(MiRequest, SrvState, CliState#cliState{requestsOut = RequestsOut + 1})
  180. end;
  181. _ ->
  182. Request = agHttpProtocol:request(Method, Host, Path, [{<<"Authorization">>, UserPassWord} | Headers], Body),
  183. case gen_tcp:send(Socket, Request) of
  184. ok ->
  185. TimerRef =
  186. case OverTime of
  187. infinity ->
  188. undefined;
  189. _ ->
  190. erlang:start_timer(OverTime, self(), waiting, [{abs, true}])
  191. end,
  192. {ok, SrvState, CliState#cliState{status = waiting, requestsOut = RequestsOut + 1, curInfo = {FromPid, RequestId, TimerRef}}};
  193. {error, Reason} ->
  194. ?WARN(ServerName, ":send error: ~p~n", [Reason]),
  195. gen_tcp:close(Socket),
  196. agAgencyUtils:agencyReply(FromPid, RequestId, undefined, {error, socket_send_error}),
  197. dealClose(SrvState, CliState, {error, socket_send_error})
  198. end
  199. end.