Mountain/ProcessManagement/
InitializationData.rs1use std::{collections::HashMap, env, fs, path::PathBuf, sync::Arc};
136
137use CommonLibrary::{
138 Environment::Requires::Requires,
139 Error::CommonError::CommonError,
140 ExtensionManagement::ExtensionManagementService::ExtensionManagementService,
141 Workspace::WorkspaceProvider::WorkspaceProvider,
142};
143use serde_json::{Value, json};
144use tauri::{AppHandle, Manager, Wry};
145use uuid::Uuid;
146
147use crate::{
148 ApplicationState::State::ApplicationState::ApplicationState,
149 Environment::MountainEnvironment::MountainEnvironment,
150 dev_log,
151};
152
153fn get_or_generate_machine_id(app_data_dir:&PathBuf) -> String {
164 let machine_id_path = app_data_dir.join("machine-id.txt");
165
166 if let Ok(content) = fs::read_to_string(&machine_id_path) {
168 let trimmed = content.trim();
169 if !trimmed.is_empty() {
170 dev_log!("cocoon", "[InitializationData] Loaded existing machine ID from disk");
171 return trimmed.to_string();
172 }
173 }
174
175 let new_machine_id = Uuid::new_v4().to_string();
177
178 if let Some(parent) = machine_id_path.parent() {
180 if let Err(e) = fs::create_dir_all(parent) {
181 dev_log!(
182 "cocoon",
183 "warn: [InitializationData] Failed to create machine ID directory: {}",
184 e
185 );
186 }
187 }
188
189 if let Err(e) = fs::write(&machine_id_path, &new_machine_id) {
191 dev_log!(
192 "cocoon",
193 "warn: [InitializationData] Failed to persist machine ID to disk: {}",
194 e
195 );
196 } else {
197 dev_log!("cocoon", "[InitializationData] Generated and persisted new machine ID");
198 }
199
200 new_machine_id
201}
202
203pub async fn ConstructSandboxConfiguration(
205 ApplicationHandle:&AppHandle<Wry>,
206
207 ApplicationState:&Arc<ApplicationState>,
208) -> Result<Value, CommonError> {
209 dev_log!("cocoon", "[InitializationData] Constructing ISandboxConfiguration for Sky.");
210
211 let PathResolver = ApplicationHandle.path();
212
213 let AppRootUri = PathResolver.resource_dir().map_err(|Error| {
214 CommonError::ConfigurationLoad {
215 Description:format!("Failed to resolve resource directory (app root): {}", Error),
216 }
217 })?;
218
219 let AppDataDir = PathResolver.app_data_dir().map_err(|Error| {
220 CommonError::ConfigurationLoad { Description:format!("Failed to resolve app data directory: {}", Error) }
221 })?;
222
223 let HomeDir = PathResolver.home_dir().map_err(|Error| {
224 CommonError::ConfigurationLoad { Description:format!("Failed to resolve home directory: {}", Error) }
225 })?;
226
227 let TmpDir = env::temp_dir();
228
229 let BackupPath = AppDataDir.join("Backups").join(ApplicationState.GetWorkspaceIdentifier()?);
230
231 let Platform = match env::consts::OS {
232 "windows" => "win32",
233
234 "macos" => "darwin",
235
236 "linux" => "linux",
237
238 _ => "unknown",
239 };
240
241 let Arch = match env::consts::ARCH {
242 "x86_64" => "x64",
243
244 "aarch64" => "arm64",
245
246 "x86" => "ia32",
247
248 _ => "unknown",
249 };
250
251 let Versions = json!({
252 "mountain": ApplicationHandle.package_info().version.to_string(),
253
254 "electron": "0.0.0-tauri",
256
257 "chrome": "120.0.0.0",
259
260 "node": "18.18.2"
262 });
263
264 let machine_id = get_or_generate_machine_id(&AppDataDir);
266
267 Ok(json!({
268 "windowId": ApplicationHandle.get_webview_window("main").unwrap().label(),
269
270 "machineId": machine_id,
275
276 "sessionId": Uuid::new_v4().to_string(),
277
278 "logLevel": log::max_level() as i32,
279
280 "userEnv": env::vars().collect::<HashMap<_,_>>(),
281
282 "appRoot": url::Url::from_directory_path(AppRootUri).unwrap().to_string(),
283
284 "appName": ApplicationHandle.package_info().name.clone(),
285
286 "appUriScheme": "mountain",
287
288 "appLanguage": "en",
289
290 "appHost": "desktop",
291
292 "platform": Platform,
293
294 "arch": Arch,
295
296 "versions": Versions,
297
298 "execPath": env::current_exe().unwrap_or_default().to_string_lossy(),
299
300 "homeDir": url::Url::from_directory_path(HomeDir).unwrap().to_string(),
301
302 "tmpDir": url::Url::from_directory_path(TmpDir).unwrap().to_string(),
303
304 "userDataDir": url::Url::from_directory_path(AppDataDir).unwrap().to_string(),
305
306 "backupPath": url::Url::from_directory_path(BackupPath).unwrap().to_string(),
307
308 "nls": { "messages": {}, "language": "en", "availableLanguages": { "en": "English" } },
309
310 "productConfiguration": {
311
312 "nameShort": std::env::var("ProductNameShort").unwrap_or_else(|_| "Land".into()),
316
317 "nameLong": std::env::var("ProductNameLong").unwrap_or_else(|_| "Land Editor".into()),
318
319 "applicationName": std::env::var("ProductApplicationName").unwrap_or_else(|_| "land".into()),
320
321 "embedderIdentifier": std::env::var("ProductEmbedderIdentifier").unwrap_or_else(|_| "land-desktop".into())
322 },
323
324 "resourcesPath": PathResolver.resource_dir().unwrap_or_default().to_string_lossy(),
325
326 "VSCODE_CWD": env::current_dir().unwrap_or_default().to_string_lossy(),
327 }))
328}
329
330pub async fn ConstructExtensionHostInitializationData(Environment:&MountainEnvironment) -> Result<Value, CommonError> {
332 dev_log!("cocoon", "[InitializationData] Constructing IExtensionHostInitData for Cocoon.");
333
334 let ApplicationState = &Environment.ApplicationState;
335
336 let ApplicationHandle = &Environment.ApplicationHandle;
337
338 let ExtensionManagementProvider:Arc<dyn ExtensionManagementService> = Environment.Require();
339
340 let ExtensionsDTO = ExtensionManagementProvider.GetExtensions().await?;
341
342 let WorkspaceProvider:Arc<dyn WorkspaceProvider> = Environment.Require();
343
344 let WorkspaceName = WorkspaceProvider
345 .GetWorkspaceName()
346 .await?
347 .unwrap_or_else(|| "Mountain Workspace".to_string());
348
349 let WorkspaceFoldersGuard = ApplicationState.Workspace.WorkspaceFolders.lock().unwrap();
350
351 let FoldersWire:Vec<Value> = WorkspaceFoldersGuard
362 .iter()
363 .map(|Folder| {
364 json!({
365 "uri": Folder.URI.to_string(),
366 "name": Folder.GetDisplayName(),
367 "index": Folder.Index,
368 })
369 })
370 .collect();
371
372 dev_log!(
378 "cocoon",
379 "[InitializationData] FoldersWire count={} sample0={}",
380 FoldersWire.len(),
381 FoldersWire.first().map(|F| F.to_string()).unwrap_or_else(|| "<none>".into())
382 );
383
384 let WorkspaceDTO = if WorkspaceFoldersGuard.is_empty() {
385 Value::Null
386 } else {
387 json!({
388
389 "id": ApplicationState.GetWorkspaceIdentifier()?,
390
391 "name": WorkspaceName,
392
393 "folders": FoldersWire,
394
395 "configuration": ApplicationState.Workspace.WorkspaceConfigurationPath.lock().unwrap().as_ref().map(|p| p.to_string_lossy()),
396
397 "isUntitled": ApplicationState.Workspace.WorkspaceConfigurationPath.lock().unwrap().is_none(),
398
399 "transient": false
400 })
401 };
402
403 let PathResolver = ApplicationHandle.path();
404
405 let AppRoot = PathResolver
406 .resource_dir()
407 .ok()
408 .filter(|P| !P.as_os_str().is_empty() && P.exists())
409 .or_else(|| {
410 let ExeDir = std::env::current_exe()
420 .ok()
421 .and_then(|P| P.parent().map(|D| D.to_path_buf()))
422 .unwrap_or_default();
423 let BundleResources = ExeDir.join("../Resources");
424 if BundleResources.exists() {
425 return Some(BundleResources.canonicalize().unwrap_or(BundleResources));
426 }
427 let SkyTarget = ExeDir.join("../../../Sky/Target");
428 if SkyTarget.exists() {
429 return Some(SkyTarget.canonicalize().unwrap_or(SkyTarget));
430 }
431 None
432 })
433 .ok_or_else(|| CommonError::ConfigurationLoad {
434 Description:"Could not resolve AppRoot from resource_dir, ../Resources, or ../../../Sky/Target".to_string(),
435 })?;
436
437 let AppData = PathResolver
438 .app_data_dir()
439 .map_err(|Error| CommonError::ConfigurationLoad { Description:Error.to_string() })?;
440
441 let LogsLocation = PathResolver
442 .app_log_dir()
443 .map_err(|Error| CommonError::ConfigurationLoad { Description:Error.to_string() })?;
444
445 let GlobalStorage = AppData.join("User/globalStorage");
446
447 let WorkspaceStorage = AppData.join("User/workspaceStorage");
448
449 Ok(json!({
450
451 "commit": std::env::var("ProductCommit").unwrap_or_else(|_| "dev".into()),
457
458 "version": std::env::var("ProductVersion").unwrap_or_else(|_| {
459 ApplicationHandle.package_info().version.to_string()
460 }),
461
462 "quality": std::env::var("ProductQuality").unwrap_or_else(|_| "development".into()),
463
464 "parentPid": std::process::id(),
465
466 "environment": {
467
468 "isExtensionDevelopmentDebug": false,
469
470 "appName": "Mountain",
471
472 "appHost": "desktop",
473
474 "appUriScheme": "mountain",
475
476 "appLanguage": "en",
477
478 "isExtensionTelemetryLoggingOnly": true,
479
480 "appRoot": url::Url::from_directory_path(AppRoot.clone()).unwrap(),
481
482 "globalStorageHome": url::Url::from_directory_path(GlobalStorage).unwrap(),
483
484 "workspaceStorageHome": url::Url::from_directory_path(WorkspaceStorage).unwrap(),
485
486 "extensionDevelopmentLocationURI": [],
487
488 "extensionTestsLocationURI": Value::Null,
489
490 "extensionLogLevel": [["info", "Default"]],
491
492 },
493
494 "workspace": WorkspaceDTO,
495
496 "remote": {
497
498 "isRemote": false,
499
500 "authority": Value::Null,
501
502 "connectionData": Value::Null,
503
504 },
505
506 "consoleForward": { "includeStack": true, "logNative": true },
507
508 "logLevel": log::max_level() as i32,
509
510 "logsLocation": url::Url::from_directory_path(LogsLocation).unwrap(),
511
512 "telemetryInfo": {
513
514 "sessionId": Uuid::new_v4().to_string(),
515
516 "machineId": get_or_generate_machine_id(&AppData),
517
518 "firstSessionDate": "2024-01-01T00:00:00.000Z",
519
520 "msftInternal": false
521 },
522
523 "extensions": ExtensionsDTO,
524
525 "autoStart": true,
526
527 "uiKind": 1,
529 }))
530}