multi_rpc/
builder.rs

1use std::future::Future;
2use std::pin::Pin;
3use std::sync::Arc;
4
5use crate::runner::ServerRunner;
6
7/// A type alias for a future that can be spawned as a server task.
8pub type ServerTask = Pin<Box<dyn Future<Output = ()> + Send>>;
9
10/// A builder for configuring and launching multiple RPC servers from a single service implementation.
11///
12/// This provides a fluent interface to add different protocol servers that all delegate
13/// to the same shared service logic.
14pub struct ServerBuilder<S> {
15    service: Arc<S>,
16    task_factories: Vec<Box<dyn FnOnce(Arc<S>) -> ServerTask + Send>>,
17}
18
19impl<S> ServerBuilder<S>
20where
21    S: Send + Sync + 'static,
22{
23    /// Creates a new `ServerBuilder`.
24    ///
25    /// # Arguments
26    ///
27    /// * `service` - The service implementation that will be shared across all protocols.
28    pub fn new(service: S) -> Self {
29        Self {
30            service: Arc::new(service),
31            task_factories: Vec::new(),
32        }
33    }
34
35    /// Adds a protocol server to the builder.
36    ///
37    /// The `#[multi_rpc_impl]` macro generates protocol-specific factory functions
38    /// (e.g., `greeter_impls::tarpc_tcp(...)`) that can be passed to this method.
39    ///
40    /// # Arguments
41    ///
42    /// * `factory` - A function that takes the shared service instance and returns a future
43    ///   representing the running server task.
44    pub fn add_protocol<F>(mut self, factory: F) -> Self
45    where
46        F: FnOnce(Arc<S>) -> ServerTask + Send + 'static,
47    {
48        self.task_factories.push(Box::new(factory));
49        self
50    }
51
52    /// Consumes the builder, spawning all configured protocol servers on the Tokio runtime.
53    ///
54    /// Returns a `ServerRunner` which can be used to keep the application alive
55    /// until a shutdown signal is received.
56    pub fn build(self) -> Result<ServerRunner, std::io::Error> {
57        println!("🚀 Launching servers...");
58        let handles = self
59            .task_factories
60            .into_iter()
61            .map(|task_fn| {
62                let task = task_fn(self.service.clone());
63                tokio::spawn(task)
64            })
65            .collect();
66        Ok(ServerRunner { handles })
67    }
68}