Skip to main content

protosocket_rpc/server/
server_traits.rs

1use protosocket::{Codec, Decoder, Encoder, SocketListener};
2
3use crate::{server::rpc_responder::RpcResponder, Message};
4
5/// SocketService receives connections and produces ConnectionServices.
6///
7/// The SocketService is notified when a new connection is established. It is given the address of the
8/// remote peer and it returns a ConnectionService for that connection. You can think of this as the
9/// "connection factory" for your server. It is the "top" of your service stack.
10pub trait SocketService: 'static {
11    /// Message encoding scheme
12    ///
13    /// Consider pooling your allocations, like with `protosocket::PooledEncoder`.
14    /// The write out to the network uses the raw `Encoder::Serialized` type, so you
15    /// can make outbound messages low-allocation via simple pooling.
16    type Codec: Codec + Decoder<Message: Message> + Encoder<Message: Message>;
17
18    /// The type of connection service that will be created for each connection.
19    type ConnectionService: ConnectionService<
20        Request = <Self::Codec as Decoder>::Message,
21        Response = <Self::Codec as Encoder>::Message,
22    >;
23
24    /// The listener type for this service. E.g., `TcpSocketListener`
25    type SocketListener: SocketListener;
26
27    /// Create a new message codec for a connection.
28    fn codec(&self) -> Self::Codec;
29
30    /// Create a new ConnectionService for your new connection.
31    /// The Stream will be wired into a `protosocket::Connection`. You can look at it in here
32    /// if it has data you want (like a SocketAddr).
33    fn new_stream_service(
34        &self,
35        _stream: &<Self::SocketListener as SocketListener>::Stream,
36    ) -> Self::ConnectionService;
37}
38
39/// A connection service receives rpcs from clients and sends responses.
40///
41/// Each client connection gets a ConnectionService. You put your per-connection state in your
42/// ConnectionService implementation.
43///
44/// Every interaction with a client is done via an RPC. You are called with the initiating message
45/// from the client, and you return the kind of response future that is used to complete the RPC.
46///
47/// A ConnectionService is executed in the context of an RPC connection server, which is a future.
48/// This means you get `&mut self` when you are called with a new rpc. You can use simple mutable
49/// state per-connection; but if you need to share state between connections or elsewhere in your
50/// application, you will need to use an appropriate state sharing mechanism.
51pub trait ConnectionService: Unpin + 'static {
52    /// The type of request message, These messages initiate rpcs.
53    type Request: Message;
54    /// The type of response message, These messages complete rpcs, or are streamed from them.
55    type Response: Message;
56
57    /// Create a new rpc task completion.
58    ///
59    /// You send the response via the RpcResponder.
60    fn new_rpc(
61        &mut self,
62        initiating_message: Self::Request,
63        responder: RpcResponder<'_, Self::Response>,
64    );
65
66    /// Optional poll to allow the connection to push work forward internally.
67    ///
68    /// You can use this to drive connection state machines (e.g., `FuturesUnordered`),
69    /// or whatever else you need to do with your connection between reading from the network and
70    /// writing to it.
71    fn poll(
72        self: std::pin::Pin<&mut Self>,
73        _context: &mut std::task::Context<'_>,
74    ) -> std::ops::ControlFlow<()> {
75        std::ops::ControlFlow::Continue(())
76    }
77}