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