rsketch_server/lib.rs
1// Copyright 2025 Crrow
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15pub mod error;
16pub mod grpc;
17pub mod http;
18
19use futures::future::join_all;
20use rsketch_error::Result;
21use tokio::{sync::oneshot::Receiver, task::JoinHandle};
22use tokio_util::sync::CancellationToken;
23
24/// Handle for managing a running service: grpc or http.
25///
26/// This handle provides control over a running service, allowing you to:
27/// - Wait for the service to start accepting connections
28/// - Signal graceful shutdown
29/// - Wait for the service to fully stop
30/// - Check if the service task has completed
31///
32/// The handle uses a cancellation token for graceful shutdown and provides
33/// async methods for coordinating server lifecycle events.
34pub struct ServiceHandler {
35 /// Join handle for the server task
36 join_handle: JoinHandle<()>,
37 /// Token for signalling shutdown
38 cancellation_token: CancellationToken,
39 /// Receiver for server start notification
40 started_rx: Option<Receiver<()>>,
41 /// Join handles for readiness reporting tasks
42 reporter_handles: Vec<JoinHandle<()>>,
43}
44
45impl ServiceHandler {
46 /// Waits for the server to start accepting connections.
47 ///
48 /// This method blocks until the server has successfully bound to its
49 /// configured address and is ready to accept gRPC requests.
50 ///
51 /// # Panics
52 /// Panics if called more than once, as the start signal is consumed.
53 pub async fn wait_for_start(&mut self) -> Result<()> {
54 self.started_rx
55 .take()
56 .expect("Server start signal already consumed")
57 .await
58 .expect("Failed to receive server start signal");
59 Ok(())
60 }
61
62 /// Waits for the server to completely stop.
63 ///
64 /// This method consumes the handle and blocks until the server task
65 /// has finished executing. Use this after calling `shutdown()` to
66 /// ensure clean termination.
67 ///
68 /// # Panics
69 /// Panics if the server task panicked during execution.
70 pub async fn wait_for_stop(self) -> Result<()> {
71 let handles = self
72 .reporter_handles
73 .into_iter()
74 .chain(std::iter::once(self.join_handle));
75 join_all(handles).await;
76 Ok(())
77 }
78
79 /// Signals the server to begin graceful shutdown.
80 ///
81 /// This method triggers the shutdown process but does not wait for
82 /// completion. Use `wait_for_stop()` to wait for the server to fully stop.
83 pub fn shutdown(&self) { self.cancellation_token.cancel(); }
84
85 /// Checks if the server task has completed.
86 ///
87 /// Returns `true` if the server has finished running, either due to
88 /// shutdown or an error condition.
89 #[must_use]
90 pub fn is_finished(&self) -> bool { self.join_handle.is_finished() }
91}