1use std::{collections::HashMap, sync::Arc};
38
39use serde_json::{Value, json};
40use tauri::{AppHandle, Emitter};
41use tokio::sync::RwLock;
42use tonic::{Request, Response, Status};
43
44use crate::{
45 RunTime::ApplicationRunTime::ApplicationRunTime,
46 Track,
47 Vine::Generated::{
48 CancelOperationRequest,
49 Empty,
50 GenericNotification,
51 GenericRequest,
52 GenericResponse,
53 RpcError as RPCError,
54 mountain_service_server::MountainService,
55 },
56 dev_log,
57};
58
59#[allow(dead_code)]
61mod ServiceConfig {
62
63 pub const MAX_CONCURRENT_OPERATIONS:usize = 50;
65
66 pub const CANCELLATION_TIMEOUT_MS:u64 = 5000;
68
69 pub const MAX_METHOD_NAME_LENGTH:usize = 128;
71}
72
73pub struct MountainVinegRPCService {
79 ApplicationHandle:AppHandle,
81
82 RunTime:Arc<ApplicationRunTime>,
84
85 ActiveOperations:Arc<RwLock<HashMap<u64, tokio_util::sync::CancellationToken>>>,
88}
89
90impl MountainVinegRPCService {
91 pub fn ApplicationHandle(&self) -> &AppHandle { &self.ApplicationHandle }
97
98 pub fn RunTime(&self) -> &Arc<ApplicationRunTime> { &self.RunTime }
103}
104
105impl MountainVinegRPCService {
106 pub fn Create(ApplicationHandle:AppHandle, RunTime:Arc<ApplicationRunTime>) -> Self {
115 dev_log!("grpc", "[MountainVinegRPCService] New instance created");
116
117 Self {
118 ApplicationHandle,
119
120 RunTime,
121
122 ActiveOperations:Arc::new(RwLock::new(HashMap::new())),
123 }
124 }
125
126 pub async fn RegisterOperation(&self, request_id:u64) -> tokio_util::sync::CancellationToken {
134 let token = tokio_util::sync::CancellationToken::new();
135
136 self.ActiveOperations.write().await.insert(request_id, token.clone());
137
138 dev_log!(
139 "grpc",
140 "[MountainVinegRPCService] Registered operation {} for cancellation",
141 request_id
142 );
143
144 token
145 }
146
147 pub async fn UnregisterOperation(&self, request_id:u64) {
152 self.ActiveOperations.write().await.remove(&request_id);
153
154 dev_log!("grpc", "[MountainVinegRPCService] Unregistered operation {}", request_id);
155 }
156
157 fn ValidateRequest(&self, request:&GenericRequest) -> Result<(), Status> {
166 if request.method.is_empty() {
168 return Err(Status::invalid_argument("Method name cannot be empty"));
169 }
170
171 if request.method.len() > ServiceConfig::MAX_METHOD_NAME_LENGTH {
172 return Err(Status::invalid_argument(format!(
173 "Method name exceeds maximum length of {} characters",
174 ServiceConfig::MAX_METHOD_NAME_LENGTH
175 )));
176 }
177
178 if request.parameter.len() > 4 * 1024 * 1024 {
180 return Err(Status::resource_exhausted("Request parameter size exceeds limit"));
181 }
182
183 if request.method.contains("../") || request.method.contains("::") {
185 return Err(Status::permission_denied("Invalid method name format"));
186 }
187
188 Ok(())
189 }
190
191 fn CreateErrorResponse(RequestIdentifier:u64, code:i32, message:String, data:Option<Vec<u8>>) -> GenericResponse {
202 GenericResponse {
203 request_identifier:RequestIdentifier,
204
205 result:vec![],
206
207 error:Some(RPCError { code, message, data:data.unwrap_or_default() }),
208 }
209 }
210
211 fn CreateSuccessResponse(RequestIdentifier:u64, result:&Value) -> GenericResponse {
220 let result_bytes = match serde_json::to_vec(result) {
221 Ok(bytes) => bytes,
222
223 Err(e) => {
224 dev_log!("grpc", "error: [MountainVinegRPCService] Failed to serialize result: {}", e);
225
226 return Self::CreateErrorResponse(
228 RequestIdentifier,
229 -32603, "Failed to serialize response".to_string(),
231 None,
232 );
233 },
234 };
235
236 GenericResponse { request_identifier:RequestIdentifier, result:result_bytes, error:None }
237 }
238}
239
240#[tonic::async_trait]
241impl MountainService for MountainVinegRPCService {
242 type OpenChannelFromCocoonStream = std::pin::Pin<
248 Box<
249 dyn tonic::codegen::tokio_stream::Stream<Item = Result<crate::Vine::Generated::Envelope, tonic::Status>>
250 + Send
251 + 'static,
252 >,
253 >;
254
255 async fn open_channel_from_cocoon(
256 &self,
257
258 _request:tonic::Request<tonic::Streaming<crate::Vine::Generated::Envelope>>,
259 ) -> Result<tonic::Response<Self::OpenChannelFromCocoonStream>, tonic::Status> {
260 Err(tonic::Status::unimplemented(
261 "OpenChannelFromCocoon: streaming multiplexer not yet wired (Patch 14); use unary endpoints",
262 ))
263 }
264
265 async fn process_cocoon_request(
280 &self,
281
282 request:Request<GenericRequest>,
283 ) -> Result<Response<GenericResponse>, Status> {
284 let RequestData = request.into_inner();
285
286 let MethodName = RequestData.method.clone();
287
288 let RequestIdentifier = RequestData.request_identifier;
289
290 let ReceiveInstant = std::time::Instant::now();
291
292 dev_log!(
301 "grpc-verbose",
302 "[MountainVinegRPCService] recv id={} method={} size={}B",
303 RequestIdentifier,
304 MethodName,
305 RequestData.parameter.len()
306 );
307
308 let IsHotRpc = matches!(
317 MethodName.as_str(),
318 "$tree:register" | "tree.register" | "Configuration.Inspect" | "Command.Execute"
319 );
320
321 if IsHotRpc {
322 let InstrumentRecvNs = std::time::SystemTime::now()
323 .duration_since(std::time::UNIX_EPOCH)
324 .map(|D| D.as_nanos())
325 .unwrap_or(0);
326
327 dev_log!(
331 "rpc-latency",
332 "[LandFix:RPC] grpc-recv method={} id={} size={} t_ns={}",
333 MethodName,
334 RequestIdentifier,
335 RequestData.parameter.len(),
336 InstrumentRecvNs
337 );
338 }
339
340 if let Err(status) = self.ValidateRequest(&RequestData) {
342 dev_log!("grpc", "warn: [MountainVinegRPCService] Request validation failed: {}", status);
343
344 return Ok(Response::new(Self::CreateErrorResponse(
345 RequestIdentifier,
346 -32602, status.message().to_string(),
348 None,
349 )));
350 }
351
352 let ParametersValue:Value = match serde_json::from_slice(&RequestData.parameter) {
356 Ok(v) => v,
357
358 Err(e) => {
359 let msg = format!("Failed to deserialize parameters for method '{}': {}", MethodName, e);
360
361 dev_log!("grpc", "error: {}", msg);
362
363 return Ok(Response::new(Self::CreateErrorResponse(
364 RequestIdentifier,
365 -32700, msg,
367 None,
368 )));
369 },
370 };
371
372 let DispatchResult = Track::SideCarRequest::DispatchSideCarRequest::DispatchSideCarRequest(
378 self.ApplicationHandle.clone(),
379 self.RunTime.clone(),
380 "cocoon-main".to_string(),
382 MethodName.clone(),
383 ParametersValue,
384 )
385 .await;
386
387 match DispatchResult {
388 Ok(SuccessfulResult) => {
389 if IsHotRpc {
390 dev_log!(
394 "rpc-latency",
395 "[LandFix:RPC] dispatched method={} id={} elapsed={}ms",
396 MethodName,
397 RequestIdentifier,
398 ReceiveInstant.elapsed().as_millis()
399 );
400 }
401
402 dev_log!(
407 "grpc-verbose",
408 "[MountainVinegRPCService] Request [ID: {}] completed successfully",
409 RequestIdentifier
410 );
411
412 Ok(Response::new(Self::CreateSuccessResponse(RequestIdentifier, &SuccessfulResult)))
413 },
414
415 Err(ErrorString) => {
416 let LowerError = ErrorString.to_lowercase();
427
428 let LooksLike404 = (MethodName == "FileSystem.ReadFile"
440 || MethodName == "FileSystem.Stat"
441 || MethodName == "FileSystem.ReadDirectory")
442 && (LowerError.contains("resource not found")
443 || LowerError.contains("not found")
444 || LowerError.contains("enoent")
445 || LowerError.contains("no such file or directory")
446 || LowerError.contains("entity not found")
447 || LowerError.contains("os error 2")
448 || LowerError.contains("path is outside of the registered workspace")
449 || LowerError.contains("permission denied for operation")
450 || LowerError.contains("workspace is not trusted"));
451
452 if LooksLike404 {
453 dev_log!(
454 "grpc-verbose",
455 "[LandFix:MountainVinegRPC] Request [ID: {}] {} 404 (benign): {}",
456 RequestIdentifier,
457 MethodName,
458 ErrorString
459 );
460 } else {
461 dev_log!(
462 "grpc",
463 "error: [MountainVinegRPCService] Request [ID: {}] failed: {}",
464 RequestIdentifier,
465 ErrorString
466 );
467 }
468
469 let ErrorCode = if LooksLike404 { -32004 } else { -32000 };
473
474 Ok(Response::new(Self::CreateErrorResponse(
475 RequestIdentifier,
476 ErrorCode,
477 ErrorString,
478 None,
479 )))
480 },
481 }
482 }
483
484 async fn send_cocoon_notification(&self, request:Request<GenericNotification>) -> Result<Response<Empty>, Status> {
504 let NotificationData = request.into_inner();
505
506 let MethodName = NotificationData.method;
507
508 dev_log!(
512 "grpc-verbose",
513 "[MountainVinegRPCService] Received gRPC Notification: Method='{}'",
514 MethodName
515 );
516
517 if MethodName.is_empty() {
519 dev_log!(
520 "grpc",
521 "warn: [MountainVinegRPCService] Received notification with empty method name"
522 );
523
524 return Err(Status::invalid_argument("Method name cannot be empty"));
525 }
526
527 let Parameter:Value = if NotificationData.parameter.is_empty() {
538 Value::Null
539 } else {
540 serde_json::from_slice(&NotificationData.parameter).unwrap_or(Value::Null)
541 };
542
543 match MethodName.as_str() {
544
545 "extensionHostMessage" => {
550
551 super::Notification::ExtensionHostMessage::ExtensionHostMessage(self, &Parameter).await;
552 },
553
554 "ExtensionActivated" => {
555
556 super::Notification::ExtensionActivated::ExtensionActivated(self, &Parameter).await;
557 },
558
559 "ExtensionDeactivated" => {
560
561 super::Notification::ExtensionDeactivated::ExtensionDeactivated(self, &Parameter).await;
562 },
563
564 "WebviewReady" => {
565
566 super::Notification::WebviewReady::WebviewReady(self, &Parameter).await;
567 },
568
569 "progress.start" => {
570
571 super::Notification::ProgressStart::ProgressStart(self, &Parameter).await;
572 },
573
574 "progress.report" => {
575
576 super::Notification::ProgressReport::ProgressReport(self, &Parameter).await;
577 },
578
579 "progress.end" => {
580
581 super::Notification::ProgressEnd::ProgressEnd(self, &Parameter).await;
582 },
583
584 "languages.setDocumentLanguage" => {
585
586 super::Notification::LanguagesSetDocumentLanguage::LanguagesSetDocumentLanguage(self, &Parameter).await;
587 },
588
589 "workspace.applyEdit" => {
590
591 super::Notification::WorkspaceApplyEdit::WorkspaceApplyEdit(self, &Parameter).await;
592 },
593
594 "window.showTextDocument" => {
595
596 super::Notification::WindowShowTextDocument::WindowShowTextDocument(self, &Parameter).await;
597 },
598
599 "webview.setTitle"
605 | "webview.setIconPath"
606 | "webview.setHtml"
607 | "webview.updateView"
608 | "webview.reveal" => {
609
610 super::Notification::WebviewLifecycle::WebviewLifecycle(self, &MethodName, &Parameter).await;
611 },
612
613 "window.createTerminal" => {
614
615 super::Notification::WindowCreateTerminal::WindowCreateTerminal(self, &Parameter).await;
616 },
617
618 "terminal.sendText" | "terminal.show" | "terminal.hide" | "terminal.dispose" => {
619
620 super::Notification::TerminalLifecycle::TerminalLifecycle(self, &MethodName, &Parameter).await;
621 },
622
623 "window.createTextEditorDecorationType" | "window.disposeTextEditorDecorationType" => {
624
625 super::Notification::DecorationTypeLifecycle::DecorationTypeLifecycle(self, &MethodName, &Parameter).await;
626 },
627
628 "window.setTextEditorDecorations" => {
632
633 super::Notification::SetTextEditorDecorations::SetTextEditorDecorations(self, &Parameter).await;
634 },
635
636 "window.applyTextEdits" => {
640
641 super::Notification::ApplyTextEdits::ApplyTextEdits(self, &Parameter).await;
642 },
643
644 "debug.addBreakpoints" | "debug.removeBreakpoints" | "debug.consoleAppend" => {
645
646 super::Notification::DebugLifecycle::DebugLifecycle(self, &MethodName, &Parameter).await;
647 },
648
649 "statusBar.update" | "statusBar.dispose" => {
650
651 super::Notification::StatusBarLifecycle::StatusBarLifecycle(self, &MethodName, &Parameter).await;
652 },
653
654 "statusBar.message" => {
655
656 super::Notification::StatusBarMessage::StatusBarMessage(self, &Parameter).await;
657 },
658
659 "window.showMessage" => {
660
661 super::Notification::WindowShowMessage::WindowShowMessage(self, &Parameter).await;
662 },
663
664 "registerCommand" => {
665
666 super::Notification::RegisterCommand::RegisterCommand(self, &Parameter).await;
667 },
668
669 "unregisterCommand" => {
670
671 super::Notification::UnregisterCommand::UnregisterCommand(self, &Parameter).await;
672 },
673
674 "unregister_authentication_provider" => {
684
685 super::Notification::UnregisterAuthenticationProvider::UnregisterAuthenticationProvider(self, &Parameter).await;
686 },
687
688 "unregister_debug_adapter" => {
689
690 super::Notification::UnregisterDebugAdapter::UnregisterDebugAdapter(self, &Parameter).await;
691 },
692
693 "unregister_debug_configuration_provider" => {
694
695 super::Notification::UnregisterDebugConfigurationProvider::UnregisterDebugConfigurationProvider(
696 self,
697
698 &Parameter,
699 )
700 .await;
701 },
702
703 "unregister_file_system_provider" => {
704
705 super::Notification::UnregisterFileSystemProvider::UnregisterFileSystemProvider(self, &Parameter).await;
706 },
707
708 "unregister_scm_provider" => {
709
710 super::Notification::UnregisterScmProvider::UnregisterScmProvider(self, &Parameter).await;
711 },
712
713 "unregister_task_provider" => {
714
715 super::Notification::UnregisterTaskProvider::UnregisterTaskProvider(self, &Parameter).await;
716 },
717
718 "unregister_uri_handler" => {
719
720 super::Notification::UnregisterUriHandler::UnregisterUriHandler(self, &Parameter).await;
721 },
722
723 "update_scm_group" => {
724
725 super::Notification::UpdateScmGroup::UpdateScmGroup(self, &Parameter).await;
726 },
727
728 "register_scm_provider" => {
739
740 super::Notification::RegisterScmProvider::RegisterScmProvider(self, &Parameter).await;
741 },
742
743 "register_scm_resource_group" => {
744
745 super::Notification::RegisterScmResourceGroup::RegisterScmResourceGroup(self, &Parameter).await;
746 },
747
748 "progress.update" => {
750
751 super::Notification::ProgressUpdate::ProgressUpdate(self, &Parameter).await;
752 },
753
754 "progress.complete" => {
755
756 super::Notification::ProgressComplete::ProgressComplete(self, &Parameter).await;
757 },
758
759 "setStatusBarText" => {
761
762 super::Notification::SetStatusBarText::SetStatusBarText(self, &Parameter).await;
763 },
764
765 "disposeStatusBarItem" => {
766
767 super::Notification::DisposeStatusBarItem::DisposeStatusBarItem(self, &Parameter).await;
768 },
769
770 "output.create" => {
775
776 super::Notification::OutputCreate::OutputCreate(self, &Parameter).await;
777 },
778
779 "output.append" => {
780
781 super::Notification::OutputAppend::OutputAppend(self, &Parameter).await;
782 },
783
784 "output.appendLine" => {
785
786 super::Notification::OutputAppendLine::OutputAppendLine(self, &Parameter).await;
787 },
788
789 "output.clear" => {
790
791 super::Notification::OutputClear::OutputClear(self, &Parameter).await;
792 },
793
794 "output.show" => {
795
796 super::Notification::OutputShow::OutputShow(self, &Parameter).await;
797 },
798
799 "output.dispose" => {
800
801 super::Notification::OutputDispose::OutputDispose(self, &Parameter).await;
802 },
803
804 "output.replace" => {
805
806 super::Notification::OutputReplace::OutputReplace(self, &Parameter).await;
807 },
808
809 "outputChannel.create" => {
810
811 super::Notification::OutputChannelCreate::OutputChannelCreate(self, &Parameter).await;
812 },
813
814 "outputChannel.append" => {
815
816 super::Notification::OutputChannelAppend::OutputChannelAppend(self, &Parameter).await;
817 },
818
819 "outputChannel.clear" => {
820
821 super::Notification::OutputChannelClear::OutputChannelClear(self, &Parameter).await;
822 },
823
824 "outputChannel.show" => {
825
826 super::Notification::OutputChannelShow::OutputChannelShow(self, &Parameter).await;
827 },
828
829 "outputChannel.hide" => {
830
831 super::Notification::OutputChannelHide::OutputChannelHide(self, &Parameter).await;
832 },
833
834 "outputChannel.dispose" => {
835
836 super::Notification::OutputChannelDispose::OutputChannelDispose(self, &Parameter).await;
837 },
838
839 "webview.postMessage" => {
841
842 super::Notification::WebviewPostMessage::WebviewPostMessage(self, &Parameter).await;
843 },
844
845 "webview.dispose" => {
846
847 super::Notification::WebviewDispose::WebviewDispose(self, &Parameter).await;
848 },
849
850 "set_language_configuration" => {
852
853 super::Notification::SetLanguageConfiguration::SetLanguageConfiguration(self, &Parameter).await;
854 },
855
856 "openExternal" => {
857
858 super::Notification::OpenExternal::OpenExternal(self, &Parameter).await;
859 },
860
861 "security.incident" => {
862
863 super::Notification::SecurityIncident::SecurityIncident(self, &Parameter).await;
864 },
865
866 "register_authentication_provider"
888 | "register_call_hierarchy_provider"
889 | "register_code_actions_provider"
890 | "register_code_lens_provider"
891 | "register_color_provider"
892 | "register_completion_item_provider"
893 | "register_debug_adapter"
894 | "register_debug_configuration_provider"
895 | "register_declaration_provider"
896 | "register_definition_provider"
897 | "register_document_drop_edit_provider"
898 | "register_document_formatting_provider"
899 | "register_document_highlight_provider"
900 | "register_document_link_provider"
901 | "register_document_paste_edit_provider"
902 | "register_document_range_formatting_provider"
903 | "register_document_symbol_provider"
904 | "register_evaluatable_expression_provider"
905 | "register_external_uri_opener"
906 | "register_file_decoration_provider"
907 | "register_file_system_provider"
908 | "register_folding_range_provider"
909 | "register_hover_provider"
910 | "register_implementation_provider"
911 | "register_inlay_hints_provider"
912 | "register_inline_completion_item_provider"
913 | "register_inline_edit_provider"
914 | "register_inline_values_provider"
915 | "register_linked_editing_range_provider"
916 | "register_mapped_edits_provider"
917 | "register_multi_document_highlight_provider"
918 | "register_notebook_content_provider"
919 | "register_notebook_serializer"
920 | "register_on_type_formatting_provider"
921 | "register_reference_provider"
922 | "register_remote_authority_resolver"
923 | "register_rename_provider"
924 | "register_resource_label_formatter"
925 | "register_selection_range_provider"
932 | "register_semantic_tokens_provider"
933 | "register_signature_help_provider"
934 | "register_task_provider"
935 | "register_terminal_link_provider"
936 | "register_terminal_profile_provider"
937 | "register_text_document_content_provider"
938 | "register_type_definition_provider"
939 | "register_type_hierarchy_provider"
940 | "register_uri_handler"
941 | "register_workspace_symbol_provider" => {
942
943 let Handle = Parameter.get("handle").and_then(|h| h.as_u64()).unwrap_or(0) as u32;
944
945 let Selector = Parameter
952 .get("languageSelector")
953 .or_else(|| Parameter.get("language_selector"))
954 .and_then(|s| s.as_str())
955 .unwrap_or("*");
956
957 let ExtId = Parameter
958 .get("extensionId")
959 .or_else(|| Parameter.get("extension_id"))
960 .and_then(|e| e.as_str())
961 .unwrap_or("");
962
963 let Scheme = Parameter.get("scheme").and_then(|s| s.as_str()).unwrap_or("");
966
967 let ProviderTypeName = MethodName
968 .strip_prefix("register_")
969 .map(|Stripped| Stripped.strip_suffix("_provider").unwrap_or(Stripped))
970 .unwrap_or("");
971
972 dev_log!(
979 "grpc-verbose",
980
981 "[MountainVinegRPCService] Cocoon registered {} provider: handle={}, lang={}",
982
983 ProviderTypeName,
984
985 Handle,
986
987 Selector
988 );
989
990 dev_log!(
991 "provider-register",
992
993 "[ProviderRegister] accepted method={} type={} handle={} lang={} scheme={} ext={}",
994
995 MethodName,
996
997 ProviderTypeName,
998
999 Handle,
1000
1001 Selector,
1002
1003 Scheme,
1004
1005 ExtId
1006 );
1007
1008 use CommonLibrary::LanguageFeature::DTO::ProviderType::ProviderType as PT;
1009
1010 let ProvType = match ProviderTypeName {
1011
1012 "authentication" => Some(PT::Authentication),
1013
1014 "call_hierarchy" => Some(PT::CallHierarchy),
1015
1016 "code_actions" => Some(PT::CodeAction),
1017
1018 "code_lens" => Some(PT::CodeLens),
1019
1020 "color" => Some(PT::Color),
1021
1022 "completion_item" => Some(PT::Completion),
1023
1024 "debug_adapter" => Some(PT::DebugAdapter),
1025
1026 "debug_configuration" => Some(PT::DebugConfiguration),
1027
1028 "declaration" => Some(PT::Declaration),
1029
1030 "definition" => Some(PT::Definition),
1031
1032 "document_drop_edit" => Some(PT::DocumentDropEdit),
1033
1034 "document_formatting" => Some(PT::DocumentFormatting),
1035
1036 "document_highlight" => Some(PT::DocumentHighlight),
1037
1038 "document_link" => Some(PT::DocumentLink),
1039
1040 "document_paste_edit" => Some(PT::DocumentPasteEdit),
1041
1042 "document_range_formatting" => Some(PT::DocumentRangeFormatting),
1043
1044 "document_symbol" => Some(PT::DocumentSymbol),
1045
1046 "evaluatable_expression" => Some(PT::EvaluatableExpression),
1047
1048 "external_uri_opener" => Some(PT::ExternalUriOpener),
1049
1050 "file_decoration" => Some(PT::FileDecoration),
1051
1052 "file_system" => Some(PT::FileSystem),
1053
1054 "folding_range" => Some(PT::FoldingRange),
1055
1056 "hover" => Some(PT::Hover),
1057
1058 "implementation" => Some(PT::Implementation),
1059
1060 "inlay_hints" => Some(PT::InlayHint),
1061
1062 "inline_completion_item" => Some(PT::InlineCompletion),
1063
1064 "inline_edit" => Some(PT::InlineEdit),
1065
1066 "inline_values" => Some(PT::InlineValues),
1067
1068 "linked_editing_range" => Some(PT::LinkedEditingRange),
1069
1070 "mapped_edits" => Some(PT::MappedEdits),
1071
1072 "multi_document_highlight" => Some(PT::MultiDocumentHighlight),
1073
1074 "notebook_content" => Some(PT::NotebookContent),
1075
1076 "notebook_serializer" => Some(PT::NotebookSerializer),
1077
1078 "on_type_formatting" => Some(PT::OnTypeFormatting),
1079
1080 "reference" => Some(PT::References),
1081
1082 "remote_authority_resolver" => Some(PT::RemoteAuthorityResolver),
1083
1084 "rename" => Some(PT::Rename),
1085
1086 "resource_label_formatter" => Some(PT::ResourceLabelFormatter),
1087
1088 "scm" => Some(PT::SourceControl),
1089
1090 "scm_resource_group" => Some(PT::ScmResourceGroup),
1091
1092 "selection_range" => Some(PT::SelectionRange),
1093
1094 "semantic_tokens" => Some(PT::SemanticTokens),
1095
1096 "signature_help" => Some(PT::SignatureHelp),
1097
1098 "task" => Some(PT::Task),
1099
1100 "terminal_link" => Some(PT::TerminalLink),
1101
1102 "terminal_profile" => Some(PT::TerminalProfile),
1103
1104 "text_document_content" => Some(PT::TextDocumentContent),
1105
1106 "type_definition" => Some(PT::TypeDefinition),
1107
1108 "type_hierarchy" => Some(PT::TypeHierarchy),
1109
1110 "uri_handler" => Some(PT::UriHandler),
1111
1112 "workspace_symbol" => Some(PT::WorkspaceSymbol),
1113
1114 _ => None,
1115 };
1116
1117 if let Some(ProviderType) = ProvType {
1118
1119 use crate::ApplicationState::DTO::ProviderRegistrationDTO::ProviderRegistrationDTO;
1120
1121 let SelectorValue = if !Scheme.is_empty() {
1125
1126 json!([{ "scheme": Scheme, "language": Selector }])
1127 } else {
1128
1129 json!([{ "language": Selector }])
1130 };
1131
1132 let Dto = ProviderRegistrationDTO {
1133
1134 Handle,
1135
1136 ProviderType,
1137
1138 Selector:SelectorValue,
1139
1140 SideCarIdentifier:"cocoon-main".to_string(),
1141
1142 ExtensionIdentifier:json!(ExtId),
1143
1144 Options:Parameter.get("options").cloned(),
1145 };
1146
1147 self.RunTime
1148 .Environment
1149 .ApplicationState
1150 .Extension
1151 .ProviderRegistration
1152 .RegisterProvider(Handle, Dto);
1153 }
1154 },
1155
1156 _ => {
1157
1158 dev_log!("grpc", "[MountainVinegRPCService] Cocoon notification: {}", MethodName);
1159
1160 let PayloadPreview = if NotificationData.parameter.len() <= 160 {
1173
1174 String::from_utf8_lossy(&NotificationData.parameter).into_owned()
1175 } else {
1176
1177 let Slice = &NotificationData.parameter[..160];
1178
1179 format!("{}…", String::from_utf8_lossy(Slice))
1180 };
1181
1182 dev_log!(
1183 "notif-drop",
1184
1185 "[NotifDrop] method={} payload_bytes={} preview={:?} (falls through to cocoon:{} event)",
1186
1187 MethodName,
1188
1189 NotificationData.parameter.len(),
1190
1191 PayloadPreview,
1192
1193 MethodName
1194 );
1195
1196 let EventName = format!("cocoon:{}", MethodName);
1199
1200 if let Err(Error) = self.ApplicationHandle.emit(&EventName, &Parameter) {
1201
1202 dev_log!(
1203 "grpc",
1204
1205 "warn: [MountainVinegRPCService] Failed to emit {}: {}",
1206
1207 EventName,
1208
1209 Error
1210 );
1211 }
1212 },
1213 }
1214
1215 Ok(Response::new(Empty {}))
1216 }
1217
1218 async fn cancel_operation(&self, request:Request<CancelOperationRequest>) -> Result<Response<Empty>, Status> {
1230 let cancel_request = request.into_inner();
1231
1232 let RequestIdentifierToCancel = cancel_request.request_identifier_to_cancel;
1233
1234 dev_log!(
1235 "grpc",
1236 "[MountainVinegRPCService] Received CancelOperation request for RequestID: {}",
1237 RequestIdentifierToCancel
1238 );
1239
1240 let cancel_token = {
1242 let operations = self.ActiveOperations.read().await;
1243
1244 operations.get(&RequestIdentifierToCancel).cloned()
1245 };
1246
1247 match cancel_token {
1248 Some(token) => {
1249 token.cancel();
1251
1252 dev_log!(
1253 "grpc",
1254 "[MountainVinegRPCService] Successfully initiated cancellation for operation {}",
1255 RequestIdentifierToCancel
1256 );
1257
1258 Ok(Response::new(Empty {}))
1263 },
1264
1265 None => {
1266 dev_log!(
1268 "grpc",
1269 "warn: [MountainVinegRPCService] Cannot cancel operation {}: operation not found (may have \
1270 already completed)",
1271 RequestIdentifierToCancel
1272 );
1273
1274 Ok(Response::new(Empty {}))
1276 },
1277 }
1278 }
1279}