Skip to content

Commit

Permalink
feat: connect/3 to connect to NNTP server
Browse files Browse the repository at this point in the history
Similar to `gen_tcp:connect/3` but also wait for server's greeting
before returning.
  • Loading branch information
sntran committed Mar 1, 2021
1 parent 295e545 commit a5b850a
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 2 deletions.
4 changes: 3 additions & 1 deletion include/gen_nntp.hrl
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
-type name() :: atom() | {'local', term()} | {'global', term()} | {'via', module(), term()}.
-type option() ::
{'name', name()}
| {'port', pos_integer()}.
| {'port', port_number()}.
-type on_start() :: {'ok', pid()} | 'ignore' | {'error', {'already_started', pid()} | term()}.
-type address() :: inet:socket_address() | inet:hostname() | binary().
-type port_number() :: inet:port_number().
5 changes: 5 additions & 0 deletions lib/gen_nntp.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ defmodule GenNNTP do
@spec stop(module()) :: :ok
defdelegate stop(ref), to: :gen_nntp

@doc """
Connects to a NNTP server.
"""
defdelegate connect(address \\ "localhost", port \\ 119, options \\ []), to: :gen_nntp

@callback init(any()) ::
{:ok, state} | {:ok, state, timeout | :hibernate} |
:ignore | {:stop, reason :: term}
Expand Down
38 changes: 37 additions & 1 deletion src/gen_nntp.erl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
%% API
-export([
start/3,
stop/1
stop/1,
connect/0,
connect/1,
connect/2,
connect/3
]).

%% gen_server callbacks
Expand Down Expand Up @@ -92,6 +96,38 @@ stop(Ref) ->
_:_ -> ok
end.

%%-------------------------------------------------------------------
%% @doc Connects to a NNTP server.
%%
%% @end
%%-------------------------------------------------------------------
-spec connect() -> {ok, socket(), Greeting :: binary()} | {error, Reason :: timeout | inet:posix()}.
connect() ->
connect("localhost", 119, []).

-spec connect(address()) -> {ok, socket(), Greeting :: binary()} | {error, Reason :: timeout | inet:posix()}.
connect(Address) ->
connect(Address, 119, []).

-spec connect(address(), port_number()) -> {ok, socket(), Greeting :: binary()} | {error, Reason :: timeout | inet:posix()}.
connect(Address, Port) ->
connect(Address, Port, []).

-spec connect(address(), port_number(), [gen_tcp:connect_option()]) -> {ok, socket(), Greeting :: binary()} | {error, Reason :: timeout | inet:posix()}.
connect(Address, Port, Options) when is_binary(Address) ->
connect(binary_to_list(Address), Port, Options);

connect(Address, Port, _Options) ->
% @TODO: Merge default options with user-supplied options.
Options = [binary, {packet, line}, {active, false}],
case gen_tcp:connect(Address, Port, Options) of
{ok, Socket} ->
{ok, Greeting} = gen_tcp:recv(Socket, 0, 1000),
{ok, Socket, Greeting};
{error, Reason} ->
{error, Reason}
end.

%% ==================================================================
%% ranch_protocol Callbacks
%% ==================================================================
Expand Down
1 change: 1 addition & 0 deletions src/gen_nntp_internal.hrl
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
-type state() :: term().
-type socket() :: gen_tcp:socket().
34 changes: 34 additions & 0 deletions test/gen_nntp_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,40 @@ defmodule GenNNTPTest do

end

describe "connect/3" do

test "connects to a NNTP server" do
GenNNTP.start(TestNNTPServer, [], [])
assert {:ok, _socket, _greeting} = GenNNTP.connect("localhost", 119, [])
end

test "error if fail to connect to NNTP server" do
assert {:error, :econnrefused} = GenNNTP.connect("localhost", 119, [])
end

test "receives a greeting after connecting" do
GenNNTP.start(TestNNTPServer, [], [])
assert {:ok, _socket, greeting} = GenNNTP.connect("localhost", 119, [])
assert greeting =~ ~r/^20[0,1] /
end

test "connect/2 default to empty options" do
GenNNTP.start(TestNNTPServer, [], [])
assert {:ok, _socket, _greeting} = GenNNTP.connect("localhost", 119)
end

test "connect/1 default to port 119" do
GenNNTP.start(TestNNTPServer, [], [])
assert {:ok, _socket, _greeting} = GenNNTP.connect("localhost")
end

test "connect/0 default to localhost" do
GenNNTP.start(TestNNTPServer, [], [])
assert {:ok, _socket, _greeting} = GenNNTP.connect()
end

end

describe "@callback init/1" do

test "is called when a client connects to it" do
Expand Down

0 comments on commit a5b850a

Please sign in to comment.