tauri_plugin_shell/
lib.rs1#![doc(
8 html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png",
9 html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
10)]
11
12use std::{
13 collections::HashMap,
14 ffi::OsStr,
15 path::Path,
16 sync::{Arc, Mutex},
17};
18
19use process::{Command, CommandChild};
20use regex::Regex;
21use tauri::{
22 plugin::{Builder, TauriPlugin},
23 AppHandle, Manager, RunEvent, Runtime,
24};
25
26mod commands;
27mod config;
28mod error;
29#[deprecated(since = "2.1.0", note = "Use tauri-plugin-opener instead.")]
30#[allow(deprecated)]
31pub mod open;
32pub mod process;
33mod scope;
34mod scope_entry;
35
36pub use error::Error;
37type Result<T> = std::result::Result<T, Error>;
38
39#[cfg(mobile)]
40use tauri::plugin::PluginHandle;
41#[cfg(target_os = "android")]
42const PLUGIN_IDENTIFIER: &str = "app.tauri.shell";
43#[cfg(target_os = "ios")]
44tauri::ios_plugin_binding!(init_plugin_shell);
45
46type ChildStore = Arc<Mutex<HashMap<u32, CommandChild>>>;
47
48pub struct Shell<R: Runtime> {
49 #[allow(dead_code)]
50 app: AppHandle<R>,
51 #[cfg(mobile)]
52 mobile_plugin_handle: PluginHandle<R>,
53 open_scope: scope::OpenScope,
54 children: ChildStore,
55}
56
57impl<R: Runtime> Shell<R> {
58 pub fn command(&self, program: impl AsRef<OsStr>) -> Command {
60 Command::new(program)
61 }
62
63 pub fn sidecar(&self, program: impl AsRef<Path>) -> Result<Command> {
68 Command::new_sidecar(program)
69 }
70
71 #[cfg(desktop)]
75 #[deprecated(since = "2.1.0", note = "Use tauri-plugin-opener instead.")]
76 #[allow(deprecated)]
77 pub fn open(&self, path: impl Into<String>, with: Option<open::Program>) -> Result<()> {
78 open::open(&self.open_scope, path.into(), with).map_err(Into::into)
79 }
80
81 #[cfg(mobile)]
85 #[deprecated(since = "2.1.0", note = "Use tauri-plugin-opener instead.")]
86 pub fn open(&self, path: impl Into<String>, _with: Option<open::Program>) -> Result<()> {
87 self.mobile_plugin_handle
88 .run_mobile_plugin("open", path.into())
89 .map_err(Into::into)
90 }
91}
92
93pub trait ShellExt<R: Runtime> {
94 fn shell(&self) -> &Shell<R>;
95}
96
97impl<R: Runtime, T: Manager<R>> ShellExt<R> for T {
98 fn shell(&self) -> &Shell<R> {
99 self.state::<Shell<R>>().inner()
100 }
101}
102
103pub fn init<R: Runtime>() -> TauriPlugin<R, Option<config::Config>> {
104 Builder::<R, Option<config::Config>>::new("shell")
105 .js_init_script(include_str!("init-iife.js").to_string())
106 .invoke_handler(tauri::generate_handler![
107 commands::execute,
108 commands::spawn,
109 commands::stdin_write,
110 commands::kill,
111 commands::open
112 ])
113 .setup(|app, api| {
114 let default_config = config::Config::default();
115 let config = api.config().as_ref().unwrap_or(&default_config);
116
117 #[cfg(target_os = "android")]
118 let handle = api.register_android_plugin(PLUGIN_IDENTIFIER, "ShellPlugin")?;
119 #[cfg(target_os = "ios")]
120 let handle = api.register_ios_plugin(init_plugin_shell)?;
121
122 app.manage(Shell {
123 app: app.clone(),
124 children: Default::default(),
125 open_scope: open_scope(&config.open),
126
127 #[cfg(mobile)]
128 mobile_plugin_handle: handle,
129 });
130 Ok(())
131 })
132 .on_event(|app, event| {
133 if let RunEvent::Exit = event {
134 let shell = app.state::<Shell<R>>();
135 let children = {
136 let mut lock = shell.children.lock().unwrap();
137 std::mem::take(&mut *lock)
138 };
139 for child in children.into_values() {
140 let _ = child.kill();
141 }
142 }
143 })
144 .build()
145}
146
147fn open_scope(open: &config::ShellAllowlistOpen) -> scope::OpenScope {
148 let shell_scope_open = match open {
149 config::ShellAllowlistOpen::Flag(false) => None,
150 config::ShellAllowlistOpen::Flag(true) => {
151 Some(Regex::new(r"^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+").unwrap())
152 }
153 config::ShellAllowlistOpen::Validate(validator) => {
154 let regex = format!("^{validator}$");
155 let validator =
156 Regex::new(®ex).unwrap_or_else(|e| panic!("invalid regex {regex}: {e}"));
157 Some(validator)
158 }
159 };
160
161 scope::OpenScope {
162 open: shell_scope_open,
163 }
164}