diff --git a/include/agHttpCli.hrl b/include/agHttpCli.hrl index c8a3ec9..8bcc359 100644 --- a/include/agHttpCli.hrl +++ b/include/agHttpCli.hrl @@ -7,8 +7,9 @@ %% 默认值定义 -define(DEFAULT_BASE_URL, <<"http://120.77.213.39:8529">>). --define(DEFAULT_DBNAME, <<"_db/_system">>). --define(USER_PASSWORD, <<"root:156736">>). +-define(DEFAULT_DBNAME, <<"_system">>). +-define(DEFAULT_USER, <<"root">>). +-define(DEFAULT_PASSWORD, <<"156736">>). -define(DEFAULT_BACKLOG_SIZE, 1024). -define(DEFAULT_CONNECT_TIMEOUT, 5000). -define(DEFAULT_POOL_SIZE, 16). @@ -17,7 +18,7 @@ -define(DEFAULT_RECONNECT_MAX, 120000). -define(DEFAULT_TIMEOUT, infinity). -define(DEFAULT_PID, self()). --define(DEFAULT_SOCKET_OPTS, [binary, {active, true}, {nodelay, true}, {delay_send, true}, {keepalive, true}, {recbuf, 2097152}, {send_timeout, 5000}, {send_timeout_close, true}]). +-define(DEFAULT_SOCKET_OPTS, [binary, {active, true}, {nodelay, true}, {delay_send, true}, {keepalive, true}, {recbuf,1048576}, {send_timeout, 5000}, {send_timeout_close, true}]). -define(GET_FROM_LIST(Key, List), agMiscUtils:getListValue(Key, List, undefined)). -define(GET_FROM_LIST(Key, List, Default), agMiscUtils:getListValue(Key, List, Default)). @@ -126,7 +127,8 @@ -type dbCfg() :: {baseUrl, binary()} | {dbName, binary()} | - {userPassword, binary()} | + {user, binary()} | + {password, binary()} | {poolSize, poolSize()} | {socketOpts, [gen_tcp:connect_option(), ...]}. diff --git a/src/arangoApi/agDbMgr.erl b/src/arangoApi/agDbMgr.erl index ca03cd1..a2576cf 100644 --- a/src/arangoApi/agDbMgr.erl +++ b/src/arangoApi/agDbMgr.erl @@ -7,48 +7,82 @@ %% doc_address:https://www.arangodb.com/docs/stable/http/database-database-management.html -%% 检索有关当前数据库的信息(别名 /_api/database/properties) -%% GET /_api/database/current +% 数据库信息永久链接 +% 检索有关当前数据库的信息(别名/_ap/database/properties) +% GET /_api/database/current +% 检索有关当前数据库的信息 +% 响应是具有以下属性的JSON对象: +% name:当前数据库的名称 +% id:当前数据库的ID +% path:当前数据库的文件系统路径 +% isSystem:当前数据库是否为_system数据库 +% sharding:此数据库中创建的集合的默认分片方法 +% ReplicationFactor:此数据库中集合的默认复制因子 +% writeConcern:此数据库中集合的默认写关注点 +% 返回码 +% 200:如果成功检索到信息,则返回。 +% 400:如果请求无效,则返回。 +% 404:如果找不到数据库,则返回。 curDbInfo(PoolNameOrSocket) -> agHttpCli:callAgency(PoolNameOrSocket, ?AgGet, <<"/_api/database/current">>, [], undefined). -%% 检索当前用户可以访问的所有数据库的列表 -%% GET /_api/database/user -curVisitDbs(PoolNameOrSocket) -> +% 检索当前用户可以访问的所有数据库的列表 +% GET /_api/database/user +% 检索当前用户可以访问的所有数据库的列表,而无需指定其他用户名或密码。 +% 返回码 +% 200:如果数据库列表编译成功,则返回。 +% 400:如果请求无效,则返回。 +visitDbs(PoolNameOrSocket) -> agHttpCli:callAgency(PoolNameOrSocket, ?AgGet, <<"/_api/database/user">>, [], undefined). -%% 检索所有现有数据库的列表 -%% GET /_api/database -curDbList(PoolNameOrSocket) -> +% 检索所有现有数据库的列表 +% GET /_api/database +% 检索所有现有数据库的列表 +% 注意:只能从_system数据库中检索数据库列表。 +% 注意:您现在应该使用GET用户API来获取可用数据库的列表。 +% 返回码 +% 200:如果数据库列表编译成功,则返回。 +% 400:如果请求无效,则返回。 +% 403:如果请求未在_system数据库中执行,则返回。 +allDbs(PoolNameOrSocket) -> agHttpCli:callAgency(PoolNameOrSocket, ?AgGet, <<"/_api/database">>, [], undefined). - -%% 创建一个新的数据库 -%% POST /_api/database +% 创建一个新的数据库 +% POST /_api/database % 具有以下属性的JSON对象是必需的: % name:必须包含一个有效的数据库名称。 % options:可选对象,可以包含以下属性: -% sharding:用于此数据库中新集合的分片方法。有效值为:“”,“ flexible”或“ single”。前两个是等效的。(仅集群) -% ReplicationFactor:在此数据库中创建的新集合的默认复制因子。 -% 特殊值包括“ satellite”和将其禁用复制的“ satellite”(将集合复制到每个数据库服务器)和“ 1”。(仅集群) -% writeConcern:在此数据库中创建的新集合的默认写关注。 -% 它确定在不同的DBServer上同步每个分片需要多少个副本。如果集群中的副本数量很少,那么分片将拒绝写入。 -% 但是,具有足够最新副本的分片写入将同时成功。writeConcern的值 不能大于ReplicationFactor。(仅集群) -% users:必须是最初为新数据库创建的用户对象数组。对于已经存在的用户,不会更改用户信息。 -% 如果未指定users或不包含任何用户,则将使用空字符串密码创建默认用户 root。这确保了新数据库在创建后将可访问。 -% 每个用户对象可以包含以下属性: -% username:要创建的用户的登录名 -% passwd:用户密码(字符串)。如果未指定,则默认为空字符串。 -% active:一个标志,指示是否应该激活用户帐户。默认值为true。如果设置为false,则用户将无法登录数据库。 -% extra:带有额外用户信息的JSON对象。Extra中包含的数据 将为用户存储,但ArangoDB不会进一步解释。 - +% sharding:用于此数据库中新集合的分片方法。有效值为:“”,“ flexible”或“ single”。前两个是等效的。(仅集群) +% ReplicationFactor:在此数据库中创建的新集合的默认复制因子。特殊值包括“ satellite”和将其禁用复制的“ satellite”(将集合复制到每个数据库服务器)和“ 1”。(仅集群) +% writeConcern:在此数据库中创建的新集合的默认写关注。它确定在不同的DBServer上同步每个分片需要多少个副本。如果集群中的副本数量很少,那么分片将拒绝写入。但是,具有足够最新副本的分片写入将同时成功。writeConcern的值 不能大于ReplicationFactor。(仅集群) +% users:必须是最初为新数据库创建的用户对象数组。对于已经存在的用户,不会更改用户信息。如果未指定users或不包含任何用户,则将使用空字符串密码创建默认用户 root。这确保了新数据库在创建后将可访问。每个用户对象可以包含以下属性: +% username:要创建的用户的登录名 +% passwd:用户密码(字符串)。如果未指定,则默认为空字符串。 +% active:一个标志,指示是否应该激活用户帐户。默认值为true。如果设置为false,则用户将无法登录数据库。 +% extra:带有额外用户信息的JSON对象。Extra中包含的数据 将为用户存储,但ArangoDB不会进一步解释。 +% 创建一个新的数据库 +% 响应是一个JSON对象,其属性结果设置为true。 +% 注意:仅可以在_system数据库中创建新数据库。 +% 返回码 +% 201:如果数据库创建成功,则返回。 +% 400:如果请求参数无效或具有指定名称的数据库已存在,则返回。 +% 403:如果请求未在_system数据库中执行,则返回。 +% 409:如果具有指定名称的数据库已经存在,则返回。 newDb(PoolNameOrSocket, MapData) -> BodyStr = jiffy:encode(MapData), agHttpCli:callAgency(PoolNameOrSocket, ?AgPost, <<"/_api/database">>, [], BodyStr, true). -%% 删除现有数据库 -%% DELETE /_api/database/{database-name} - +% 删除现有数据库 +% DELETE /_api/database/{database-name} +% 路径参数 +% database-name(必填):数据库的名称 +% 删除数据库以及其中存储的所有数据。 +% 注意:只能从_system数据库中删除数据库。该_SYSTEM数据库本身不能被丢弃。 +% 返回码 +% 200:如果成功删除数据库,则返回。 +% 400:如果请求格式错误,则返回。 +% 403:如果请求未在_system数据库中执行,则返回。 +% 404:如果找不到数据库,则返回。 delDb(PoolNameOrSocket, Name) -> Path = <<"/_api/database/", Name/binary>>, agHttpCli:callAgency(PoolNameOrSocket, ?AgDelete, Path, [], undefined, true). diff --git a/src/httpCli/agAgencyPoolMgrIns.erl b/src/httpCli/agAgencyPoolMgrIns.erl index 95efec2..7396b7f 100644 --- a/src/httpCli/agAgencyPoolMgrIns.erl +++ b/src/httpCli/agAgencyPoolMgrIns.erl @@ -112,7 +112,7 @@ agencyMod(_) -> agencySpec(ServerMod, ServerName, Args) -> %% TODO 下面spawn_opt 参数需要调优 - StartFunc = {ServerMod, start_link, [ServerName, Args, [{min_heap_size, 10240}, {min_bin_vheap_size, 524288}, {fullsweep_after, 512}]]}, + StartFunc = {ServerMod, start_link, [ServerName, Args, [{min_heap_size, 10240}, {min_bin_vheap_size, 524288}, {fullsweep_after, 1024}]]}, {ServerName, StartFunc, transient, infinity, worker, [ServerMod]}. -spec startChildren(atom(), protocol(), poolSize(), agencyOpts()) -> ok. diff --git a/src/httpCli/agHttpCli.erl b/src/httpCli/agHttpCli.erl index aed19cb..8d85572 100644 --- a/src/httpCli/agHttpCli.erl +++ b/src/httpCli/agHttpCli.erl @@ -40,7 +40,7 @@ callAgency(PoolNameOrSocket, Method, Path, Headers, Body, IsSystem) -> -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 - {ok, RequestId, MonitorRef} -> + {waitRRT, RequestId, MonitorRef} -> receiveRequestRet(RequestId, MonitorRef); {error, _Reason} = Err -> Err; @@ -79,7 +79,7 @@ castAgency(PoolNameOrSocket, Method, Path, Headers, Body, Pid, IsSystem, Timeout MonitorRef = erlang:monitor(process, AgencyName), RequestId = {AgencyName, MonitorRef}, catch AgencyName ! #miRequest{method = Method, path = Path, headers = Headers, body = Body, requestId = RequestId, fromPid = Pid, overTime = OverTime, isSystem = IsSystem}, - {ok, RequestId, MonitorRef} + {waitRRT, RequestId, MonitorRef} end; _ -> case getCurDbInfo(PoolNameOrSocket) of @@ -89,14 +89,7 @@ castAgency(PoolNameOrSocket, Method, Path, Headers, Body, Pid, IsSystem, Timeout tcp -> case gen_tcp:send(PoolNameOrSocket, Request) of ok -> - TimerRef = - case OverTime of - infinity -> - undefined; - _ -> - erlang:start_timer(OverTime, self(), waiting_over, [{abs, true}]) - end, - receiveTcpData(undefined, PoolNameOrSocket, TimerRef, binary:compile_pattern(<<"\r\n">>), binary:compile_pattern(<<"\r\n\r\n">>), Method == ?AgHead); + receiveTcpData(undefined, PoolNameOrSocket, binary:compile_pattern(<<"\r\n">>), binary:compile_pattern(<<"\r\n\r\n">>), Method == ?AgHead); {error, Reason} = Err -> ?WARN(castAgency, ":gen_tcp send error: ~p ~n", [Reason]), disConnectDb(PoolNameOrSocket), @@ -105,14 +98,7 @@ castAgency(PoolNameOrSocket, Method, Path, Headers, Body, Pid, IsSystem, Timeout ssl -> case ssl:send(PoolNameOrSocket, Request) of ok -> - TimerRef = - case OverTime of - infinity -> - undefined; - _ -> - erlang:start_timer(OverTime, self(), waiting_over, [{abs, true}]) - end, - receiveSslData(undefined, PoolNameOrSocket, TimerRef, binary:compile_pattern(<<"\r\n">>), binary:compile_pattern(<<"\r\n\r\n">>), Method == ?AgHead); + receiveSslData(undefined, PoolNameOrSocket, binary:compile_pattern(<<"\r\n">>), binary:compile_pattern(<<"\r\n\r\n">>), Method == ?AgHead); {error, Reason} = Err -> ?WARN(castAgency, ":ssl send error: ~p ~n", [Reason]), disConnectDb(PoolNameOrSocket), @@ -139,15 +125,15 @@ receiveRequestRet(RequestId, MonitorRef) -> {error, {agencyDown, Reason}} end. --spec receiveTcpData(recvState() | undefined, socket(), reference() | undefined, binary:cp(), binary:cp(), boolean()) -> {ok, term(), term()} | {error, term()}. -receiveTcpData(RecvState, Socket, TimerRef, Rn, RnRn, IsHeadMethod) -> +-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 agHttpProtocol:response(RecvState, Rn, RnRn, Data, IsHeadMethod) of {done, #recvState{headers = Headers, body = Body}} -> {ok, Headers, jiffy:decode(Body, [return_maps, copy_strings])}; {ok, NewRecvState} -> - receiveTcpData(NewRecvState, Socket, TimerRef, Rn, RnRn, IsHeadMethod); + receiveTcpData(NewRecvState, Socket, Rn, RnRn, IsHeadMethod); {error, Reason} -> ?WARN(receiveTcpData, "handle tcp data error: ~p ~n", [Reason]), disConnectDb(Socket), @@ -158,8 +144,6 @@ receiveTcpData(RecvState, Socket, TimerRef, Rn, RnRn, IsHeadMethod) -> disConnectDb(Socket), {error, handledata_error} end; - {timeout, TimerRef, waiting_over} -> - {error, timeout}; {tcp_closed, Socket} -> disConnectDb(Socket), {error, tcp_closed}; @@ -168,15 +152,15 @@ receiveTcpData(RecvState, Socket, TimerRef, Rn, RnRn, IsHeadMethod) -> {error, {tcp_error, Reason}} end. --spec receiveSslData(recvState() | undefined, socket(), reference() | undefined, binary:cp(), binary:cp(), boolean()) -> {ok, term(), term()} | {error, term()}. -receiveSslData(RecvState, Socket, TimerRef, Rn, RnRn, IsHeadMethod) -> +-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 agHttpProtocol:response(RecvState, Rn, RnRn, Data, IsHeadMethod) of {done, #recvState{headers = Headers, body = Body}} -> {ok, Headers, jiffy:decode(Body, [return_maps, copy_strings])}; {ok, NewRecvState} -> - receiveSslData(NewRecvState, Socket, TimerRef, Rn, RnRn, IsHeadMethod); + receiveSslData(NewRecvState, Socket, Rn, RnRn, IsHeadMethod); {error, Reason} -> ?WARN(receiveSslData, "handle tcp data error: ~p ~n", [Reason]), disConnectDb(Socket), @@ -187,8 +171,6 @@ receiveSslData(RecvState, Socket, TimerRef, Rn, RnRn, IsHeadMethod) -> disConnectDb(Socket), {error, handledata_error} end; - {timeout, TimerRef, waiting_over} -> - {error, timeout}; {ssl_closed, Socket} -> disConnectDb(Socket), {error, ssl_closed}; @@ -276,6 +258,6 @@ setCurDbName(Socket, NewDbName) -> undefined -> ignore; {_DbName, UserPassword, Host, Protocol} -> - erlang:put({'$agDbInfo', Socket}, {NewDbName, UserPassword, Host, Protocol}) + erlang:put({'$agDbInfo', Socket}, {<<"_db/", NewDbName/binary>>, UserPassword, Host, Protocol}) end, ok. diff --git a/src/httpCli/agMiscUtils.erl b/src/httpCli/agMiscUtils.erl index 70a2863..594bce1 100644 --- a/src/httpCli/agMiscUtils.erl +++ b/src/httpCli/agMiscUtils.erl @@ -53,12 +53,13 @@ parseUrl(Protocol, Rest) -> dbOpts(DbCfgs) -> BaseUrl = ?GET_FROM_LIST(baseUrl, DbCfgs, ?DEFAULT_BASE_URL), DbName = ?GET_FROM_LIST(dbName, DbCfgs, ?DEFAULT_DBNAME), - UserPassword = ?GET_FROM_LIST(userPassword, DbCfgs, ?USER_PASSWORD), + User = ?GET_FROM_LIST(user, DbCfgs, ?DEFAULT_USER), + Password = ?GET_FROM_LIST(password, DbCfgs, ?DEFAULT_PASSWORD), PoolSize = ?GET_FROM_LIST(poolSize, DbCfgs, ?DEFAULT_POOL_SIZE), SocketOpts = ?GET_FROM_LIST(socketOpts, DbCfgs, ?DEFAULT_SOCKET_OPTS), DbOpts = agMiscUtils:parseUrl(BaseUrl), - UserPasswordBase64 = {<<"Authorization">>, <<"Basic ", (base64:encode(UserPassword))/binary>>}, - DbOpts#dbOpts{dbName = DbName, userPassword = UserPasswordBase64, poolSize = PoolSize, socketOpts = SocketOpts}. + UserPasswordBase64 = {<<"Authorization">>, <<"Basic ", (base64:encode(<>))/binary>>}, + DbOpts#dbOpts{dbName = <<"_db/", DbName/binary>>, userPassword = UserPasswordBase64, poolSize = PoolSize, socketOpts = SocketOpts}. -spec agencyOpts(list()) -> agencyOpts(). agencyOpts(AgencyCfgs) ->