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}