A library for building asynchronous RPC-style protocols.
The approach here is to have a separate representation of the server-side
implementation of an RPC (An Implementation.t
) and the interface that it exports
(either an Rpc.t
, a State_rpc.t
or a Pipe_rpc.t
, but we'll refer to them
generically as RPC interfaces). A server builds the Implementation.t
out of an RPC
interface and a function for implementing the RPC, while the client dispatches a
request using the same RPC interface.
The Implementation.t
hides the type of the query and the response, whereas the
Rpc.t
is polymorphic in the query and response type. This allows you to build a
Implementations.t
out of a list of Implementation.t
s.
Each RPC also comes with a version number. This is meant to allow support of multiple different versions of what is essentially the same RPC. You can think of it as an extension to the name of the RPC, and in fact, each RPC is uniquely identified by its (name, version) pair. RPCs with the same name but different versions should implement similar functionality.
A 'connection_state t
is something that knows how to respond to one query, given
a 'connection_state
. That is, you can create a 'connection_state t
by providing
a function which takes a query *and* a 'connection_state
and provides a response.
The reason for this is that rpcs often do something like look something up in a
master structure. This way, Implementation.t
's can be created without having the
master structure in your hands.
A 'connection_state Implementations.t
is something that knows how to respond to
many different queries. It is conceptually a package of 'connection_state
Implementation.t
's.
create ~implementations ~on_unknown_rpc
creates a server capable of responding to
the rpc's implemented in the implementation list. Be careful about setting
on_unknown_rpc
to `Raise
because other programs may mistakenly connect to this
one causing it to crash.
This has (..., 'error) Result.t
as its return type to represent the possibility of
the call itself being somehow erroneous (but understood - the outer Or_error.t
encompasses failures of that nature). Note that this cannot be done simply by
making 'response
a result type, since ('response Pipe.Reader.t, 'error) Result.t
is distinct from ('response, 'error) Result.t Pipe.Reader.t
.
Closing the pipe has the effect of calling abort
.
abort rpc connection id
given an RPC and the id returned as part of a call to
dispatch, abort requests that the other side of the connection stop sending
updates.
A state rpc is an easy way for two processes to synchronize a data structure by sending updates over the wire. It's basically a pipe rpc that sends/receives an initial state of the data structure, and then updates, and applies the updates under the covers.