condor
condor copied to clipboard
A minimal library for building scalable TCP servers in Erlang
-
Condor
Condor is a minimal library for building scalable TCP servers in Erlang.
** Quick Overview
#+BEGIN_SRC erlang -module(ping_server). -behaviour(condor_listener).
%% condor_listener callbacks -export([init/1]). -export([handle_packet/2]). -export([handle_info/2]). -export([terminate/2]).
init([]) -> {ok, undefined}.
handle_packet(<<"stop">>, State) -> {send_and_stop, <<"ok">>, normal, State}; handle_packet(<<"ping">>, State) -> {send, <<"pong">>, State}.
handle_info(_Msg, State) -> {ok, State}.
terminate(_Reason, _State) -> ok. #+END_SRC
** Features
- Reusable supervised connection acceptors
- Neat packet frames and buffers
** API
*** Start a Listener
#+BEGIN_SRC
condor:start_listener(Name, Opts, Module, InitialState) ->
{ok, Pid} | {error, Reason}
Name = atom()
Opts = #{
ip => inet:ip_address(),
port => inet:port_number(),
max_acceptors => non_neg_integer(),
len => 1 | 2,
timeout => non_neg_integer()
}
Module = atom() InitialState = any() Pid = pid() Reason = any() #+END_SRC
~Opts~:
- ~ip~: to what IP Condor should bind.
- ~port~: on what port Condor should listen.
- ~max_acceptors~: maximum number of socket acceptors, or in other words, maximum number of concurrent connections.
- ~len~: length of the indicator of a packet's size.
- ~timeout~: the time limit, in milliseconds, for a packet to be buffered.
Default ~Opts~:
#+BEGIN_SRC #{ ip => {127, 0, 0, 1}, len => 2, timeout => 10000, max_acceptors => 100 } #+END_SRC
*** Stop a Listener
#+BEGIN_SRC
condor:stop_listener(Name) -> ok
Name = atom()
#+END_SRC
*** Condor Listener Callbacks
Behaviour: ~condor_listener~
#+BEGIN_SRC
init(State) -> Result
handle_packet(Packet, State) -> Result
handle_info(Msg, State) -> Result
terminate(Reason, State) -> ok
Result = {ok, State}
| {send, Packet, State}
| {stop, Reason, State}
| {send_and_stop, Packet, Reason, State}
Packet = binary()
State = any()
Reason = atom()
#+END_SRC
Events that invoke callbacks:
#+BEGIN_SRC
event callback module
----- ---------------
new connection ---> Module:init/1
new packet ---> Module:handle_packet/2
receiving a message ---> Module:handle_info/2
packet timeout ---> Module:handle_info/2
connection termination ---> Module:terminate/2
#+END_SRC
Condor takes care of framing packets. Each packet frame consists of two
segments: ~Len | Packet~.
~Len~ indicates the length of ~Packet~ in big-endian order.
The length of ~Len~ is two bytes by default, though it can be modified with
the ~len~ option.
Condor also takes care of buffering. So, ~Module:handle_packet/2~ is called
only when an entire packet is received. That is, when ~Packet~ is buffered
according to the value of ~Len~. ~Len~ will then be stripped off, and only
~Packet~ will be passed to ~Module:handle_packet/2~. However, if ~Packet~ is
not received completely in ~Timeout~ milliseconds (which would be specified
in ~Opts~), ~Module:handle_info/2~ will be invoked with ~Msg~ being
~{timeout, Buffer :: binary()}~.
A callback's ~Result~:
- ~{send, Packet, State}~ sends ~Packet~ (in the frame: ~Len | Packet~).
- ~{stop, Reason, State}~ terminates the connection.
- ~{send_and_stop, Packet, Reason, State}~ sends ~Packet~ (in the frame:
~Len | Packet~), and then terminates the connection.
** License
Apache License, Version 2.0