Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

287 řádky
12 KiB

před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
před 5 roky
  1. -module(agHttpCli).
  2. -include("agHttpCli.hrl").
  3. -include("erlArango.hrl").
  4. -compile(inline).
  5. -compile({inline_size, 128}).
  6. -export([
  7. %% 请求通用API
  8. callAgency/5
  9. , callAgency/6
  10. , callAgency/7
  11. , castAgency/5
  12. , castAgency/6
  13. , castAgency/7
  14. , castAgency/8
  15. , receiveResponse/2
  16. %% 连接池API
  17. , startPool/2
  18. , startPool/3
  19. , stopPool/1
  20. %% 单进程操作DbAPI
  21. , connectDb/1
  22. , disConnectDb/1
  23. , getCurDbInfo/1
  24. , setCurDbName/2
  25. ]).
  26. -spec callAgency(poolNameOrSocket(), method(), path(), headers(), body()) -> term() | {error, term()}.
  27. callAgency(PoolNameOrSocket, Method, Path, Headers, Body) ->
  28. callAgency(PoolNameOrSocket, Method, Path, Headers, Body, false, ?DEFAULT_TIMEOUT).
  29. -spec callAgency(poolNameOrSocket(), method(), path(), headers(), body(), boolean()) -> term() | {error, atom()}.
  30. callAgency(PoolNameOrSocket, Method, Path, Headers, Body, IsSystem) ->
  31. callAgency(PoolNameOrSocket, Method, Path, Headers, Body, IsSystem, ?DEFAULT_TIMEOUT).
  32. -spec callAgency(poolNameOrSocket(), method(), path(), headers(), body(), boolean(), timeout()) -> term() | {error, atom()}.
  33. callAgency(PoolNameOrSocket, Method, Path, Headers, Body, IsSystem, Timeout) ->
  34. case castAgency(PoolNameOrSocket, Method, Path, Headers, Body, self(), IsSystem, Timeout) of
  35. {ok, RequestId, MonitorRef} ->
  36. receiveResponse(RequestId, MonitorRef);
  37. {error, _Reason} = Err ->
  38. Err;
  39. Ret ->
  40. Ret
  41. end.
  42. -spec castAgency(poolNameOrSocket(), method(), path(), headers(), body()) -> {ok, requestId()} | {error, atom()}.
  43. castAgency(PoolNameOrSocket, Method, Path, Headers, Body) ->
  44. castAgency(PoolNameOrSocket, Method, Path, Headers, Body, self(), false, ?DEFAULT_TIMEOUT).
  45. -spec castAgency(poolNameOrSocket(), method(), path(), headers(), body(), boolean()) -> {ok, requestId()} | {error, atom()}.
  46. castAgency(PoolNameOrSocket, Method, Path, Headers, Body, IsSystem) ->
  47. castAgency(PoolNameOrSocket, Method, Path, Headers, Body, self(), IsSystem, ?DEFAULT_TIMEOUT).
  48. -spec castAgency(poolNameOrSocket(), method(), path(), headers(), body(), boolean(), timeout()) -> {ok, requestId()} | {error, atom()}.
  49. castAgency(PoolNameOrSocket, Method, Path, Headers, Body, IsSystem, Timeout) ->
  50. castAgency(PoolNameOrSocket, Method, Path, Headers, Body, self(), IsSystem, Timeout).
  51. -spec castAgency(poolNameOrSocket(), method(), path(), headers(), body(), pid(), boolean(), timeout()) -> {ok, requestId()} | {error, atom()}.
  52. castAgency(PoolNameOrSocket, Method, Path, Headers, Body, Pid, IsSystem, Timeout) ->
  53. OverTime =
  54. case Timeout of
  55. infinity -> infinity;
  56. _ ->
  57. erlang:system_time(millisecond) + Timeout
  58. end,
  59. case erlang:is_atom(PoolNameOrSocket) of
  60. true ->
  61. case agAgencyPoolMgrIns:getOneAgency(PoolNameOrSocket) of
  62. {error, pool_not_found} = Err ->
  63. Err;
  64. undefined ->
  65. {error, undefined_server};
  66. AgencyName ->
  67. MonitorRef = erlang:monitor(process, AgencyName),
  68. RequestId = {AgencyName, MonitorRef},
  69. catch AgencyName ! #miRequest{method = Method, path = Path, headers = Headers, body = Body, requestId = RequestId, fromPid = Pid, overTime = OverTime, isSystem = IsSystem},
  70. {ok, RequestId, MonitorRef}
  71. end;
  72. _ ->
  73. case getCurDbInfo(PoolNameOrSocket) of
  74. {DbName, UserPassWord, Host, Protocol} ->
  75. Request = agHttpProtocol:request(IsSystem, Body, Method, Host, DbName, Path, [UserPassWord | Headers]),
  76. case Protocol of
  77. tcp ->
  78. case gen_tcp:send(PoolNameOrSocket, Request) of
  79. ok ->
  80. TimerRef =
  81. case OverTime of
  82. infinity ->
  83. undefined;
  84. _ ->
  85. erlang:start_timer(OverTime, self(), waiting_over, [{abs, true}])
  86. end,
  87. receiveTcpData(undefined, PoolNameOrSocket, TimerRef, binary:compile_pattern(<<"\r\n">>), binary:compile_pattern(<<"\r\n\r\n">>), Method == ?AgHead);
  88. {error, Reason} = Err ->
  89. ?WARN(castAgency, ":gen_tcp send error: ~p ~n", [Reason]),
  90. disConnectDb(PoolNameOrSocket),
  91. Err
  92. end;
  93. ssl ->
  94. case ssl:send(PoolNameOrSocket, Request) of
  95. ok ->
  96. TimerRef =
  97. case OverTime of
  98. infinity ->
  99. undefined;
  100. _ ->
  101. erlang:start_timer(OverTime, self(), waiting_over, [{abs, true}])
  102. end,
  103. receiveSslData(undefined, PoolNameOrSocket, TimerRef, binary:compile_pattern(<<"\r\n">>), binary:compile_pattern(<<"\r\n\r\n">>), Method == ?AgHead);
  104. {error, Reason} = Err ->
  105. ?WARN(castAgency, ":ssl send error: ~p ~n", [Reason]),
  106. disConnectDb(PoolNameOrSocket),
  107. Err
  108. end
  109. end;
  110. _ ->
  111. {error, dbinfo_not_found}
  112. end
  113. end.
  114. -spec receiveResponse(requestId(), reference()) -> term() | {error, term()}.
  115. receiveResponse(RequestId, MonitorRef) ->
  116. receive
  117. #miRequestRet{requestId = RequestId, reply = Reply} ->
  118. erlang:demonitor(MonitorRef),
  119. case Reply of
  120. {ok, Headers, Body} ->
  121. {ok, Headers, jiffy:decode(Body, [return_maps])};
  122. _ ->
  123. Reply
  124. end;
  125. {'DOWN', MonitorRef, process, _Pid, Reason} ->
  126. {error, {agencyDown, Reason}}
  127. end.
  128. -spec receiveTcpData(recvState() | undefined, socket(), reference() | undefined, binary:cp(), binary:cp(), boolean()) -> {ok, term(), term()} | {error, term()}.
  129. receiveTcpData(RecvState, Socket, TimerRef, Rn, RnRn, IsHeadMethod) ->
  130. receive
  131. {tcp, Socket, Data} ->
  132. try agHttpProtocol:response(RecvState, Rn, RnRn, Data, IsHeadMethod) of
  133. {done, #recvState{headers = Headers, body = Body}} ->
  134. {ok, Headers, jiffy:decode(Body, [return_maps])};
  135. {ok, NewRecvState} ->
  136. receiveTcpData(NewRecvState, Socket, TimerRef, Rn, RnRn, IsHeadMethod);
  137. {error, Reason} ->
  138. ?WARN(receiveTcpData, "handle tcp data error: ~p ~n", [Reason]),
  139. disConnectDb(Socket),
  140. {error, {tcp_data_error, Reason}}
  141. catch
  142. E:R:S ->
  143. ?WARN(receiveTcpData, "handle tcp data crash: ~p:~p~n~p ~n ", [E, R, S]),
  144. disConnectDb(Socket),
  145. {error, handledata_error}
  146. end;
  147. {timeout, TimerRef, waiting_over} ->
  148. {error, timeout};
  149. {tcp_closed, Socket} ->
  150. disConnectDb(Socket),
  151. {error, tcp_closed};
  152. {tcp_error, Socket, Reason} ->
  153. disConnectDb(Socket),
  154. {error, {tcp_error, Reason}};
  155. _Msg ->
  156. ?WARN(receiveTcpData, "receive unexpect msg: ~p~n", [_Msg]),
  157. receiveTcpData(RecvState, Socket, TimerRef, Rn, RnRn, IsHeadMethod)
  158. end.
  159. -spec receiveSslData(recvState() | undefined, socket(), reference() | undefined, binary:cp(), binary:cp(), boolean()) -> {ok, term(), term()} | {error, term()}.
  160. receiveSslData(RecvState, Socket, TimerRef, Rn, RnRn, IsHeadMethod) ->
  161. receive
  162. {ssl, Socket, Data} ->
  163. try agHttpProtocol:response(RecvState, Rn, RnRn, Data, IsHeadMethod) of
  164. {done, #recvState{headers = Headers, body = Body}} ->
  165. {ok, Headers, jiffy:decode(Body, [return_maps])};
  166. {ok, NewRecvState} ->
  167. receiveTcpData(NewRecvState, Socket, TimerRef, Rn, RnRn, IsHeadMethod);
  168. {error, Reason} ->
  169. ?WARN(receiveSslData, "handle tcp data error: ~p ~n", [Reason]),
  170. disConnectDb(Socket),
  171. {error, {ssl_data_error, Reason}}
  172. catch
  173. E:R:S ->
  174. ?WARN(receiveSslData, "handle tcp data crash: ~p:~p~n~p ~n ", [E, R, S]),
  175. disConnectDb(Socket),
  176. {error, handledata_error}
  177. end;
  178. {timeout, TimerRef, waiting_over} ->
  179. {error, timeout};
  180. {ssl_closed, Socket} ->
  181. disConnectDb(Socket),
  182. {error, ssl_closed};
  183. {ssl_error, Socket, Reason} ->
  184. disConnectDb(Socket),
  185. {error, {ssl_error, Reason}};
  186. _Msg ->
  187. ?WARN(receiveSslData, "receive unexpect msg: ~p~n", [_Msg]),
  188. receiveSslData(RecvState, Socket, TimerRef, Rn, RnRn, IsHeadMethod)
  189. end.
  190. -spec startPool(poolName(), dbCfgs()) -> ok | {error, pool_name_used}.
  191. startPool(PoolName, DbCfgs) ->
  192. agAgencyPoolMgrIns:startPool(PoolName, DbCfgs, []).
  193. -spec startPool(poolName(), dbCfgs(), agencyCfgs()) -> ok | {error, pool_name_used}.
  194. startPool(PoolName, DbCfgs, AgencyCfgs) ->
  195. agAgencyPoolMgrIns:startPool(PoolName, DbCfgs, AgencyCfgs).
  196. -spec stopPool(poolName()) -> ok | {error, pool_not_started}.
  197. stopPool(PoolName) ->
  198. agAgencyPoolMgrIns:stopPool(PoolName).
  199. -spec connectDb(dbCfgs()) -> {ok, socket()} | {error, term()}.
  200. connectDb(DbCfgs) ->
  201. #dbOpts{
  202. host = Host,
  203. port = Port,
  204. hostname = HostName,
  205. dbName = DbName,
  206. protocol = Protocol,
  207. userPassword = UserPassword,
  208. socketOpts = SocketOpts
  209. } = agMiscUtils:dbOpts(DbCfgs),
  210. case inet:getaddrs(HostName, inet) of
  211. {ok, IPList} ->
  212. Ip = agMiscUtils:randomElement(IPList),
  213. case Protocol of
  214. tcp ->
  215. case gen_tcp:connect(Ip, Port, SocketOpts, ?DEFAULT_CONNECT_TIMEOUT) of
  216. {ok, Socket} ->
  217. setCurDbInfo(Socket, DbName, UserPassword, Host, Protocol),
  218. {ok, Socket};
  219. {error, Reason} = Err ->
  220. ?WARN(connectDb, "connect error: ~p~n", [Reason]),
  221. Err
  222. end;
  223. ssl ->
  224. case ssl:connect(Ip, Port, SocketOpts, ?DEFAULT_CONNECT_TIMEOUT) of
  225. {ok, Socket} ->
  226. setCurDbInfo(Socket, DbName, UserPassword, Host, Protocol),
  227. {ok, Socket};
  228. {error, Reason} = Err ->
  229. ?WARN(connectDb, "connect error: ~p~n", [Reason]),
  230. Err
  231. end
  232. end;
  233. {error, Reason} = Err ->
  234. ?WARN(connectDb, "getaddrs error: ~p~n", [Reason]),
  235. Err
  236. end.
  237. -spec disConnectDb(socket()) -> ok | {error, term()}.
  238. disConnectDb(Socket) ->
  239. case erlang:erase({'$agDbInfo', Socket}) of
  240. undefined ->
  241. ignore;
  242. {_DbName, _UserPassword, _Host, Protocol} ->
  243. case Protocol of
  244. tcp ->
  245. gen_tcp:close(Socket);
  246. ssl ->
  247. ssl:close(Socket)
  248. end
  249. end.
  250. -spec setCurDbInfo(socket(), binary(), tuple(), host(), protocol()) -> term().
  251. setCurDbInfo(Socket, DbName, UserPassword, Host, Protocol) ->
  252. erlang:put({'$agDbInfo', Socket}, {DbName, UserPassword, Host, Protocol}).
  253. -spec getCurDbInfo(socket()) -> term().
  254. getCurDbInfo(Socket) ->
  255. erlang:get({'$agDbInfo', Socket}).
  256. -spec setCurDbName(socket(), binary()) -> ok.
  257. setCurDbName(Socket, NewDbName) ->
  258. case erlang:get({'$agDbInfo', Socket}) of
  259. undefined ->
  260. ignore;
  261. {_DbName, UserPassword, Host, Protocol} ->
  262. erlang:put({'$agDbInfo', Socket}, {NewDbName, UserPassword, Host, Protocol})
  263. end,
  264. ok.