DevelopmentNodeEnvironment_MicrosoftVSCodeDependency_22NodeVersion_Bundle_Clean_Debug_ElectronProfile_EsbuildCompiler_Mountain/IPC/WindServiceHandlers/NativeHost/
OpenExternal.rs1#![allow(non_snake_case, unused_variables, dead_code, unused_imports)]
2
3use std::sync::Arc;
7
8use serde_json::Value;
9
10use crate::{RunTime::ApplicationRunTime::ApplicationRunTime, dev_log};
11
12pub async fn OpenExternal(RunTime:Arc<ApplicationRunTime>, Arguments:Vec<Value>) -> Result<Value, String> {
13 let url_str = match Arguments.first() {
16 Some(Value::String(S)) => S.as_str(),
17 Some(Value::Object(Obj)) => Obj.get("uri").or_else(|| Obj.get("url")).and_then(|V| V.as_str()).unwrap_or(""),
18 _ => return Ok(Value::Bool(false)),
19 };
20
21 if url_str.is_empty() {
22 return Ok(Value::Bool(false));
23 }
24
25 dev_log!("lifecycle", "openExternal: {}", url_str);
26
27 let Scheme = url_str.splitn(2, ':').next().unwrap_or("").to_lowercase();
31 let AllowedSchemes = [
32 "http",
33 "https",
34 "mailto",
35 "ftp",
36 "vscode",
37 "fiddee",
38 "ssh",
39 "git",
40 "x-github-client",
41 "github-windows",
42 "slack",
43 "teams",
44 "zoommtg",
45 "tel",
46 "callto",
47 ];
48 if Scheme == "file" || Scheme.is_empty() || !url_str.contains(':') {
49 dev_log!(
50 "lifecycle",
51 "warn: [OpenExternal] blocked scheme '{}' for uri '{}'",
52 Scheme,
53 url_str
54 );
55 return Ok(Value::Bool(false));
56 }
57 let IsKnownScheme = AllowedSchemes.contains(&Scheme.as_str());
58 if !IsKnownScheme {
59 dev_log!(
60 "lifecycle",
61 "[OpenExternal] unknown scheme '{}' - forwarding to OS anyway",
62 Scheme
63 );
64 }
65
66 #[cfg(target_os = "macos")]
67 {
68 use std::process::Command;
69
70 let result = Command::new("open")
71 .arg(url_str)
72 .output()
73 .map_err(|Error| format!("Failed to execute open command: {}", Error))?;
74
75 if !result.status.success() {
76 return Err(format!("Failed to open URL: {}", String::from_utf8_lossy(&result.stderr)));
77 }
78 }
79
80 #[cfg(target_os = "windows")]
81 {
82 use std::process::Command;
83
84 let result = Command::new("cmd")
85 .arg("/c")
86 .arg("start")
87 .arg(url_str)
88 .output()
89 .map_err(|Error| format!("Failed to execute start command: {}", Error))?;
90
91 if !result.status.success() {
92 return Err(format!("Failed to open URL: {}", String::from_utf8_lossy(&result.stderr)));
93 }
94 }
95
96 #[cfg(target_os = "linux")]
97 {
98 use std::process::Command;
99
100 let handlers = ["xdg-open", "gnome-open", "kde-open", "x-www-browser"];
101
102 let mut last_error = String::new();
103
104 for handler in handlers.iter() {
105 let result = Command::new(handler).arg(url_str).output();
106
107 match result {
108 Ok(output) if output.status.success() => {
109 dev_log!("lifecycle", "opened with {}", handler);
110
111 break;
112 },
113
114 Err(e) => {
115 last_error = e.to_string();
116
117 continue;
118 },
119
120 _ => continue,
121 }
122 }
123
124 if !last_error.is_empty() {
125 return Err(format!("Failed to open URL with any handler: {}", last_error));
126 }
127 }
128
129 dev_log!("lifecycle", "opened URL: {}", url_str);
130
131 Ok(Value::Bool(true))
132}