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 Box::pin(async move {
16 let uri = Parameters
17 .get(0)
18 .and_then(Value::as_str)
19 .unwrap_or("")
20 .to_string();
21 let lower = uri.to_ascii_lowercase();
22 const BlockedSchemes:&[&str] =
23 &["javascript:", "data:", "vbscript:", "file:"];
24 for scheme in BlockedSchemes {
25 if lower.starts_with(scheme) {
26 dev_log!(
27 "ipc",
28 "warn: [NativeHost.OpenExternal] rejected scheme '{}': {}",
29 scheme,
30 uri
31 );
32 return Err(format!(
33 "NativeHost.OpenExternal: scheme '{}' is not allowed",
34 scheme
35 ));
36 }
37 }
38 if uri.is_empty() {
39 return Err("NativeHost.OpenExternal: empty URI".to_string());
40 }
41 let uri_owned = uri.clone();
42 let result =
43 tokio::task::spawn_blocking(move || open::that_detached(uri_owned))
44 .await
45 .map_err(|e| format!("NativeHost.OpenExternal join error: {}", e))?;
46 match result {
47 Ok(()) => {
48 dev_log!("ipc", "[NativeHost.OpenExternal] opened {}", uri);
49 Ok(json!(true))
50 },
51 Err(e) => {
52 dev_log!(
53 "ipc",
54 "warn: [NativeHost.OpenExternal] failed uri={} error={}",
55 uri,
56 e
57 );
58 Err(e.to_string())
59 },
60 }
61 })
62 };
63 Some(Ok(Box::new(effect)))
64 },
65
66 _ => None,
67 }
68}