Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support connection options map in endpoint tuple #101

Merged
merged 7 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
otp_version: ['25.2.3', '24.1.2']
rebar3_version: ['3.19.0']
otp_version: ['26.0', '25.2.3', '24.1.2']
rebar3_version: ['3.20.0']
os: [ubuntu-20.04]
env:
OTP_VERSION: ${{ matrix.otp_version }}
Expand All @@ -32,12 +32,38 @@ jobs:
run: rebar3 compile
- name: Tests
run: rebar3 ct --cover
- name: Dialyzer
run: rebar3 dialyzer
- name: Covertool
run: rebar3 covertool generate
- uses: codecov/codecov-action@v2
if: ${{ always() }}
with:
file: _build/test/covertool/grpcbox.covertool.xml
env_vars: OTP_VERSION

dialyzer:
name: Dialyze on OTP ${{ matrix.otp_version }} and ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
otp_version: ['26.0']
rebar3_version: ['3.22.1']
os: [ubuntu-20.04]
steps:
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
with:
otp-version: ${{ matrix.otp_version }}
rebar3-version: ${{ matrix.rebar3_version }}
version-type: 'strict'
- uses: actions/cache@v2
name: Cache
with:
path: |
_build
key: ${{ runner.os }}-build-${{ matrix.otp_version }}-${{ hashFiles('rebar.lock') }}-5
restore-keys: |
${{ runner.os }}-dialyzer-${{ matrix.otp_version }}-5-
- name: Compile
run: rebar3 compile
- name: Dialyzer
run: rebar3 as dialyzer dialyzer
2 changes: 2 additions & 0 deletions rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,5 @@

%% create junit xml for circleci
{ct_opts, [{ct_hooks, [cth_surefire]}]}.

{dialyzer, [{warnings, [no_unknown]}]}.
2 changes: 1 addition & 1 deletion rebar.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[{<<"acceptor_pool">>,{pkg,<<"acceptor_pool">>,<<"1.0.0">>},0},
{<<"chatterbox">>,
{git,"https://github.com/tsloughter/chatterbox",
{ref,"2c595c14c4b378d1a3c01f11a1a3e001fd8834c1"}},
{ref,"73d5bf2355bfb520440cfb4458030ecec09f36e6"}},
0},
{<<"ctx">>,{pkg,<<"ctx">>,<<"0.6.0">>},0},
{<<"gproc">>,{pkg,<<"gproc">>,<<"0.9.1">>},0},
Expand Down
29 changes: 19 additions & 10 deletions src/grpcbox_channel.erl
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@
-type t() :: any().
-type name() :: t().
-type transport() :: http | https.
-type endpoint_options() :: [ssl:ssl_option() |
{connect_timeout, integer()} |
{tcp_user_timeout, integer()}].
-type host() :: inet:ip_address() | inet:hostname().
-type endpoint() :: {transport(), host(), inet:port_number(), endpoint_options()}.
-type connection_settings() :: map().
-type endpoint() :: {transport(), host(), inet:port_number(), [ssl:ssl_options()]} |
{transport(), host(), inet:port_number(), [ssl:ssl_options()], connection_settings()}.

-type options() :: #{balancer => load_balancer(),
encoding => gprcbox:encoding(),
Expand Down Expand Up @@ -88,6 +87,9 @@

init([Name, Endpoints, Options]) ->
process_flag(trap_exit, true),

Endpoints1 = normalize_endpoints(Endpoints),

BalancerType = maps:get(balancer, Options, round_robin),
Encoding = maps:get(encoding, Options, identity),
StatsHandler = maps:get(stats_handler, Options, undefined),
Expand All @@ -100,14 +102,14 @@
pool = Name,
encoding = Encoding,
stats_handler = StatsHandler,
endpoints = Endpoints
endpoints = Endpoints1
},

case maps:get(sync_start, Options, false) of
false ->
{ok, idle, Data, [{next_event, internal, connect}]};
true ->
_ = start_workers(Name, StatsHandler, Encoding, Endpoints),
_ = start_workers(Name, StatsHandler, Encoding, Endpoints1),

Check warning on line 112 in src/grpcbox_channel.erl

View check run for this annotation

Codecov / codecov/patch

src/grpcbox_channel.erl#L112

Added line #L112 was not covered by tests
{ok, connected, Data}
end.

Expand Down Expand Up @@ -173,8 +175,15 @@
start_workers(Pool, StatsHandler, Encoding, Endpoints) ->
[begin
gproc_pool:add_worker(Pool, Endpoint),
{ok, Pid} = grpcbox_subchannel:start_link(Endpoint, Pool, {Transport, Host, Port, EndpointOptions},
Encoding, StatsHandler),
{ok, Pid} = grpcbox_subchannel:start_link(Endpoint, Pool, {Transport, Host, Port, SSLOptions, ConnectionSettings},
Encoding, StatsHandler),
Pid
end || Endpoint={Transport, Host, Port, EndpointOptions} <- Endpoints].

end || Endpoint={Transport, Host, Port, SSLOptions, ConnectionSettings} <- Endpoints].

%% add the chatterbox connection settings map to the endpoint if it isn't there already
normalize_endpoints(Endpoints) ->
lists:map(fun({Transport, Host, Port, SSLOptions}) ->
{Transport, Host, Port, SSLOptions, #{}};
({Transport, Host, Port, SSLOptions, ConnectionSettings}) ->
{Transport, Host, Port, SSLOptions, ConnectionSettings}

Check warning on line 188 in src/grpcbox_channel.erl

View check run for this annotation

Codecov / codecov/patch

src/grpcbox_channel.erl#L188

Added line #L188 was not covered by tests
end, Endpoints).
22 changes: 7 additions & 15 deletions src/grpcbox_subchannel.erl
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,17 @@ init([Name, Channel, Endpoint, Encoding, StatsHandler]) ->
endpoint=Endpoint,
channel=Channel}}.

info_map({http, Host, 80, _}, Encoding, StatsHandler) ->
info_map({http, Host, 80, _, _}, Encoding, StatsHandler) ->
#{authority => list_to_binary(Host),
scheme => <<"http">>,
encoding => Encoding,
stats_handler => StatsHandler};
info_map({https, Host, 443, _}, Encoding, StatsHandler) ->
info_map({https, Host, 443, _, _}, Encoding, StatsHandler) ->
#{authority => list_to_binary(Host),
scheme => <<"https">>,
encoding => Encoding,
stats_handler => StatsHandler};
info_map({Scheme, Host, Port, _}, Encoding, StatsHandler) ->
info_map({Scheme, Host, Port, _, _}, Encoding, StatsHandler) ->
#{authority => list_to_binary(Host ++ ":" ++ integer_to_list(Port)),
scheme => atom_to_binary(Scheme, utf8),
encoding => Encoding,
Expand Down Expand Up @@ -111,18 +111,10 @@ terminate(Reason, _State, #data{conn_pid=Pid,
ok.

connect(Data=#data{conn=undefined,
endpoint={Transport, Host, Port, EndpointOptions}}, From, Actions) ->
% Get and delete non-ssl options from endpoint options, these are passed as connection settings
ConnectTimeout = proplists:get_value(connect_timeout, EndpointOptions, 5000),
TcpUserTimeout = proplists:get_value(tcp_user_timeout, EndpointOptions, 0),
EndpointOptions2 = proplists:delete(connect_timeout, EndpointOptions),
EndpointOptions3 = proplists:delete(tcp_user_timeout, EndpointOptions2),

case h2_client:start_link(Transport, Host, Port, options(Transport, EndpointOptions3),
#{garbage_on_end => true,
stream_callback_mod => grpcbox_client_stream,
connect_timeout => ConnectTimeout,
tcp_user_timeout => TcpUserTimeout}) of
endpoint={Transport, Host, Port, SSLOptions, ConnectionSettings}}, From, Actions) ->
case h2_client:start_link(Transport, Host, Port, options(Transport, SSLOptions),
ConnectionSettings#{garbage_on_end => true,
stream_callback_mod => grpcbox_client_stream}) of
{ok, Conn} ->
Pid = h2_stream_set:connection(Conn),
{next_state, ready, Data#data{conn=Conn, conn_pid=Pid}, Actions};
Expand Down
39 changes: 21 additions & 18 deletions test/grpcbox_SUITE_data/certificates/ca.pem
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
-----BEGIN CERTIFICATE-----
MIIDSTCCAjGgAwIBAgIUbJEDBjGTuji/9gWi6eGHhISJ7dEwDQYJKoZIhvcNAQEL
BQAwNDESMBAGA1UEAwwJbG9jYWxob3N0MQswCQYDVQQGEwJVUzERMA8GA1UEBwwI
TGFya3NwdXIwHhcNMjMwNjA3MTQ1NzE0WhcNMjMwNzA3MTQ1NzE0WjA0MRIwEAYD
VQQDDAlsb2NhbGhvc3QxCzAJBgNVBAYTAlVTMREwDwYDVQQHDAhMYXJrc3B1cjCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANWVUbdk812XheZFS1jOLLou
YqImVgYhvWnjDqVMjGi4+OJzVrBcYHcXjFdGUsVe2mRm8vJ4q8DKMCGtxXof3y+5
Ch8DihBaHc6/udE5pA/8eAwfVHyYucJ36EBQ8BOsoLYWjqIyGE40tEAXcIvRi6gX
c4Iwzzf8ZacE+E4SSPrevWxSCY5pyAlI08zxY5tdznT0DW1np5Ix/5vRXolZouwq
PDV7IKdhIW1QK2Eq4vgTHBIzvA4ZxfXNDyCdUagC0qc2Sj0WvfJIKjBDiFY9PFyS
iwyOS+sqG9KQIrTeP9qtVADwBIQ4fHCuWqplFj32ydk0gei98dIyQWy6MYW+QVkC
AwEAAaNTMFEwHQYDVR0OBBYEFAVcy6SQzWd8G5QzQvt7SdRScPk7MB8GA1UdIwQY
MBaAFAVcy6SQzWd8G5QzQvt7SdRScPk7MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
hvcNAQELBQADggEBAD/tZHnpZlyRNgVi6UvdJobYMqNnVnbXOWYkuJP+lviZnuN/
BDb4FUIf9nzvY6ZTi2VX0Md2tmzmEuvllWbDs7NVzxtKL66n9i4MOjs6AW53jZNa
bfdzfIZVwo4M6F4xEwJVeYsQhAxvjbZzsQepJDi1vcBTMFH7uR4TD+9yYKWSoedU
5XrxUu0EjIwkYxjLNbco+j7CZ9e4zcaocJLVKRhm1P4cx63GfFlSWFuuU4otviqz
m7kQ7ipxQZpw4jDvrIsckNOxmf4eP5vS6tEGXDBV0JlWJNcuET5rb24cAcbKJcsa
XB0lldwf596qZjXYR1lbZ8RKlrQCiBAl/5eikj0=
MIIDwDCCAqigAwIBAgIUXMlP8/6iUkU3Rem9PhcISuywVVQwDQYJKoZIhvcNAQEL
BQAwOzESMBAGA1UEAwwJbG9jYWxob3N0MSUwIwYDVQQuExxSdTFrMUdmbEtyakJ5
cVBMdlNIWlZCaW1ERnc9MB4XDTIzMTEwOTE0MjU1NVoXDTMzMTEwNjE0MjU1NVow
OzESMBAGA1UEAwwJbG9jYWxob3N0MSUwIwYDVQQuExxSdTFrMUdmbEtyakJ5cVBM
dlNIWlZCaW1ERnc9MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu7UP
lnxd9Zz7BtAY/l4JJAOIsbv0dQjepp3GQAzilUDTlVStl8jPLbP69VVFhH/oELyE
3pWA030Hd+xJvJ8P/yMlH+OU48j9dtGLFCkt7DQmr9zedkT8iZjF67yxEC0H9uf6
eIM162U5OdPWANiYn6XLcyKAwHE8D5op1CQo5zJj+UFdqxXi0zGgpAgOKgavqzf6
VSUCB+0VxVAUXrZGyojasYJTHOVFrT3whMv4GrIy2YAxnixZoDrC/rECKVoUNTjX
543VWA78rq/EEmpzHXFjZ/JiDMw6Ijf3QxzsXWCyLR5J/AwbyD6E459Ld4X05o/F
TboWA1GCQkbzJnC6dwIDAQABo4G7MIG4MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
BBYEFEbtZNRn5Sq4wcqjy70h2VQYpgxcMA4GA1UdDwEB/wQEAwIBhjB2BgNVHSME
bzBtgBRG7WTUZ+UquMHKo8u9IdlUGKYMXKE/pD0wOzESMBAGA1UEAwwJbG9jYWxo
b3N0MSUwIwYDVQQuExxSdTFrMUdmbEtyakJ5cVBMdlNIWlZCaW1ERnc9ghRcyU/z
/qJSRTdF6b0+FwhK7LBVVDANBgkqhkiG9w0BAQsFAAOCAQEAro4qY76Pst+Ffmy+
2jQ3iBPAOVmR6Yb6Ybyxkr5f4aYQ2b2Kf17qe2bKsu1eqqHXMUF1ALfAfgL8tCM3
C4ievxKv8PcekMqp54XF+6ad70sWg4i+MmjbhpCPBNq/7g1W/lG9v3cpCxTEoeC0
+kQIlGyxDOZfaGd+OB/Q9fV1sMcH2pV+4YJE6uvOxkvDIpX5HJa9dTTu8Ozm2k7w
wD84j3zlg9TNyW0r62ONbwK+vym1QdjuXos7glxoX7raRkdW/RsIfYqa25m756Sc
v+pzjnN8NmzyKK+kkPRQ7ScUFC2lKXryyXX7Als5YFw0nxNZ4Ye1vuUJujJhGMfe
qBXAeg==
-----END CERTIFICATE-----
52 changes: 26 additions & 26 deletions test/grpcbox_SUITE_data/certificates/server1.key
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDFZd8QIioOf5qg
7kpd/CJjtkvrh7qYuVjre02C4YVqv0RKapK7Ruhloidc+rq0DBr6r5JsiYdMBJRE
wg5Sz3mqlMpj94cwh2qzoL/1krAOHbHoVjbPAUCsmW/QZbUKJRRU+ZXgJVnb8hVO
xOxBuEuBWh4mGdWEbdIfaH+JszDCbKC2kFK7Wy4IF5+j35Gg2cQpTxuvb7NoGEP8
eyEX0WSV+sNJcIs2huRjph76SotZ+sICyGWdBNh4QgPD3+X5m+g4J/VpbiREKfsu
T/XO1FBlQtfceG/IotheAzbokTiVr8rKjHjEPyCcPeyUhJytzLty/t8F9wbc/bUf
N3kV9ppnAgMBAAECggEAEmkwd2BAXO7Q3L6s5/wqtvMbPKIBqNnsrbXn4lOnbm/d
bjVnbxkrdsM7eaQXAtD4OTZj6USgfloU/B6/WEDqn5rWD6HYFZIjxRIypTRjwEVL
wRg9b2w1/IMpFx5NVt9jeJN4w5moOmfnTdv3DyAhxrRBiJszO3FEvlIwRwcT/qYa
Bv77JqZD40WlmV0b/jm2xY6St0d//HS1opvoB/2NSGlrmtsgagiH7CFxhDXBmUOA
JJbKr7uq8mOqyI6n7azcBnZU1hTgtEJ0NRxpqKVzsPXZDc4rlFs1Ir4/+2YM5Q8M
zPxW4KWrat9SrvkLDyJ5PLgHIsp8qWVRWRDxxtt/lQKBgQDwGbTTHMu3iN34+1Jc
3KqnbptzZXiBTprPMf966xsEmdHNK54dhePHevCstHW9pcIFiTXnC1HIwHixRsdf
Bi/4o2CBtsHAUJUK2SsiKKwbg5cOa88oACyYJIKgtYuXcQrFiBMWP58V+5DlMJE+
qAF+D4VtuNwvzNPJcD1Ovrki2wKBgQDSeECy4HF+xFlW9So0Wr0sjJNwbOK5u/tO
VJsos8we8dlCqgKfZYEWDf0kIvl6jDMmI0yf7TdmKKGMcW8zh7uF5qRtNcDRC/iY
0ZbhIeQX4eD5w8lTEaiXt4c3Kgl9v7Eb9TfTQ2ny8SQTCsE2hWJabN2bpp8FDccB
7Wj9eSGuZQKBgFKu95eQHhOZXZ/FpMp374jzTTNDKWmWUTezJyEEX+yIsDhwoeXW
2ucyTjmbd8SUlalkZBypyENTDP03u6bcsZ51XOGutzBsT7dJrFH6IbLj8Rw1QkSr
MrA+OoHvox/G/QejYbdSt41RcceLnyktoD3ySGfNtn37kp+XOHWqtoTrAoGAQqdo
vf2Mk/v02zArXIc8D+a5LsqdBvs8fDMZLEu8ojQvfQhAamCIAAcQGyikX6YU8MgP
FTrX55eIieTGtcgPoDlJ63gxh0LGSQdfRA8qoFGdoRvbH16hSOMLhHHgrZ1Opq8D
LfnUjObHaOxoAi891atSh1++TqhtVPPt4xBAlW0CgYAPENGGswRxkjkLS3QkOABN
+Bv3zgRmoLealcW8X11yW47ARAZVGkXirZgJP77ZMCR+kE48AF9Szi2rO87+yUm+
bv9gjW4P/5yG7pQa7HRHyXDJ9EgmQmqHl4ByjTFvG1yc1eQ/8cZT3fVfneAQqGCX
YszkXIs1Taso97Y2kEry/A==
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDLxtcJStNPpCB9
Iv+QwXMTLaErCnjPzC+2K2wgU7EC1sif76q22ZdSHzMaI92h2eusrOnAuWXQNTOo
ffIfIMZZvt25aYAZKj+Xad6nrWJ7FSvo5fEChIIcPj8Iq72R0zcnbYhQNzMTedE1
SlBbadmlw1RbN6cDnFgmWvGUrU1ZyEbq2yjONZLE3yyEKLfyhsQAaVqq3cdjhXAM
ComPFg+vRoOiXLUidiJtC+8leCkI9V0QnxuLsPA3A/4MMfKxdGMk7vPLremAndXN
xuCoDMgNScxUlhQec+W6GXMVZ9WlvZjsTM/AWQq2DkWrNJ+gZJj+Srwvea/LFHB1
QwlWD00hAgMBAAECggEAY/vgLrMEE6OYPU4az0/bwqE03wV4WZz6HAwaNZJa2+W+
8pqJzMXetXCRhlXqvStLs6Hz35gYGJzCB/4j+pn+OLKp3/uf2rkcEpLjqKouE+5D
aTbJlk6l+G2iSALcNNzJxxK7O4CaEwhGWjtoSjIZlHfOwCMCU4c2yTr+JdESjuYR
Z6ynCCa6sGEPXVwtFHFUto1S+aWkdd8+1KY5a2Tgpx7xPxcKhLPaPhIPQQ8gHXz0
s+WAPSFpboi/0XKgeqXmyRcpbcKZlPqUh1vtD3/c+wkR5G8xy5G7oMlgE5aS8etk
czixy9kBLQEXWQrC4/jk27nniDIKZPn/fiUZkpFMMQKBgQDvDcIrZ9pckydSMqWG
VDtJO80H1ynyFly9QZZfK0sqvK2w/P7qn3BLfG4eJEbq6uaiFHbEbzN959quD7Mg
G6B7EaSnmBc5YY+K6I9Q1A/TGEo25/npDbkJ5HUsAbEMJl0edYmICvIcFjFhRGc4
qOyIftxqePQKHLB8SCaVFph8owKBgQDaOOPBditLaPBhGRZUOomx7I9BSefBVq7S
qxQKqNh1tsOOOiy0msq+f+pcVR2+itzP7psjuYkEgklkqvw2P8vOeu3thQwa1iFK
uIDdeF0HVxiCwFI9IZRdZAshHEJXrjOvj2bLelbwGuy/giPkotv0cAcl6ONQWFfA
569TCVZHawKBgBu6qtVCHLA0WZFNUqn8R0w9ZZENQk5UjbleTEUJzpRMgpFPJ3qr
t+jprBRO/PLvAIW4ffZXN8/Y/yLFq2+EBN+BsmnGWJtNV8szIryrfJJt9N3dlr2T
2+zr1TOflpvkL1UDKUrgiij74gp4VsjZv2Yt4P9wvE4X+djQvbj5gAKlAoGACvOZ
8oaUq6crkSPqK/X4HRbLJbKoz9oi0e3GBrbsjhPLAqNGxRWToTXYNCQNZxee90x5
OrS//JrxRf0SxUI0XztqH2Zy8hHW/+H8jaDRwmGLmFxAhFLgGEPCDzpU1gOnEmN2
/DU6kbg4M3A7jujhcwYARdXHOqwEU2kNMnSggNsCgYBx6UYAj9z2m2PNtsHOmE4p
tdFUzS2ELEkHaEGwLhG359MVVPl3+Sdh1cSmDSeh6DHUWWXPt04lWIrU7BN7Qasj
4kXG1vOy6LM5qpCwrJuVH3Z7LneB4pue0VT+x3Q5QVoSLHYiJJdHAqLoPbqcKfV1
q2png2Z97Dnrt6jMUwRhNA==
-----END PRIVATE KEY-----
40 changes: 23 additions & 17 deletions test/grpcbox_SUITE_data/certificates/server1.pem
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
-----BEGIN CERTIFICATE-----
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
mSww1w==
-----END CERTIFICATE-----
Loading