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