Skip to main content

DevelopmentNodeEnvironment_MicrosoftVSCodeDependency_22NodeVersion_Bundle_Clean_Debug_ElectronProfile_EsbuildCompiler_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};
39
40use tauri::{AppHandle, Manager};
41use tonic::transport::Server;
42
43use super::MountainVinegRPCService::MountainVinegRPCService;
44use crate::{
45	RPC::CocoonService::CocoonServiceImpl,
46	RunTime::ApplicationRunTime::ApplicationRunTime,
47	Vine::{
48		Error::VineError,
49		Generated::{cocoon_service_server::CocoonServiceServer, mountain_service_server::MountainServiceServer},
50	},
51	dev_log,
52};
53
54/// Server configuration constants
55mod ServerConfig {
56
57	use std::time::Duration;
58
59	/// Default port for MountainService server
60	pub const DEFAULT_MOUNTAIN_PORT:u16 = 50051;
61
62	/// Default port for CocoonService server
63	pub const DEFAULT_COCOON_PORT:u16 = 50052;
64
65	/// Maximum concurrent connections per server
66	pub const MAX_CONNECTIONS:usize = 100;
67
68	/// Connection timeout duration
69	pub const CONNECTION_TIMEOUT:Duration = Duration::from_secs(30);
70
71	/// Default message size limit (4MB)
72	pub const MAX_MESSAGE_SIZE:usize = 4 * 1024 * 1024;
73}
74
75/// Validates a socket address string before parsing.
76///
77/// # Parameters
78/// - `AddressString`: The address string to validate
79/// - `ServerName`: Name of the server for error messages
80///
81/// # Returns
82/// - `Ok(SocketAddr)`: Validated and parsed socket address
83/// - `Err(VineError)`: Invalid address format
84fn ValidateSocketAddress(AddressString:&str, ServerName:&str) -> Result<SocketAddr, VineError> {
85	if AddressString.is_empty() {
86		return Err(VineError::InvalidMessageFormat(format!(
87			"{} address cannot be empty",
88			ServerName
89		)));
90	}
91
92	if AddressString.len() > 256 {
93		return Err(VineError::InvalidMessageFormat(format!(
94			"{} address exceeds maximum length (256 characters)",
95			ServerName
96		)));
97	}
98
99	match AddressString.parse::<SocketAddr>() {
100		Ok(addr) => {
101			// Validate port is within valid range
102			if addr.port() < 1024 {
103				dev_log!(
104					"grpc",
105					"warn: [VineServer] {} using privileged port {}, this may require elevated privileges",
106					ServerName,
107					addr.port()
108				);
109			}
110
111			Ok(addr)
112		},
113
114		Err(e) => Err(VineError::AddressParseError(e)),
115	}
116}
117
118/// Initializes and starts the gRPC servers on background tasks.
119///
120/// This function retrieves the core `ApplicationRunTime` from Tauri's managed
121/// state, instantiates the gRPC service implementations
122/// (`MountainVinegRPCService` and `CocoonServiceServer`), and uses `tonic` to
123/// serve them at the specified addresses.
124///
125/// # Parameters
126/// - `ApplicationHandle`: The Tauri application handle
127/// - `MountainAddressString`: The address and port to bind the Mountain server
128///   to (e.g., `"[::1]:50051"`)
129/// - `CocoonAddressString`: The address and port to bind the Cocoon server to
130///   (e.g., `"[::1]:50052"`)
131///
132/// # Returns
133/// - `Ok(())`: Successfully initialized and started both servers
134/// - `Err(VineError)`: Initialization failed (invalid address, missing runtime,
135///   etc.)
136///
137/// # Errors
138///
139/// This function will return an error if:
140/// - Either socket address string is invalid or unparseable
141/// - ApplicationRunTime is not available in Tauri state
142/// - Server task spawning fails (rare)
143///
144/// # Example
145///
146/// ```rust,no_run
147/// # use Vine::Server::Initialize::Initialize;
148/// # use tauri::AppHandle;
149/// # async fn example(handle: AppHandle) -> Result<(), Box<dyn std::error::Error>> {
150/// Initialize(handle, "[::1]:50051".to_string(), "[::1]:50052".to_string())?;
151/// # Ok(())
152/// # }
153/// ```
154///
155/// # Notes
156///
157/// - Servers run as detached tokio tasks
158/// - Initialization is async-safe but function is synchronous
159/// - Servers log errors independently after startup
160/// - Use `Default` addresses for development (localhost with default ports)
161pub fn Initialize(
162	ApplicationHandle:AppHandle,
163
164	MountainAddressString:String,
165
166	CocoonAddressString:String,
167) -> Result<(), VineError> {
168	dev_log!("grpc", "[VineServer] Initializing Vine gRPC servers...");
169
170	crate::dev_log!("grpc", "initializing Vine gRPC servers");
171
172	// Validate and parse socket addresses
173	let MountainAddress = ValidateSocketAddress(&MountainAddressString, "MountainService")?;
174
175	let CocoonAddress = ValidateSocketAddress(&CocoonAddressString, "CocoonService")?;
176
177	dev_log!("grpc", "[VineServer] MountainService will bind to: {}", MountainAddress);
178
179	dev_log!(
180		"grpc",
181		"[VineServer] Cocoon expected on: {} (started by Cocoon process)",
182		CocoonAddress
183	);
184
185	crate::dev_log!("grpc", "Mountain={} Cocoon(remote)={}", MountainAddress, CocoonAddress);
186
187	// Retrieve ApplicationRunTime from Tauri managed state
188	let RunTime = ApplicationHandle
189		.try_state::<Arc<ApplicationRunTime>>()
190		.ok_or_else(|| {
191			let msg = "[VineServer] CRITICAL: ApplicationRunTime not found in Tauri state. Server cannot start.";
192
193			dev_log!("grpc", "error: {}", msg);
194
195			VineError::InternalLockError(msg.to_string())
196		})?
197		.inner()
198		.clone();
199
200	dev_log!("grpc", "[VineServer] ApplicationRunTime retrieved successfully");
201
202	// Create MountainService implementation (handles calls from Cocoon to Mountain)
203	let MountainService = MountainVinegRPCService::Create(ApplicationHandle.clone(), RunTime.clone());
204
205	// Create CocoonService implementation (handles calls from Mountain to Cocoon)
206	let cocoon_service_impl = CocoonServiceImpl::new(RunTime.Environment.clone());
207
208	dev_log!("grpc", "[VineServer] Service implementations created");
209
210	// Spawn Mountain server to run in the background
211	let MountainServerName = MountainAddress.to_string();
212
213	tokio::spawn(async move {
214		dev_log!(
215			"grpc",
216			"[VineServer] Starting MountainService gRPC server on {}",
217			MountainServerName
218		);
219
220		let ServerResult = Server::builder()
221			.add_service(
222				MountainServiceServer::new(MountainService)
223					.max_decoding_message_size(ServerConfig::MAX_MESSAGE_SIZE)
224					.max_encoding_message_size(ServerConfig::MAX_MESSAGE_SIZE),
225			)
226			.serve(MountainAddress)
227			.await;
228
229		match ServerResult {
230			Ok(_) => {
231				dev_log!("grpc", "[VineServer] MountainService server shut down gracefully");
232			},
233			Err(e) => {
234				dev_log!("grpc", "error: [VineServer] MountainService gRPC server error: {}", e);
235			},
236		}
237	});
238
239	// NOTE: CocoonService gRPC server is NOT started by Mountain.
240	// Port 50052 is reserved for Cocoon's own gRPC server (started by
241	// Cocoon's Effect-TS bootstrap, Stage 5). Mountain connects to Cocoon
242	// as a CLIENT on 50052 via Vine::Client::ConnectToSideCar.
243	// Starting CocoonServiceServer here would cause EADDRINUSE when Cocoon
244	// tries to bind the same port.
245	let _ = cocoon_service_impl; // suppress unused variable warning
246
247	dev_log!(
248		"grpc",
249		"[VineServer] MountainService gRPC server initialized on {}",
250		MountainAddress
251	);
252
253	Ok(())
254}