Development Documentation (main branch) - For stable release docs, see docs.rs/eidetica

eidetica/sync/transports/
shared.rs

1//! Shared utilities for transport implementations.
2//!
3//! This module provides common functionality used across different transport
4//! implementations to reduce code duplication and ensure consistency.
5
6use tokio::sync::oneshot;
7
8use crate::sync::{
9    error::SyncError,
10    protocol::{SyncRequest, SyncResponse},
11};
12
13/// Manages server state common to all transport implementations.
14/// Since transports are owned exclusively by Sync instances and all operations
15/// require &mut self, no internal locking is needed - the Rust ownership system
16/// provides the necessary synchronization guarantees.
17pub struct ServerState {
18    /// Whether the server is running.
19    running: bool,
20    /// Shutdown signal for the server loop.
21    shutdown: Option<oneshot::Sender<()>>,
22    /// The server's address.
23    address: Option<String>,
24}
25
26impl Default for ServerState {
27    fn default() -> Self {
28        Self::new()
29    }
30}
31
32impl ServerState {
33    /// Create a new server state manager.
34    pub fn new() -> Self {
35        Self {
36            running: false,
37            shutdown: None,
38            address: None,
39        }
40    }
41
42    /// Check if the server is currently running.
43    pub fn is_running(&self) -> bool {
44        self.running
45    }
46
47    /// Get the server address if available.
48    pub fn get_address(&self) -> Result<String, SyncError> {
49        if let Some(addr) = &self.address {
50            Ok(addr.clone())
51        } else {
52            Err(SyncError::ServerNotRunning)
53        }
54    }
55
56    /// Start the server by setting it as running with the given address and shutdown sender.
57    /// This combines the commonly used pair: set_running + set_shutdown_sender.
58    pub fn server_started(&mut self, address: String, shutdown_sender: oneshot::Sender<()>) {
59        self.running = true;
60        self.address = Some(address);
61        self.shutdown = Some(shutdown_sender);
62    }
63
64    /// Stop the server by triggering shutdown and clearing state.
65    /// This combines the commonly used pair: trigger_shutdown + set_stopped.
66    pub fn stop_server(&mut self) {
67        // First trigger shutdown if we have a sender
68        if let Some(tx) = self.shutdown.take() {
69            let _ = tx.send(());
70        }
71        // Then mark as stopped and clear address
72        self.running = false;
73        self.address = None;
74    }
75}
76
77/// Utilities for handling JSON serialization/deserialization in transports.
78pub struct JsonHandler;
79
80impl JsonHandler {
81    /// Serialize a SyncRequest to JSON bytes.
82    pub fn serialize_request(request: &SyncRequest) -> Result<Vec<u8>, SyncError> {
83        serde_json::to_vec(request)
84            .map_err(|e| SyncError::Network(format!("Failed to serialize request: {e}")))
85    }
86
87    /// Serialize a SyncResponse to JSON bytes.
88    pub fn serialize_response(response: &SyncResponse) -> Result<Vec<u8>, SyncError> {
89        serde_json::to_vec(response)
90            .map_err(|e| SyncError::Network(format!("Failed to serialize response: {e}")))
91    }
92
93    /// Deserialize JSON bytes to a SyncRequest.
94    pub fn deserialize_request(bytes: &[u8]) -> Result<SyncRequest, SyncError> {
95        serde_json::from_slice(bytes)
96            .map_err(|e| SyncError::Network(format!("Failed to deserialize request: {e}")))
97    }
98
99    /// Deserialize JSON bytes to a SyncResponse.
100    pub fn deserialize_response(bytes: &[u8]) -> Result<SyncResponse, SyncError> {
101        serde_json::from_slice(bytes)
102            .map_err(|e| SyncError::Network(format!("Failed to deserialize response: {e}")))
103    }
104}
105
106/// Waits for server ready signal and maps errors appropriately.
107pub async fn wait_for_ready(
108    ready_rx: oneshot::Receiver<()>,
109    address: &str,
110) -> Result<(), SyncError> {
111    ready_rx.await.map_err(|_| SyncError::ServerBind {
112        address: address.to_string(),
113        reason: "Server startup failed".to_string(),
114    })
115}