|
@@ -27,7 +27,7 @@
|
|
|
| unknown).
|
|
|
|
|
|
-record(connect,
|
|
|
- {opts :: list(),
|
|
|
+ {opts :: map(),
|
|
|
auth_fun :: auth_fun() | undefined,
|
|
|
auth_state :: any() | undefined,
|
|
|
auth_send :: {integer(), iodata()} | undefined,
|
|
@@ -42,18 +42,17 @@
|
|
|
-define(AUTH_SASL_FINAL, 12).
|
|
|
|
|
|
init({Host, Username, Password, Opts}) ->
|
|
|
- Opts1 = [{host, Host},
|
|
|
- {username, Username},
|
|
|
- {password, Password}
|
|
|
- | Opts],
|
|
|
+ Opts1 = maps:merge(Opts,
|
|
|
+ #{host => Host,
|
|
|
+ username => Username,
|
|
|
+ password => Password}),
|
|
|
#connect{opts = Opts1}.
|
|
|
|
|
|
execute(PgSock, #connect{opts = Opts, stage = connect} = State) ->
|
|
|
- Host = get_val(host, Opts),
|
|
|
- Username = get_val(username, Opts),
|
|
|
- %% _ = get_val(password, Opts),
|
|
|
- Timeout = proplists:get_value(timeout, Opts, 5000),
|
|
|
- Port = proplists:get_value(port, Opts, 5432),
|
|
|
+ #{host := Host,
|
|
|
+ username := Username} = Opts,
|
|
|
+ Timeout = maps:get(timeout, Opts, 5000),
|
|
|
+ Port = maps:get(port, Opts, 5432),
|
|
|
SockOpts = [{active, false}, {packet, raw}, binary, {nodelay, true}, {keepalive, true}],
|
|
|
case gen_tcp:connect(Host, Port, SockOpts, Timeout) of
|
|
|
{ok, Sock} ->
|
|
@@ -67,29 +66,27 @@ execute(PgSock, #connect{opts = Opts, stage = connect} = State) ->
|
|
|
inet:getopts(Sock, [recbuf, sndbuf]),
|
|
|
inet:setopts(Sock, [{buffer, max(RecBufSize, SndBufSize)}]),
|
|
|
|
|
|
- PgSock1 = maybe_ssl(Sock, proplists:get_value(ssl, Opts, false), Opts, PgSock),
|
|
|
+ PgSock1 = maybe_ssl(Sock, maps:get(ssl, Opts, false), Opts, PgSock),
|
|
|
|
|
|
Opts2 = ["user", 0, Username, 0],
|
|
|
- Opts3 = case proplists:get_value(database, Opts, undefined) of
|
|
|
- undefined -> Opts2;
|
|
|
- Database -> [Opts2 | ["database", 0, Database, 0]]
|
|
|
+ Opts3 = case maps:find(database, Opts) of
|
|
|
+ error -> Opts2;
|
|
|
+ {ok, Database} -> [Opts2 | ["database", 0, Database, 0]]
|
|
|
end,
|
|
|
|
|
|
- Replication = proplists:get_value(replication, Opts, undefined),
|
|
|
- Opts4 = case Replication of
|
|
|
- undefined -> Opts3;
|
|
|
- Replication ->
|
|
|
- [Opts3 | ["replication", 0, Replication, 0]]
|
|
|
+ {Opts4, PgSock2} =
|
|
|
+ case Opts of
|
|
|
+ #{replication := Replication} ->
|
|
|
+ {[Opts3 | ["replication", 0, Replication, 0]],
|
|
|
+ epgsql_sock:init_replication_state(PgSock1)};
|
|
|
+ _ -> {Opts3, PgSock1}
|
|
|
end,
|
|
|
- PgSock2 = case Replication of
|
|
|
- undefined -> PgSock1;
|
|
|
- _ -> epgsql_sock:init_replication_state(PgSock1)
|
|
|
- end,
|
|
|
|
|
|
epgsql_sock:send(PgSock2, [<<196608:?int32>>, Opts4, 0]),
|
|
|
- PgSock3 = case proplists:get_value(async, Opts, undefined) of
|
|
|
- undefined -> PgSock2;
|
|
|
- Async -> epgsql_sock:set_attr(async, Async, PgSock2)
|
|
|
+ PgSock3 = case Opts of
|
|
|
+ #{async := Async} ->
|
|
|
+ epgsql_sock:set_attr(async, Async, PgSock2);
|
|
|
+ _ -> PgSock2
|
|
|
end,
|
|
|
{ok, PgSock3, State#connect{stage = maybe_auth}};
|
|
|
{error, Reason} = Error ->
|
|
@@ -104,11 +101,11 @@ maybe_ssl(S, false, _, PgSock) ->
|
|
|
epgsql_sock:set_net_socket(gen_tcp, S, PgSock);
|
|
|
maybe_ssl(S, Flag, Opts, PgSock) ->
|
|
|
ok = gen_tcp:send(S, <<8:?int32, 80877103:?int32>>),
|
|
|
- Timeout = proplists:get_value(timeout, Opts, 5000),
|
|
|
+ Timeout = maps:get(timeout, Opts, 5000),
|
|
|
{ok, <<Code>>} = gen_tcp:recv(S, 1, Timeout),
|
|
|
case Code of
|
|
|
$S ->
|
|
|
- SslOpts = proplists:get_value(ssl_opts, Opts, []),
|
|
|
+ SslOpts = maps:get(ssl_opts, Opts, []),
|
|
|
case ssl:connect(S, SslOpts, Timeout) of
|
|
|
{ok, S2} ->
|
|
|
epgsql_sock:set_net_socket(ssl, S2, PgSock);
|
|
@@ -167,14 +164,14 @@ auth_handle(Data, PgSock, #connect{auth_fun = Fun, auth_state = AuthSt} = St) ->
|
|
|
|
|
|
%% AuthenticationCleartextPassword
|
|
|
auth_cleartext(init, _AuthState, #connect{opts = Opts}) ->
|
|
|
- Password = get_val(password, Opts),
|
|
|
+ Password = maps:get(password, Opts),
|
|
|
{send, ?PASSWORD, [Password, 0], undefined};
|
|
|
auth_cleartext(_, _, _) -> unknown.
|
|
|
|
|
|
%% AuthenticationMD5Password
|
|
|
auth_md5(init, Salt, #connect{opts = Opts}) ->
|
|
|
- User = get_val(username, Opts),
|
|
|
- Password = get_val(password, Opts),
|
|
|
+ User = maps:get(username, Opts),
|
|
|
+ Password = maps:get(password, Opts),
|
|
|
Digest1 = hex(erlang:md5([Password, User])),
|
|
|
Str = ["md5", hex(erlang:md5([Digest1, Salt])), 0],
|
|
|
{send, ?PASSWORD, Str, undefined};
|
|
@@ -182,14 +179,14 @@ auth_md5(_, _, _) -> unknown.
|
|
|
|
|
|
%% AuthenticationSASL
|
|
|
auth_scram(init, undefined, #connect{opts = Opts}) ->
|
|
|
- User = get_val(username, Opts),
|
|
|
+ User = maps:get(username, Opts),
|
|
|
Nonce = epgsql_scram:get_nonce(16),
|
|
|
ClientFirst = epgsql_scram:get_client_first(User, Nonce),
|
|
|
SaslInitialResponse = [?SCRAM_AUTH_METHOD, 0, <<(iolist_size(ClientFirst)):?int32>>, ClientFirst],
|
|
|
{send, ?SASL_ANY_RESPONSE, SaslInitialResponse, {auth_request, Nonce}};
|
|
|
auth_scram(<<?AUTH_SASL_CONTINUE:?int32, ServerFirst/binary>>, {auth_request, Nonce}, #connect{opts = Opts}) ->
|
|
|
- User = get_val(username, Opts),
|
|
|
- Password = get_val(password, Opts),
|
|
|
+ User = maps:get(username, Opts),
|
|
|
+ Password = maps:get(password, Opts),
|
|
|
ServerFirstParts = epgsql_scram:parse_server_first(ServerFirst, Nonce),
|
|
|
{ClientFinalMessage, ServerProof} = epgsql_scram:get_client_final(ServerFirstParts, Nonce, User, Password),
|
|
|
{send, ?SASL_ANY_RESPONSE, ClientFinalMessage, {server_final, ServerProof}};
|
|
@@ -242,12 +239,6 @@ handle_message(?ERROR, Err, Sock, #connect{stage = Stage} = _State) when Stage =
|
|
|
handle_message(_, _, _, _) ->
|
|
|
unknown.
|
|
|
|
|
|
-
|
|
|
-get_val(Key, Proplist) ->
|
|
|
- Val = proplists:get_value(Key, Proplist),
|
|
|
- (Val =/= undefined) orelse error({required_option, Key}),
|
|
|
- Val.
|
|
|
-
|
|
|
hex(Bin) ->
|
|
|
HChar = fun(N) when N < 10 -> $0 + N;
|
|
|
(N) when N < 16 -> $W + N
|