erps v0.3.1 Erps.Server behaviour View Source
Create an Erps server GenServer.
An Erps server is just a GenServer that has its call/2
and cast/2
callbacks
connected to the external network over a transport portocol.
Basic Operation
Presuming you have set up TLS credentials, you can instantiate a server in basically the same way that you would instantiate a GenServer:
defmodule ErpsServer do
use Erps.Server
@port <...>
def start_link, do: Erps.Server.start_link(__MODULE__, :ok,
port: @port,
tls_opts: [...])
@impl true
def init(init_state), do: {:ok, init_state}
def handle_call(:some_remote_call, state) do
{:reply, :some_remote_response, state}
end
end
Now you may either access these values as a normal, local
GenServer, or access them via Erps.Client
(see documentation)
for the implementation.
{:ok, server} = ErpsServer.start_link()
GenServer.call(server, :some_remote_call) #==> :some_remote_response
{:ok, client} = ErpsClient.start_link()
GenServer.call(client, :some_remote_call) #==> :some_remote_response
Module Options
:identifier
a binary identifier for your Erps API endpoint. Maximum 12 bytes, suggested to be human-readable.:versions
client semvers which are accepted. See the "requirements" section inVersion
.:safe
(see:erlang.binary_to_term/2
), for decoding terms. If set tofalse
, then allows undefined atoms and lambdas to be passed via the protocol. This should be used with extreme caution, as disabling safe mode can be an attack vector. (defaults totrue
):port
- sets the TCP/IP port that the server will listen to. If you don't set it or set it to0
it will pick a random port, which is useful for testing purposes.:transport
- set the transport module, which must implementErps.Transport.Api
behaviour. If you set it tofalse
, the Erps server will act similarly to aGenServer
(with some overhead).
Example
defmodule MyServer do
use Erps.Server, versions: "~> 0.2.4",
identifier: "my_api",
safe: false
def start_link(iv) do
Erps.Server.start_link(__MODULE__, init,
port: ,
tls_opts: [...])
end
def init(iv), do: {:ok, iv}
end
Magical features
The following functions are hoisted to your server module so that you can call them in your code with clarity and less boilerplate:
Link to this section Summary
Types
a from
term that is either a local from
, compatible with GenServer.from/0
or an opaque term that represents a connected remote client.
Functions
queries the server to retrieve a list of all clients that are connected to the server.
instruct the server to drop one of its connections.
queries the server to retrieve the TCP port that it's bound to to receive protocol messages.
pushes a message to all connected clients. Causes client Erps.Client.handle_push/2
callbacks to be triggered.
sends a reply to either a local process or a remotely connected client.
starts a server GenServer, not linked to the caller. Most useful for tests.
starts a server GenServer, linked to the caller.
Callbacks
used to filter messages from remote clients, allowing you to restrict your api.
similar to GenServer.handle_call/3
, but handles content from both
local and remote clients.
similar to GenServer.handle_cast/2
, but handles content from both local
and remote clients (if the content has been successfully filtered).
Invoked when an internal callback requests a continuation, using {:noreply, state, {:continue, continuation}}
, or from init/1
using
{:ok, state, {:continue, continuation}}
Invoked to handle general messages sent to the client process.
Invoked to set up the process.
Link to this section Types
from()
View Source
(opaque)
from()
from()
a from
term that is either a local from
, compatible with GenServer.from/0
or an opaque term that represents a connected remote client.
server()
View Source
server() :: GenServer.server()
server() :: GenServer.server()
Link to this section Functions
connections(srv)
View Source
connections(server()) :: [Erps.socket()]
connections(server()) :: [Erps.socket()]
queries the server to retrieve a list of all clients that are connected to the server.
disconnect(srv, socket)
View Source
disconnect(server(), Erps.socket()) :: :ok | {:error, :enoent}
disconnect(server(), Erps.socket()) :: :ok | {:error, :enoent}
instruct the server to drop one of its connections.
returns {:error, :enoent}
if the connection is not in its list of active
connections.
port(srv)
View Source
port(server()) :: {:ok, :inet.port_number()} | {:error, any()}
port(server()) :: {:ok, :inet.port_number()} | {:error, any()}
queries the server to retrieve the TCP port that it's bound to to receive protocol messages.
Useful if you have initiated your server with port: 0
, especially in tests.
push(srv, push) View Source
pushes a message to all connected clients. Causes client Erps.Client.handle_push/2
callbacks to be triggered.
reply(via \\ self(), from, reply)
View Source
reply(via :: GenServer.server(), from(), term()) :: :ok
reply(via :: GenServer.server(), from(), term()) :: :ok
sends a reply to either a local process or a remotely connected client.
The Erps Server holds connection information, so you must supply the Erps
Server pid; though you may use the arity-2 form if you call from within
the action loop of the Erps Server itself, in which case it acts like
GenServer.reply/2
naturally takes the from
value passed in to the second parameter of
handle_call/3
.
start(module, param, opts \\ [])
View Source
start(module(), term(), keyword()) :: GenServer.on_start()
start(module(), term(), keyword()) :: GenServer.on_start()
starts a server GenServer, not linked to the caller. Most useful for tests.
see start_link/3
for a description of avaliable options.
start_link(module, param, opts \\ [])
View Source
start_link(module(), term(), keyword()) :: GenServer.on_start()
start_link(module(), term(), keyword()) :: GenServer.on_start()
starts a server GenServer, linked to the caller.
options
:port
tcp port that the server should listen to. Use0
to pick an unused port andport/1
to retrieve that port number (useful for testing). You may also set it tofalse
if you want the server to act as a normal GenServer (this is useful if you need a configuration-dependent behaviour):transport
transport module (seeErps.Transport.Api
):tls_opts
options for TLS authorization and encryption. Should include::cacertfile
path to the certificate of your signing authority.:certfile
path to the server certificate file.:keyfile
path to the signing key.
see GenServer.start_link/3
for a description of further options.
Link to this section Callbacks
filter(mode, payload) View Source (optional)
used to filter messages from remote clients, allowing you to restrict your api.
The first term is either :call
or :cast
, indicating which type of api protocol
the filter applies to, followed by the term to be checked for filtering. A true
response means allow, and a false
response means drop.
Defaults to fn _, _ -> true end
(which is permissive).
handle_call(request, from, state)
View Source
(optional)
handle_call(request :: term(), from(), state :: term()) ::
{:reply, reply, new_state}
| {:reply, reply, new_state, timeout() | :hibernate | {:continue, term()}}
| {:noreply, new_state}
| {:noreply, new_state, timeout() | :hibernate | {:continue, term()}}
| {:stop, reason, reply, new_state}
| {:stop, reason, new_state}
when reply: term(), new_state: term(), reason: term()
handle_call(request :: term(), from(), state :: term()) :: {:reply, reply, new_state} | {:reply, reply, new_state, timeout() | :hibernate | {:continue, term()}} | {:noreply, new_state} | {:noreply, new_state, timeout() | :hibernate | {:continue, term()}} | {:stop, reason, reply, new_state} | {:stop, reason, new_state} when reply: term(), new_state: term(), reason: term()
similar to GenServer.handle_call/3
, but handles content from both
local and remote clients.
The from
term might contain a opaque term which represents a return
address for a remote client, but you may use this term as expected in
reply/2
.
Return codes
{:reply, reply, new_state}
replies, then updates the state of the Server.{:reply, reply, new_state, timeout}
replies, then causes a :timeout message to be sent tohandle_info/2
if no other message comes by{:reply, reply, new_state, :hibernate}
replies, then causes a hibernation event (see:erlang.hibernate/3
){:reply, reply, new_state, {:continue, term}}
replies, then causes a continuation to be triggered after the message is handled, it will be sent toc:handle_continue/3
- and all return codes supported by
GenServer.handle_cast/2
handle_cast(request, state) View Source (optional)
similar to GenServer.handle_cast/2
, but handles content from both local
and remote clients (if the content has been successfully filtered).
Return codes
{:noreply, new_state}
continues the loop with new statenew_state
{:noreply, new_state, timeout}
causes a :timeout message to be sent tohandle_info/2
if no other message comes by{:noreply, new_state, :hibernate}
, causes a hibernation event (see:erlang.hibernate/3
){:noreply, new_state, {:continue, term}}
causes a continuation to be triggered after the message is handled, it will be sent toc:handle_continue/3
{:stop, reason, new_state}
terminates the loop, passingnew_state
toterminate/2
, if it's implemented.
handle_continue(continue, state) View Source (optional)
Invoked when an internal callback requests a continuation, using {:noreply, state, {:continue, continuation}}
, or from init/1
using
{:ok, state, {:continue, continuation}}
see: GenServer.handle_continue/2
.
Return codes
see return codes for handle_cast/2
handle_info(msg, state) View Source (optional)
Invoked to handle general messages sent to the client process.
Most useful if the client needs to be attentive to system messages, such as nodedown or monitored processes, but also useful for internal timeouts.
see: GenServer.handle_info/2
.
Return codes
see return codes for handle_cast/2
init(init_arg) View Source
Invoked to set up the process.
Like GenServer.init/1
, this function is called from inside
the process immediately after start_link/3
or start/3
.
Return codes
{:ok, state}
a succesful startup of your intialization logic and sets the internal state of your server tostate
.{:ok, state, timeout}
the above, plus a :timeout atom will be sent tohandle_info/2
if no other messages come by.{:ok, state, :hibernate}
successful startup, followed by a hibernation event (see:erlang.hibernate/3
){:ok, state, {:continue, term}}
successful startup, and causes a continuation to be triggered after the message is handled, sent toc:handle_continue/3
:ignore
- Drop the gen_server creation request, because for some reason it shouldn't have started.{:stop, reason}
- a failure in creating the gen_server. Results in{:error, reason}
being propagated as the result of the start_link
terminate(reason, state) View Source (optional)
see: GenServer.terminate/2
.