ServiceMap
A service map is a type that knows how to deliver messages to individual actors. It dispatches if you will. You can tell Peer
to expose a set of services remotely by bundling them in a ServiceMap
and registering that map.
This makes it possible to expose different sets of services on different connections. For the moment it is not possible to dynamically change what services are exposed at runtime. The problem here is that we consider the service map a contract between two processes, so if all of a sudden we would stop providing certain services, the remote process might run into errors. This might change in the future, with some thought of how we inform a remote process of what services are available at any given time. One purpose might be to deal with authentication, enabling certain services only once a user has authenticated. However for now you have to deal with authentication yourself by adding a token in your messages. The receiving actor doesn't actually know which connection a message comes from.
There are three implementations of ServiceMap
provided by thespis_remote:
service_map!
, a macroRelayMap
, used for relaying messages to a different process.PubSub
, for relays to implement a publish/subscribe architecture.
service_map!
This is a macro because as it needs to deserialize your actor messages, it needs to know it's types, but that can only be provided inside your crate, not in thespis_remote. Thus it gives you all that functionality that needs to be in your crate to make things convenient so you don't have to write that yourself. It's main use looks like:
The meaning of the parameters:
- namespace: this will be transformed into a module in your code. It is also used to uniquely identify services to avoid name collisions.
- wire_format: The wire format used for connections that expose this service map, in this case
CborWF
, the default implementation provided by thespis_remote. - services: The message types that will be served by this service map.
Usually you will put this macro as well as the message types mentioned in a separate crate that can be compiled into both processes that will communicate to eachother.
You can of course interact with such process also from binaries written in different languages as long as they correctly speak the wire format.
Usage of service_map!
looks like this on the side that exposes these services:
On the side that wants to use the service, you can obtain a RemoteAddr
that accepts all the message types declared in the service_map
macro. This cannot be statically verified by the compiler as the other side is generally another process. So you basically declare that you know that the process on the other end accepts messages of this type. Apart from this, everything is statically type checked in thespis.
RemoteAddr
works pretty much like thespis::Addr
, except for the error type which will be PeerErr
instead of ThesErr
because a lot more things can go wrong when dealing with messaging over a network connection and you probably want to know what went wrong when it does.
RelayMap
A RelayMap
has the same place in the workflow as Services
created by the service_map!
macro, but instead of delivering to a local actor it passes on the message to a Peer
that is connected to another process. This allows for transparent relaying to other backend services.
To create the RelayMap
, you give it a ServiceHandler
and a list of ServiceID
s that should be relayed. Then you register it as a service map with the Peer that is listening for the incoming requests just as Services
.
The ServiceHandler
is an enum that is either an address to a Peer
or a closure that will provide an address on a case by case basis. The latter option allows you to do load balancing or other runtime checks/logs before producing the address.
For a working code example, check the relay example for thespis_remote.
PubSub
- TODO