1use std::{collections::HashMap, sync::Arc};
38
39use log::{debug, error, info, trace, warn};
40use serde_json::Value;
41use tauri::AppHandle;
42use tokio::sync::RwLock;
43use tonic::{Request, Response, Status};
44
45use crate::{
46 RunTime::ApplicationRunTime::ApplicationRunTime,
47 Track,
48 Vine::Generated::{
49 CancelOperationRequest,
50 Empty,
51 GenericNotification,
52 GenericRequest,
53 GenericResponse,
54 RpcError as RPCError,
55 mountain_service_server::MountainService,
56 },
57};
58
59mod ServiceConfig {
61 pub const MAX_CONCURRENT_OPERATIONS:usize = 50;
63
64 pub const CANCELLATION_TIMEOUT_MS:u64 = 5000;
66
67 pub const MAX_METHOD_NAME_LENGTH:usize = 128;
69}
70
71pub struct MountainVinegRPCService {
77 ApplicationHandle:AppHandle,
79
80 RunTime:Arc<ApplicationRunTime>,
82
83 ActiveOperations:Arc<RwLock<HashMap<u64, tokio_util::sync::CancellationToken>>>,
86}
87
88impl MountainVinegRPCService {
89 pub fn Create(ApplicationHandle:AppHandle, RunTime:Arc<ApplicationRunTime>) -> Self {
98 info!("[MountainVinegRPCService] New instance created");
99
100 Self {
101 ApplicationHandle,
102 RunTime,
103 ActiveOperations:Arc::new(RwLock::new(HashMap::new())),
104 }
105 }
106
107 pub async fn RegisterOperation(&self, request_id:u64) -> tokio_util::sync::CancellationToken {
115 let token = tokio_util::sync::CancellationToken::new();
116 self.ActiveOperations.write().await.insert(request_id, token.clone());
117 debug!("[MountainVinegRPCService] Registered operation {} for cancellation", request_id);
118 token
119 }
120
121 pub async fn UnregisterOperation(&self, request_id:u64) {
126 self.ActiveOperations.write().await.remove(&request_id);
127 debug!("[MountainVinegRPCService] Unregistered operation {}", request_id);
128 }
129
130 fn ValidateRequest(&self, request:&GenericRequest) -> Result<(), Status> {
139 if request.method.is_empty() {
141 return Err(Status::invalid_argument("Method name cannot be empty"));
142 }
143
144 if request.method.len() > ServiceConfig::MAX_METHOD_NAME_LENGTH {
145 return Err(Status::invalid_argument(format!(
146 "Method name exceeds maximum length of {} characters",
147 ServiceConfig::MAX_METHOD_NAME_LENGTH
148 )));
149 }
150
151 if request.parameter.len() > 4 * 1024 * 1024 {
153 return Err(Status::resource_exhausted("Request parameter size exceeds limit"));
154 }
155
156 if request.method.contains("../") || request.method.contains("::") {
158 return Err(Status::permission_denied("Invalid method name format"));
159 }
160
161 Ok(())
162 }
163
164 fn CreateErrorResponse(RequestIdentifier:u64, code:i32, message:String, data:Option<Vec<u8>>) -> GenericResponse {
175 GenericResponse {
176 request_identifier:RequestIdentifier,
177 result:vec![],
178 error:Some(RPCError { code, message, data:data.unwrap_or_default() }),
179 }
180 }
181
182 fn CreateSuccessResponse(RequestIdentifier:u64, result:&Value) -> GenericResponse {
191 let result_bytes = match serde_json::to_vec(result) {
192 Ok(bytes) => bytes,
193 Err(e) => {
194 error!("[MountainVinegRPCService] Failed to serialize result: {}", e);
195
196 return Self::CreateErrorResponse(
198 RequestIdentifier,
199 -32603, "Failed to serialize response".to_string(),
201 None,
202 );
203 },
204 };
205
206 GenericResponse { request_identifier:RequestIdentifier, result:result_bytes, error:None }
207 }
208}
209
210#[tonic::async_trait]
211impl MountainService for MountainVinegRPCService {
212 async fn process_cocoon_request(
227 &self,
228 request:Request<GenericRequest>,
229 ) -> Result<Response<GenericResponse>, Status> {
230 let RequestData = request.into_inner();
231
232 let MethodName = RequestData.method.clone();
233
234 let RequestIdentifier = RequestData.request_identifier;
235
236 info!(
237 "[MountainVinegRPCService] Received gRPC Request [ID: {}]: Method='{}'",
238 RequestIdentifier, MethodName
239 );
240
241 if let Err(status) = self.ValidateRequest(&RequestData) {
243 warn!("[MountainVinegRPCService] Request validation failed: {}", status);
244
245 return Ok(Response::new(Self::CreateErrorResponse(
246 RequestIdentifier,
247 -32602, status.message().to_string(),
249 None,
250 )));
251 }
252
253 let ParametersValue:Value = match serde_json::from_slice(&RequestData.parameter) {
255 Ok(v) => {
256 trace!("[MountainVinegRPCService] Params for [ID: {}]: {:?}", RequestIdentifier, v);
257 v
258 },
259 Err(e) => {
260 let msg = format!("Failed to deserialize parameters for method '{}': {}", MethodName, e);
261
262 error!("{}", msg);
263
264 return Ok(Response::new(Self::CreateErrorResponse(
265 RequestIdentifier,
266 -32700, msg,
268 None,
269 )));
270 },
271 };
272
273 debug!(
274 "[MountainVinegRPCService] Dispatching request [ID: {}] to Track::DispatchLogic",
275 RequestIdentifier
276 );
277
278 let DispatchResult = Track::SideCarRequest::DispatchSideCarRequest(
280 self.ApplicationHandle.clone(),
281 self.RunTime.clone(),
282 "cocoon-main".to_string(),
284 MethodName.clone(),
285 ParametersValue,
286 )
287 .await;
288
289 match DispatchResult {
290 Ok(SuccessfulResult) => {
291 info!(
292 "[MountainVinegRPCService] Request [ID: {}] completed successfully",
293 RequestIdentifier
294 );
295
296 Ok(Response::new(Self::CreateSuccessResponse(RequestIdentifier, &SuccessfulResult)))
297 },
298
299 Err(ErrorString) => {
300 error!(
301 "[MountainVinegRPCService] Request [ID: {}] failed: {}",
302 RequestIdentifier, ErrorString
303 );
304
305 Ok(Response::new(Self::CreateErrorResponse(
306 RequestIdentifier,
307 -32000, ErrorString,
309 None,
310 )))
311 },
312 }
313 }
314
315 async fn send_cocoon_notification(&self, request:Request<GenericNotification>) -> Result<Response<Empty>, Status> {
335 let NotificationData = request.into_inner();
336
337 let MethodName = NotificationData.method;
338
339 info!("[MountainVinegRPCService] Received gRPC Notification: Method='{}'", MethodName);
340
341 if MethodName.is_empty() {
343 warn!("[MountainVinegRPCService] Received notification with empty method name");
344 return Err(Status::invalid_argument("Method name cannot be empty"));
345 }
346
347 match MethodName.as_str() {
357 "ExtensionActivated" => {
358 debug!("[MountainVinegRPCService] Extension activated notification received");
359 },
360 "ExtensionDeactivated" => {
361 debug!("[MountainVinegRPCService] Extension deactivated notification received");
362 },
363 "WebviewReady" => {
364 debug!("[MountainVinegRPCService] Webview ready notification received");
365 },
366 _ => {
367 debug!("[MountainVinegRPCService] Unknown notification method: {}", MethodName);
368 },
369 }
370
371 Ok(Response::new(Empty {}))
372 }
373
374 async fn cancel_operation(&self, request:Request<CancelOperationRequest>) -> Result<Response<Empty>, Status> {
386 let cancel_request = request.into_inner();
387
388 let RequestIdentifierToCancel = cancel_request.request_identifier_to_cancel;
389
390 info!(
391 "[MountainVinegRPCService] Received CancelOperation request for RequestID: {}",
392 RequestIdentifierToCancel
393 );
394
395 let cancel_token = {
397 let operations = self.ActiveOperations.read().await;
398 operations.get(&RequestIdentifierToCancel).cloned()
399 };
400
401 match cancel_token {
402 Some(token) => {
403 token.cancel();
405
406 info!(
407 "[MountainVinegRPCService] Successfully initiated cancellation for operation {}",
408 RequestIdentifierToCancel
409 );
410
411 Ok(Response::new(Empty {}))
416 },
417 None => {
418 warn!(
420 "[MountainVinegRPCService] Cannot cancel operation {}: operation not found (may have already \
421 completed)",
422 RequestIdentifierToCancel
423 );
424
425 Ok(Response::new(Empty {}))
427 },
428 }
429 }
430}