|
|
- -module(agVstCli).
- -include("agVstCli.hrl").
- -include("eArango.hrl").
-
- -compile(inline).
- -compile({inline_size, 128}).
-
- -export([
- %% Common Request API
- callAgency/5
- , callAgency/6
- , callAgency/7
- , castAgency/5
- , castAgency/6
- , castAgency/7
- , castAgency/8
- , receiveRequestRet/2
-
- %% Pools API
- , startPool/2
- , startPool/3
- , stopPool/1
-
- %% Single Process DbAPI
- , connectDb/1
- , disConnectDb/1
- , getCurDbInfo/1
- , useDatabase/2
-
- ]).
-
- -spec callAgency(poolNameOrSocket(), method(), path(), headers(), body()) -> term() | {error, term()}.
- callAgency(PoolNameOrSocket, Method, Path, Headers, Body) ->
- callAgency(PoolNameOrSocket, Method, Path, Headers, Body, false, ?DEFAULT_TIMEOUT).
-
- -spec callAgency(poolNameOrSocket(), method(), path(), headers(), body(), boolean()) -> term() | {error, atom()}.
- callAgency(PoolNameOrSocket, Method, Path, Headers, Body, IsSystem) ->
- callAgency(PoolNameOrSocket, Method, Path, Headers, Body, IsSystem, ?DEFAULT_TIMEOUT).
-
- -spec callAgency(poolNameOrSocket(), method(), path(), headers(), body(), boolean(), timeout()) -> term() | {error, atom()}.
- callAgency(PoolNameOrSocket, Method, Path, Headers, Body, IsSystem, Timeout) ->
- case castAgency(PoolNameOrSocket, Method, Path, Headers, Body, self(), IsSystem, Timeout) of
- {waitRRT, RequestId, MonitorRef} ->
- receiveRequestRet(RequestId, MonitorRef);
- {error, _Reason} = Err ->
- Err;
- Ret ->
- Ret
- end.
-
- -spec castAgency(poolNameOrSocket(), method(), path(), headers(), body()) -> {ok, messageId()} | {error, atom()}.
- castAgency(PoolNameOrSocket, Method, Path, Headers, Body) ->
- castAgency(PoolNameOrSocket, Method, Path, Headers, Body, self(), false, ?DEFAULT_TIMEOUT).
-
- -spec castAgency(poolNameOrSocket(), method(), path(), headers(), body(), boolean()) -> {ok, messageId()} | {error, atom()}.
- castAgency(PoolNameOrSocket, Method, Path, Headers, Body, IsSystem) ->
- castAgency(PoolNameOrSocket, Method, Path, Headers, Body, self(), IsSystem, ?DEFAULT_TIMEOUT).
-
- -spec castAgency(poolNameOrSocket(), method(), path(), headers(), body(), boolean(), timeout()) -> {ok, messageId()} | {error, atom()}.
- castAgency(PoolNameOrSocket, Method, Path, Headers, Body, IsSystem, Timeout) ->
- castAgency(PoolNameOrSocket, Method, Path, Headers, Body, self(), IsSystem, Timeout).
-
- -spec castAgency(poolNameOrSocket(), method(), path(), headers(), body(), pid(), boolean(), timeout()) -> {ok, messageId()} | {error, atom()}.
- castAgency(PoolNameOrSocket, Method, Path, Headers, Body, Pid, IsSystem, Timeout) ->
- OverTime =
- case Timeout of
- infinity -> infinity;
- _ ->
- erlang:monotonic_time(millisecond) + Timeout
- end,
- case erlang:is_atom(PoolNameOrSocket) of
- true ->
- case agAgencyPoolMgrIns:getOneAgency(PoolNameOrSocket) of
- {error, pool_not_found} = Err ->
- Err;
- undefined ->
- {error, undefined_server};
- AgencyName ->
- MonitorRef = erlang:monitor(process, AgencyName),
- RequestId = {AgencyName, MonitorRef},
- catch AgencyName ! #agReq{method = Method, path = Path, headers = Headers, body = Body, messageId = RequestId, fromPid = Pid, overTime = OverTime, isSystem = IsSystem},
- {waitRRT, RequestId, MonitorRef}
- end;
- _ ->
- case getCurDbInfo(PoolNameOrSocket) of
- {DbName, UserPassWord, Host, Protocol} ->
- Request = agVstProtocol:request(IsSystem, Body, Method, Host, DbName, Path, [UserPassWord | Headers]),
- case Protocol of
- tcp ->
- case gen_tcp:send(PoolNameOrSocket, Request) of
- ok ->
- receiveTcpData(undefined, PoolNameOrSocket, binary:compile_pattern(<<"\r\n">>), binary:compile_pattern(<<"\r\n\r\n">>), Method == ?AgHead);
- {error, Reason} = Err ->
- ?AgWarn(castAgency, ":gen_tcp send error: ~p ~n", [Reason]),
- disConnectDb(PoolNameOrSocket),
- Err
- end;
- ssl ->
- case ssl:send(PoolNameOrSocket, Request) of
- ok ->
- receiveSslData(undefined, PoolNameOrSocket, binary:compile_pattern(<<"\r\n">>), binary:compile_pattern(<<"\r\n\r\n">>), Method == ?AgHead);
- {error, Reason} = Err ->
- ?AgWarn(castAgency, ":ssl send error: ~p ~n", [Reason]),
- disConnectDb(PoolNameOrSocket),
- Err
- end
- end;
- _ ->
- {error, dbinfoNotFound}
- end
- end.
-
- -spec receiveRequestRet(messageId(), reference()) -> {StatusCode :: non_neg_integer(), Body :: binary(), Headers :: binary()} | {error, term()}.
- receiveRequestRet(RequestId, MonitorRef) ->
- receive
- #agReqRet{messageId = RequestId, reply = Reply} ->
- erlang:demonitor(MonitorRef),
- case Reply of
- {_StatusCode, Body, _Headers} ->
- case Body of
- <<>> ->
- erlang:setelement(2, Reply, #{});
- _ ->
- erlang:setelement(2, Reply, jiffy:decode(Body, [return_maps, copy_strings]))
- end;
- _ ->
- Reply
- end;
- {'DOWN', MonitorRef, process, _Pid, Reason} ->
- {error, {agencyDown, Reason}}
- end.
-
- -spec receiveTcpData(recvState() | undefined, socket(), binary:cp(), binary:cp(), boolean()) -> {ok, term(), term()} | {error, term()}.
- receiveTcpData(RecvState, Socket, Rn, RnRn, IsHeadMethod) ->
- receive
- {tcp, Socket, Data} ->
- try agVstProtocol:response(RecvState, Rn, RnRn, Data, IsHeadMethod) of
- {done, #recvState{statusCode = StatusCode, headers = Headers, body = Body}} ->
- case Body of
- <<>> ->
- {ok, #{}, StatusCode, Headers};
- _ ->
- {ok, jiffy:decode(Body, [return_maps, copy_strings]), StatusCode, Headers}
- end;
- {ok, NewRecvState} ->
- receiveTcpData(NewRecvState, Socket, Rn, RnRn, IsHeadMethod);
- {error, Reason} ->
- ?AgWarn(receiveTcpData, "handle tcp data error: ~p ~n", [Reason]),
- disConnectDb(Socket),
- {error, {tcpDataError, Reason}}
- catch
- E:R:S ->
- ?AgWarn(receiveTcpData, "handle tcp data crash: ~p:~p~n~p ~n ", [E, R, S]),
- disConnectDb(Socket),
- {error, handledataError}
- end;
- {tcp_closed, Socket} ->
- disConnectDb(Socket),
- {error, tcp_closed};
- {tcp_error, Socket, Reason} ->
- disConnectDb(Socket),
- {error, {tcp_error, Reason}}
- end.
-
- -spec receiveSslData(recvState() | undefined, socket(), binary:cp(), binary:cp(), boolean()) -> {ok, term(), term()} | {error, term()}.
- receiveSslData(RecvState, Socket, Rn, RnRn, IsHeadMethod) ->
- receive
- {ssl, Socket, Data} ->
- try agVstProtocol:response(RecvState, Rn, RnRn, Data, IsHeadMethod) of
- {done, #recvState{statusCode = StatusCode, headers = Headers, body = Body}} ->
- case Body of
- <<>> ->
- {ok, #{}, StatusCode, Headers};
- _ ->
- {ok, jiffy:decode(Body, [return_maps, copy_strings]), StatusCode, Headers}
- end;
- {ok, NewRecvState} ->
- receiveSslData(NewRecvState, Socket, Rn, RnRn, IsHeadMethod);
- {error, Reason} ->
- ?AgWarn(receiveSslData, "handle tcp data error: ~p ~n", [Reason]),
- disConnectDb(Socket),
- {error, {sslDataError, Reason}}
- catch
- E:R:S ->
- ?AgWarn(receiveSslData, "handle tcp data crash: ~p:~p~n~p ~n ", [E, R, S]),
- disConnectDb(Socket),
- {error, handledataError}
- end;
- {ssl_closed, Socket} ->
- disConnectDb(Socket),
- {error, ssl_closed};
- {ssl_error, Socket, Reason} ->
- disConnectDb(Socket),
- {error, {ssl_error, Reason}}
- end.
-
- -spec startPool(poolName(), dbCfgs()) -> ok | {error, poolNameUsed}.
- startPool(PoolName, DbCfgs) ->
- agAgencyPoolMgrIns:startPool(PoolName, DbCfgs, []).
-
- -spec startPool(poolName(), dbCfgs(), agencyCfgs()) -> ok | {error, poolNameUsed}.
- startPool(PoolName, DbCfgs, AgencyCfgs) ->
- agAgencyPoolMgrIns:startPool(PoolName, DbCfgs, AgencyCfgs).
-
- -spec stopPool(poolName()) -> ok | {error, poolNotStarted}.
- stopPool(PoolName) ->
- agAgencyPoolMgrIns:stopPool(PoolName).
-
- -spec connectDb(dbCfgs()) -> {ok, socket()} | {error, term()}.
- connectDb(DbCfgs) ->
- #dbOpts{
- host = Host,
- port = Port,
- hostname = HostName,
- dbName = DbName,
- protocol = Protocol,
- userPassword = UserPassword,
- socketOpts = SocketOpts
- } = agMiscUtils:dbOpts(DbCfgs),
- case inet:getaddrs(HostName, inet) of
- {ok, IPList} ->
- Ip = agMiscUtils:randomElement(IPList),
- case Protocol of
- tcp ->
- case gen_tcp:connect(Ip, Port, SocketOpts, ?AgDefConnTimeout) of
- {ok, Socket} ->
- setCurDbInfo(Socket, DbName, UserPassword, Host, Protocol),
- {ok, Socket};
- {error, Reason} = Err ->
- ?AgWarn(connectDb, "connect error: ~p~n", [Reason]),
- Err
- end;
- ssl ->
- case ssl:connect(Ip, Port, SocketOpts, ?AgDefConnTimeout) of
- {ok, Socket} ->
- setCurDbInfo(Socket, DbName, UserPassword, Host, Protocol),
- {ok, Socket};
- {error, Reason} = Err ->
- ?AgWarn(connectDb, "connect error: ~p~n", [Reason]),
- Err
- end
- end;
- {error, Reason} = Err ->
- ?AgWarn(connectDb, "getaddrs error: ~p~n", [Reason]),
- Err
- end.
-
- -spec disConnectDb(socket()) -> ok | {error, term()}.
- disConnectDb(Socket) ->
- case erlang:erase({'$agDbInfo', Socket}) of
- undefined ->
- ignore;
- {_DbName, _UserPassword, _Host, Protocol} ->
- case Protocol of
- tcp ->
- gen_tcp:close(Socket);
- ssl ->
- ssl:close(Socket)
- end
- end.
-
- -spec setCurDbInfo(socket(), binary(), tuple(), host(), protocol()) -> term().
- setCurDbInfo(Socket, DbName, UserPassword, Host, Protocol) ->
- erlang:put({'$agDbInfo', Socket}, {DbName, UserPassword, Host, Protocol}).
-
- -spec getCurDbInfo(socket()) -> term().
- getCurDbInfo(Socket) ->
- erlang:get({'$agDbInfo', Socket}).
-
- -spec useDatabase(socket(), binary()) -> ok.
- useDatabase(Socket, NewDbName) ->
- case erlang:get({'$agDbInfo', Socket}) of
- undefined ->
- ignore;
- {_DbName, UserPassword, Host, Protocol} ->
- erlang:put({'$agDbInfo', Socket}, {<<"/_db/", NewDbName/binary>>, UserPassword, Host, Protocol})
- end,
- ok.
|