Mountain/Environment/
DebugProvider.rs

1// File: Mountain/Source/Environment/DebugProvider.rs
2// Role: Implements the `DebugService` trait for the `MountainEnvironment`.
3// Responsibilities:
4//   - Manage the registration of debug configuration providers and adapter
5//     factories.
6//   - Orchestrate the `startDebugging` flow, which involves:
7//     1. Calling back to the extension host to resolve the final debug
8//        configuration.
9//     2. Calling back to the extension host to get the debug adapter executable
10//        details.
11//     3. Spawning and managing the debug adapter process.
12//     4. Mediating communication between the UI, the extension host, and the
13//        debug adapter.
14
15//! # DebugProvider Implementation
16//!
17//! Implements the `DebugService` trait for the `MountainEnvironment`. This
18//! provider manages the entire debugging lifecycle, from configuration to
19//! adapter communication.
20
21#![allow(non_snake_case, non_camel_case_types)]
22
23use std::sync::Arc;
24
25use Common::{
26	Debug::DebugService::DebugService,
27	Environment::Requires::Requires,
28	Error::CommonError::CommonError,
29	IPC::{DTO::ProxyTarget::ProxyTarget, IPCProvider::IPCProvider},
30};
31use async_trait::async_trait;
32use log::{info, warn};
33use serde_json::{Value, json};
34use url::Url;
35
36use super::MountainEnvironment::MountainEnvironment;
37
38#[async_trait]
39impl DebugService for MountainEnvironment {
40	async fn RegisterDebugConfigurationProvider(
41		&self,
42
43		DebugType:String,
44
45		_ProviderHandle:u32,
46
47		_SideCarIdentifier:String,
48	) -> Result<(), CommonError> {
49		// TODO: Store this registration in ApplicationState to track which sidecar
50		// owns which debug type.
51		info!(
52			"[DebugProvider] Registering DebugConfigurationProvider for type '{}'",
53			DebugType
54		);
55		Ok(())
56	}
57
58	async fn RegisterDebugAdapterDescriptorFactory(
59		&self,
60
61		DebugType:String,
62
63		_FactoryHandle:u32,
64
65		_SideCarIdentifier:String,
66	) -> Result<(), CommonError> {
67		// TODO: Store this registration in ApplicationState.
68		info!(
69			"[DebugProvider] Registering DebugAdapterDescriptorFactory for type '{}'",
70			DebugType
71		);
72		Ok(())
73	}
74
75	async fn StartDebugging(&self, _FolderURI:Option<Url>, Configuration:Value) -> Result<String, CommonError> {
76		let SessionID = uuid::Uuid::new_v4().to_string();
77		info!(
78			"[DebugProvider] Starting debug session '{}' with config: {:?}",
79			SessionID, Configuration
80		);
81
82		let IPCProvider:Arc<dyn IPCProvider> = self.Require();
83		let DebugType = Configuration
84			.get("type")
85			.and_then(Value::as_str)
86			.ok_or_else(|| {
87				CommonError::InvalidArgument {
88					ArgumentName:"Configuration".into(),
89
90					Reason:"Missing 'type' field in debug configuration.".into(),
91				}
92			})?
93			.to_string();
94
95		// For now, assume the main sidecar handles all debugging.
96		let TargetSideCar = "cocoon-main".to_string();
97
98		// 1. Resolve configuration (Reverse-RPC to Cocoon)
99		info!("[DebugProvider] Resolving debug configuration...");
100		let ResolveConfigMethod = format!("{}$resolveDebugConfiguration", ProxyTarget::ExtHostDebug.GetTargetPrefix());
101		let ResolvedConfig = IPCProvider
102			.SendRequestToSideCar(
103				TargetSideCar.clone(),
104				ResolveConfigMethod,
105				json!([DebugType.clone(), Configuration]),
106				5000,
107			)
108			.await?;
109
110		// 2. Get the Debug Adapter Descriptor (Reverse-RPC to Cocoon)
111		info!("[DebugProvider] Creating debug adapter descriptor...");
112		let CreateDescriptorMethod =
113			format!("{}$createDebugAdapterDescriptor", ProxyTarget::ExtHostDebug.GetTargetPrefix());
114		let Descriptor = IPCProvider
115			.SendRequestToSideCar(
116				TargetSideCar.clone(),
117				CreateDescriptorMethod,
118				json!([DebugType, &ResolvedConfig]),
119				5000,
120			)
121			.await?;
122
123		// 3. Spawn the Debug Adapter process based on the descriptor.
124		// This is a complex step involving process management. For now, we log and
125		// simulate.
126		info!("[DebugProvider] Spawning Debug Adapter based on descriptor: {:?}", Descriptor);
127		// A full implementation would:
128		// - Parse the `Descriptor` (which could be an executable, a server port, etc.).
129		// - Spawn a new OS process or connect to a TCP socket.
130		// - Create a new `DebugSession` struct to manage the DAP communication stream.
131		// - Store this session in `ApplicationState`.
132
133		info!("[DebugProvider] Debug session '{}' started (simulation).", SessionID);
134		Ok(SessionID)
135	}
136
137	async fn SendCommand(&self, SessionID:String, Command:String, Arguments:Value) -> Result<Value, CommonError> {
138		// TODO:
139		// 1. Look up the active `DebugSession` in `ApplicationState` using `SessionID`.
140		// 2. Serialize the command and arguments into a DAP message.
141		// 3. Write the message to the Debug Adapter's stdin/socket.
142		// 4. Await a response from the adapter, deserialize it, and return.
143		warn!(
144			"[DebugProvider] SendCommand for session '{}' (command: '{}', args: {:?}) is not implemented.",
145			SessionID, Command, Arguments
146		);
147		Err(CommonError::NotImplemented { FeatureName:"DebugService.SendCommand".into() })
148	}
149}