Mountain/Vine/Server/
Initialize.rs

1//! # Initialize (Vine Server)
2//!
3//! Contains the logic to initialize and start the Mountain gRPC server.
4//!
5//! This module provides the entry point for starting Vine's gRPC servers:
6//! - **MountainServiceServer**: Listens for connections from Cocoon sidecar
7//! - **CocoonServiceServer**: Listens for connections from Mountain
8//!   (bidirectional)
9//!
10//! ## Initialization Process
11//!
12//! 1. Validates socket addresses
13//! 2. Retrieves ApplicationRunTime from Tauri state
14//! 3. Creates service implementations with runtime dependencies
15//! 4. Spawns server tasks as background tokio tasks
16//! 5. Servers begin listening on specified ports
17//!
18//! ## Server Configuration
19//!
20//! - **Mountaln Service**: Typically on port 50051 (configurable)
21//! - **Cocoon Service**: Typically on port 50052 (configurable)
22//! - Both servers support compression and message size limits
23//!
24//! ## Error Handling
25//!
26//! Initialization failures are logged and returned to the caller.
27//! Once started, servers run independently and log their own errors.
28//!
29//! ## Lifecycle
30//!
31//! Servers run as detached tokio tasks. They will:
32//! - Start immediately when spawned
33//! - Continue until process termination or tokio runtime shutdown
34//! - Log errors to the logging system
35//! - Not automatically restart on failure (caller should implement retry logic
36//!   if needed)
37
38use std::{net::SocketAddr, sync::Arc, time::Duration};
39
40use log::{debug, error, info, warn};
41use tauri::{AppHandle, Manager};
42use tonic::transport::Server;
43
44use super::MountainVinegRPCService::MountainVinegRPCService;
45use crate::{
46	RPC::CocoonService::CocoonServiceImpl,
47	RunTime::ApplicationRunTime::ApplicationRunTime,
48	Vine::{
49		Error::VineError,
50		Generated::{cocoon_service_server::CocoonServiceServer, mountain_service_server::MountainServiceServer},
51	},
52};
53
54/// Server configuration constants
55mod ServerConfig {
56	use std::time::Duration;
57
58	/// Default port for MountainService server
59	pub const DEFAULT_MOUNTAIN_PORT:u16 = 50051;
60
61	/// Default port for CocoonService server
62	pub const DEFAULT_COCOON_PORT:u16 = 50052;
63
64	/// Maximum concurrent connections per server
65	pub const MAX_CONNECTIONS:usize = 100;
66
67	/// Connection timeout duration
68	pub const CONNECTION_TIMEOUT:Duration = Duration::from_secs(30);
69
70	/// Default message size limit (4MB)
71	pub const MAX_MESSAGE_SIZE:usize = 4 * 1024 * 1024;
72}
73
74/// Validates a socket address string before parsing.
75///
76/// # Parameters
77/// - `AddressString`: The address string to validate
78/// - `ServerName`: Name of the server for error messages
79///
80/// # Returns
81/// - `Ok(SocketAddr)`: Validated and parsed socket address
82/// - `Err(VineError)`: Invalid address format
83fn ValidateSocketAddress(AddressString:&str, ServerName:&str) -> Result<SocketAddr, VineError> {
84	if AddressString.is_empty() {
85		return Err(VineError::InvalidMessageFormat(format!(
86			"{} address cannot be empty",
87			ServerName
88		)));
89	}
90
91	if AddressString.len() > 256 {
92		return Err(VineError::InvalidMessageFormat(format!(
93			"{} address exceeds maximum length (256 characters)",
94			ServerName
95		)));
96	}
97
98	match AddressString.parse::<SocketAddr>() {
99		Ok(addr) => {
100			// Validate port is within valid range
101			if addr.port() < 1024 {
102				warn!(
103					"[VineServer] {} using privileged port {}, this may require elevated privileges",
104					ServerName,
105					addr.port()
106				);
107			}
108
109			Ok(addr)
110		},
111		Err(e) => Err(VineError::AddressParseError(e)),
112	}
113}
114
115/// Initializes and starts the gRPC servers on background tasks.
116///
117/// This function retrieves the core `ApplicationRunTime` from Tauri's managed
118/// state, instantiates the gRPC service implementations
119/// (`MountainVinegRPCService` and `CocoonServiceServer`), and uses `tonic` to
120/// serve them at the specified addresses.
121///
122/// # Parameters
123/// - `ApplicationHandle`: The Tauri application handle
124/// - `MountainAddressString`: The address and port to bind the Mountain server
125///   to (e.g., `"[::1]:50051"`)
126/// - `CocoonAddressString`: The address and port to bind the Cocoon server to
127///   (e.g., `"[::1]:50052"`)
128///
129/// # Returns
130/// - `Ok(())`: Successfully initialized and started both servers
131/// - `Err(VineError)`: Initialization failed (invalid address, missing runtime,
132///   etc.)
133///
134/// # Errors
135///
136/// This function will return an error if:
137/// - Either socket address string is invalid or unparseable
138/// - ApplicationRunTime is not available in Tauri state
139/// - Server task spawning fails (rare)
140///
141/// # Example
142///
143/// ```rust,no_run
144/// # use Vine::Server::Initialize::Initialize;
145/// # use tauri::AppHandle;
146/// # async fn example(handle: AppHandle) -> Result<(), Box<dyn std::error::Error>> {
147/// Initialize(handle, "[::1]:50051".to_string(), "[::1]:50052".to_string())?;
148/// # Ok(())
149/// # }
150/// ```
151///
152/// # Notes
153///
154/// - Servers run as detached tokio tasks
155/// - Initialization is async-safe but function is synchronous
156/// - Servers log errors independently after startup
157/// - Use `Default` addresses for development (localhost with default ports)
158pub fn Initialize(
159	ApplicationHandle:AppHandle,
160	MountainAddressString:String,
161	CocoonAddressString:String,
162) -> Result<(), VineError> {
163	info!("[VineServer] Initializing Vine gRPC servers...");
164
165	// Validate and parse socket addresses
166	let MountainAddress = ValidateSocketAddress(&MountainAddressString, "MountainService")?;
167	let CocoonAddress = ValidateSocketAddress(&CocoonAddressString, "CocoonService")?;
168
169	info!("[VineServer] MountainService will bind to: {}", MountainAddress);
170	info!("[VineServer] CocoonService will bind to: {}", CocoonAddress);
171
172	// Retrieve ApplicationRunTime from Tauri managed state
173	let RunTime = ApplicationHandle
174		.try_state::<Arc<ApplicationRunTime>>()
175		.ok_or_else(|| {
176			let msg = "[VineServer] CRITICAL: ApplicationRunTime not found in Tauri state. Server cannot start.";
177
178			error!("{}", msg);
179
180			VineError::InternalLockError(msg.to_string())
181		})?
182		.inner()
183		.clone();
184
185	debug!("[VineServer] ApplicationRunTime retrieved successfully");
186
187	// Create MountainService implementation (handles calls from Cocoon to Mountain)
188	let MountainService = MountainVinegRPCService::Create(ApplicationHandle.clone(), RunTime.clone());
189
190	// Create CocoonService implementation (handles calls from Mountain to Cocoon)
191	let cocoon_service_impl = CocoonServiceImpl::new(RunTime.Environment.clone());
192
193	debug!("[VineServer] Service implementations created");
194
195	// Spawn Mountain server to run in the background
196	let MountainServerName = MountainAddress.to_string();
197	tokio::spawn(async move {
198		info!("[VineServer] Starting MountainService gRPC server on {}", MountainServerName);
199
200		let ServerResult = Server::builder()
201			.add_service(
202				MountainServiceServer::new(MountainService)
203					.max_decoding_message_size(ServerConfig::MAX_MESSAGE_SIZE)
204					.max_encoding_message_size(ServerConfig::MAX_MESSAGE_SIZE),
205			)
206			.serve(MountainAddress)
207			.await;
208
209		match ServerResult {
210			Ok(_) => {
211				info!("[VineServer] MountainService server shut down gracefully");
212			},
213			Err(e) => {
214				error!("[VineServer] MountainService gRPC server error: {}", e);
215			},
216		}
217	});
218
219	// Spawn Cocoon server to run in the background
220	let CocoonServerName = CocoonAddress.to_string();
221	tokio::spawn(async move {
222		info!("[VineServer] Starting CocoonService gRPC server on {}", CocoonServerName);
223
224		let ServerResult = Server::builder()
225			.add_service(
226				CocoonServiceServer::new(cocoon_service_impl)
227					.max_decoding_message_size(ServerConfig::MAX_MESSAGE_SIZE)
228					.max_encoding_message_size(ServerConfig::MAX_MESSAGE_SIZE),
229			)
230			.serve(CocoonAddress)
231			.await;
232
233		match ServerResult {
234			Ok(_) => {
235				info!("[VineServer] CocoonService server shut down gracefully");
236			},
237			Err(e) => {
238				error!("[VineServer] CocoonService gRPC server error: {}", e);
239			},
240		}
241	});
242
243	info!("[VineServer] Both gRPC servers initialized successfully and running in background");
244
245	Ok(())
246}