Mountain/Track/Effect/CreateEffectForRequest/
NativeHost.rs1#![allow(non_snake_case, unused_variables, dead_code, unused_imports)]
2
3use std::{future::Future, pin::Pin, sync::Arc};
4
5use serde_json::{Value, json};
6use tauri::Runtime;
7
8use crate::{RunTime::ApplicationRunTime::ApplicationRunTime, Track::Effect::MappedEffectType::MappedEffect, dev_log};
9
10pub fn CreateEffect<R:Runtime>(MethodName:&str, Parameters:Value) -> Option<Result<MappedEffect, String>> {
11 match MethodName {
12 "NativeHost.OpenExternal" => {
13 let effect =
14 move |_run_time:Arc<ApplicationRunTime>| -> Pin<Box<dyn Future<Output = Result<Value, String>> + Send>> {
15
16 Box::pin(async move {
17 let uri = Parameters
18 .get(0)
19 .and_then(Value::as_str)
20 .unwrap_or("")
21 .to_string();
22 let lower = uri.to_ascii_lowercase();
23 const BlockedSchemes:&[&str] =
24 &["javascript:", "data:", "vbscript:", "file:"];
25 for scheme in BlockedSchemes {
26 if lower.starts_with(scheme) {
27 dev_log!(
28 "ipc",
29
30 "warn: [NativeHost.OpenExternal] rejected scheme '{}': {}",
31
32 scheme,
33
34 uri
35 );
36 return Err(format!(
37 "NativeHost.OpenExternal: scheme '{}' is not allowed",
38
39 scheme
40 ));
41 }
42 }
43 if uri.is_empty() {
44 return Err("NativeHost.OpenExternal: empty URI".to_string());
45 }
46 let uri_owned = uri.clone();
47 let result =
48 tokio::task::spawn_blocking(move || open::that_detached(uri_owned))
49 .await
50 .map_err(|e| format!("NativeHost.OpenExternal join error: {}", e))?;
51 match result {
52 Ok(()) => {
53 dev_log!("ipc", "[NativeHost.OpenExternal] opened {}", uri);
54 Ok(json!(true))
55 },
56 Err(e) => {
57 dev_log!(
58 "ipc",
59
60 "warn: [NativeHost.OpenExternal] failed uri={} error={}",
61
62 uri,
63
64 e
65 );
66 Err(e.to_string())
67 },
68 }
69 })
70 };
71
72 Some(Ok(Box::new(effect)))
73 },
74
75 _ => None,
76 }
77}