tauri: Replace portmaster plugin with interface

This commit is contained in:
Vladimir Stoilov 2024-04-23 15:48:04 +03:00
parent 338abd6090
commit 7ee1faa68c
No known key found for this signature in database
GPG key ID: 2F190B67A43A81AF
6 changed files with 1906 additions and 18857 deletions

File diff suppressed because it is too large Load diff

View file

@ -37,13 +37,13 @@
"@fortawesome/free-brands-svg-icons": "^6.4.0",
"@fortawesome/free-regular-svg-icons": "^6.4.0",
"@fortawesome/free-solid-svg-icons": "^6.4.0",
"@tauri-apps/api": "^2.0.0-beta.3",
"@tauri-apps/plugin-cli": "^2.0.0-beta.1",
"@tauri-apps/plugin-clipboard-manager": "^2.0.0-alpha.4",
"@tauri-apps/plugin-dialog": "^2.0.0-alpha.4",
"@tauri-apps/plugin-notification": "^2.0.0-alpha.4",
"@tauri-apps/plugin-os": "^2.0.0-alpha.5",
"@tauri-apps/plugin-shell": "^2.0.0-alpha.4",
"@tauri-apps/api": ">=2.0.0-beta.0",
"@tauri-apps/plugin-cli": ">=2.0.0-beta.0",
"@tauri-apps/plugin-clipboard-manager": ">=2.0.0-beta.0",
"@tauri-apps/plugin-dialog": ">=2.0.0-beta.0",
"@tauri-apps/plugin-notification": ">=2.0.0-beta.0",
"@tauri-apps/plugin-os": ">=2.0.0-beta.0",
"@tauri-apps/plugin-shell": "^2.0.0-beta",
"autoprefixer": "^10.4.14",
"d3": "^7.8.4",
"data-urls": "^5.0.0",
@ -101,4 +101,4 @@
"webpack-ext-reloader": "^1.1.9",
"zip-a-folder": "^1.1.5"
}
}
}

View file

@ -75,7 +75,7 @@ export class TauriIntegrationService implements IntegrationService {
}
getAppInfo(info: ProcessInfo): Promise<AppInfo> {
return asyncInvoke("plugin:portmaster|get_app_info", {
return asyncInvoke("get_app_info", {
...info,
})
}
@ -112,7 +112,7 @@ export class TauriIntegrationService implements IntegrationService {
async shouldShow(): Promise<boolean> {
try {
const response = await invoke<string>("plugin:portmaster|should_show");
const response = await invoke<string>("should_show");
return response === "show";
} catch (err) {
console.error(err);
@ -122,7 +122,7 @@ export class TauriIntegrationService implements IntegrationService {
async shouldHandlePrompts(): Promise<boolean> {
try {
const response = await invoke<string>("plugin:portmaster|should_handle_prompts")
const response = await invoke<string>("should_handle_prompts")
return response === "true"
} catch (err) {
console.error(err);
@ -131,22 +131,22 @@ export class TauriIntegrationService implements IntegrationService {
}
get_state(key: string): Promise<string> {
return invoke<string>("plugin:portmaster|get_state");
return invoke<string>("get_state");
}
set_state(key: string, value: string): Promise<void> {
return invoke<void>("plugin:portmaster|set_state", {
return invoke<void>("set_state", {
key,
value
})
}
getServiceManagerStatus(): Promise<ServiceManagerStatus> {
return asyncInvoke("plugin:portmaster|get_service_manager_status", {})
return asyncInvoke("get_service_manager_status", {})
}
startService(): Promise<any> {
return asyncInvoke("plugin:portmaster|start_service", {});
return asyncInvoke("start_service", {});
}
onExitRequest(cb: () => void): () => void {

View file

@ -102,16 +102,24 @@ fn main() {
.plugin(tauri_plugin_cli::init())
// Notification support
.plugin(tauri_plugin_notification::init())
// Our Portmaster Plugin that handles communication between tauri and our angular app.
.plugin(portmaster::init())
.invoke_handler(tauri::generate_handler![
portmaster::commands::get_app_info,
portmaster::commands::get_service_manager_status,
portmaster::commands::start_service,
portmaster::commands::get_state,
portmaster::commands::set_state,
portmaster::commands::should_show,
portmaster::commands::should_handle_prompts
])
// Setup the app an any listeners
.setup(|app| {
setup_tray_menu(app)?;
portmaster::setup(app.handle().clone());
// Setup the single-instance event listener that will create/focus the main window
// or the splash-screen.
let handle = app.handle().clone();
app.listen("single-instance", move |_event| {
app.listen_any("single-instance", move |_event| {
let _ = window::open_window(&handle);
});
@ -197,7 +205,12 @@ fn main() {
api.prevent_close();
if let Some(window) = handle.get_webview_window(label.as_str()) {
let _ = window.emit("exit-requested", "");
let result = window.emit("exit-requested", "");
if let Err(err) = result {
error!("failed to emit event: {}", err.to_string());
}
} else {
error!("window was None");
}
}
_ => {}

View file

@ -1,4 +1,4 @@
use super::PortmasterPlugin;
use super::PortmasterInterface;
use crate::service::get_service_manager;
use crate::service::ServiceManager;
use log::debug;
@ -15,7 +15,7 @@ pub struct Error {
#[tauri::command]
pub fn should_show<R: Runtime>(
_window: Window<R>,
portmaster: State<'_, PortmasterPlugin<R>>,
portmaster: State<'_, PortmasterInterface<R>>,
) -> Result {
if portmaster.get_show_after_bootstrap() {
debug!("[tauri:rpc:should_show] application should show after bootstrap");
@ -31,7 +31,7 @@ pub fn should_show<R: Runtime>(
#[tauri::command]
pub fn should_handle_prompts<R: Runtime>(
_window: Window<R>,
portmaster: State<'_, PortmasterPlugin<R>>,
portmaster: State<'_, PortmasterInterface<R>>,
) -> Result {
if portmaster.handle_prompts.load(Ordering::Relaxed) {
Ok("true".to_string())
@ -43,7 +43,7 @@ pub fn should_handle_prompts<R: Runtime>(
#[tauri::command]
pub fn get_state<R: Runtime>(
_window: Window<R>,
portmaster: State<'_, PortmasterPlugin<R>>,
portmaster: State<'_, PortmasterInterface<R>>,
key: String,
) -> Result {
let value = portmaster.get_state(key);
@ -58,7 +58,7 @@ pub fn get_state<R: Runtime>(
#[tauri::command]
pub fn set_state<R: Runtime>(
_window: Window<R>,
portmaster: State<'_, PortmasterPlugin<R>>,
portmaster: State<'_, PortmasterInterface<R>>,
key: String,
value: String,
) -> Result {

View file

@ -13,7 +13,7 @@
/// in the crate root.
// The commands module contains tauri commands that are available to Javascript
// using the invoke() and our custom invokeAsync() command.
mod commands;
pub mod commands;
// The websocket module spawns an async function on tauri's runtime that manages
// a persistent connection to the Portmaster websocket API and updates the tauri Portmaster
@ -34,10 +34,7 @@ use std::{
use log::{debug, error};
use serde;
use std::sync::Mutex;
use tauri::{
plugin::{Builder, TauriPlugin},
AppHandle, Manager, Runtime,
};
use tauri::{AppHandle, EventTarget, Manager, Runtime};
pub trait Handler {
fn on_connect(&mut self, cli: PortAPI) -> ();
@ -45,7 +42,7 @@ pub trait Handler {
fn name(&self) -> String;
}
pub struct PortmasterPlugin<R: Runtime> {
pub struct PortmasterInterface<R: Runtime> {
#[allow(dead_code)]
app: AppHandle<R>,
@ -76,7 +73,7 @@ pub struct PortmasterPlugin<R: Runtime> {
should_show_after_bootstrap: AtomicBool,
}
impl<R: Runtime> PortmasterPlugin<R> {
impl<R: Runtime> PortmasterInterface<R> {
/// Returns a state stored in the portmaster plugin.
pub fn get_state(&self, key: String) -> Option<String> {
let map = self.state.lock();
@ -118,7 +115,7 @@ impl<R: Runtime> PortmasterPlugin<R> {
handler.on_connect(api);
} else {
debug!("not yet connected to Portmaster API, calling on_disconnect()");
debug!("not yet connected to Portmaster API, calling on_disconnect()");
handler.on_disconnect();
}
@ -174,7 +171,7 @@ impl<R: Runtime> PortmasterPlugin<R> {
self.should_show_after_bootstrap.load(Ordering::Relaxed)
}
/// Tells the angular applicatoin to show the window by emitting an event.
/// Tells the angular application to show the window by emitting an event.
/// It calls set_show_after_bootstrap(true) automatically so the application
/// also shows after bootstrapping.
pub fn show_window(&self) {
@ -184,8 +181,9 @@ impl<R: Runtime> PortmasterPlugin<R> {
// misses the event below because it's still bootstrapping.
self.set_show_after_bootstrap(true);
// ignore the error here, there's nothing we could do about it anyways.
let _ = self.app.emit("portmaster:show", "");
if let Err(err) = self.app.emit("portmaster:show", "") {
error!("failed to emit show event: {}", err.to_string());
}
}
/// Enables or disables the SPN.
@ -262,47 +260,32 @@ impl<R: Runtime> PortmasterPlugin<R> {
}
pub trait PortmasterExt<R: Runtime> {
fn portmaster(&self) -> &PortmasterPlugin<R>;
fn portmaster(&self) -> &PortmasterInterface<R>;
}
#[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct Config {}
impl<R: Runtime, T: Manager<R>> PortmasterExt<R> for T {
fn portmaster(&self) -> &PortmasterPlugin<R> {
self.state::<PortmasterPlugin<R>>().inner()
fn portmaster(&self) -> &PortmasterInterface<R> {
self.state::<PortmasterInterface<R>>().inner()
}
}
pub fn init<R: Runtime>() -> TauriPlugin<R, Option<Config>> {
Builder::<R, Option<Config>>::new("portmaster")
.invoke_handler(tauri::generate_handler![
commands::get_app_info,
commands::get_service_manager_status,
commands::start_service,
commands::get_state,
commands::set_state,
commands::should_show,
commands::should_handle_prompts
])
.setup(|app, _api| {
let plugin = PortmasterPlugin {
app: app.clone(),
state: Mutex::new(HashMap::new()),
is_reachable: AtomicBool::new(false),
handlers: Mutex::new(Vec::new()),
api: Mutex::new(None),
handle_notifications: AtomicBool::new(false),
handle_prompts: AtomicBool::new(false),
should_show_after_bootstrap: AtomicBool::new(true),
};
pub fn setup(app: AppHandle) {
let interface = PortmasterInterface {
app: app.clone(),
state: Mutex::new(HashMap::new()),
is_reachable: AtomicBool::new(false),
handlers: Mutex::new(Vec::new()),
api: Mutex::new(None),
handle_notifications: AtomicBool::new(false),
handle_prompts: AtomicBool::new(false),
should_show_after_bootstrap: AtomicBool::new(true),
};
app.manage(plugin);
app.manage(interface);
// fire of the websocket handler
websocket::start_websocket_thread(app.clone());
Ok(())
})
.build()
// fire of the websocket handler
websocket::start_websocket_thread(app.clone());
}