mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-09-26 21:41:48 +02:00
chore: edition 2024
This commit is contained in:
+1
-1
@@ -26,7 +26,7 @@ glob = "0.3"
|
|||||||
zbus = "5.9"
|
zbus = "5.9"
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
authors = ["Tauri Programme within The Commons Conservancy"]
|
authors = ["Tauri Programme within The Commons Conservancy"]
|
||||||
license = "Apache-2.0 OR MIT"
|
license = "Apache-2.0 OR MIT"
|
||||||
rust-version = "1.90"
|
rust-version = "1.90"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ name = "api"
|
|||||||
publish = false
|
publish = false
|
||||||
version = "2.0.49"
|
version = "2.0.49"
|
||||||
description = "An example Tauri Application showcasing the api"
|
description = "An example Tauri Application showcasing the api"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
license = "Apache-2.0 OR MIT"
|
license = "Apache-2.0 OR MIT"
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ mod tray;
|
|||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
webview::{PageLoadEvent, WebviewWindowBuilder},
|
|
||||||
App, AppHandle, Emitter, Listener, RunEvent, WebviewUrl,
|
App, AppHandle, Emitter, Listener, RunEvent, WebviewUrl,
|
||||||
|
webview::{PageLoadEvent, WebviewWindowBuilder},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Serialize)]
|
#[derive(Clone, Serialize)]
|
||||||
@@ -204,12 +204,11 @@ pub fn run() {
|
|||||||
|
|
||||||
app.run(move |_app_handle, _event| {
|
app.run(move |_app_handle, _event| {
|
||||||
#[cfg(desktop)]
|
#[cfg(desktop)]
|
||||||
if let RunEvent::ExitRequested { code, api, .. } = &_event {
|
if let RunEvent::ExitRequested { code, api, .. } = &_event
|
||||||
if code.is_none() {
|
&& code.is_none() {
|
||||||
// Keep the event loop running even if all windows are closed
|
// Keep the event loop running even if all windows are closed
|
||||||
// This allow us to catch system tray events when there is no window
|
// This allow us to catch system tray events when there is no window
|
||||||
api.prevent_exit();
|
api.prevent_exit();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
|
Manager, Runtime, WebviewUrl, WebviewWindowBuilder,
|
||||||
menu::{Menu, MenuItem},
|
menu::{Menu, MenuItem},
|
||||||
tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
|
tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
|
||||||
Manager, Runtime, WebviewUrl, WebviewWindowBuilder,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn create_tray<R: Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result<()> {
|
pub fn create_tray<R: Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result<()> {
|
||||||
|
|||||||
@@ -11,11 +11,10 @@
|
|||||||
#![cfg(not(any(target_os = "android", target_os = "ios")))]
|
#![cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
|
|
||||||
use auto_launch::{AutoLaunch, AutoLaunchBuilder};
|
use auto_launch::{AutoLaunch, AutoLaunchBuilder};
|
||||||
use serde::{ser::Serializer, Serialize};
|
use serde::{Serialize, ser::Serializer};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
command,
|
Manager, Runtime, State, command,
|
||||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||||
Manager, Runtime, State,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::env::current_exe;
|
use std::env::current_exe;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::{ser::Serializer, Serialize};
|
use serde::{Serialize, ser::Serializer};
|
||||||
|
|
||||||
/// Alias for the result type returned by this crate's functions.
|
/// Alias for the result type returned by this crate's functions.
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
#![cfg(mobile)]
|
#![cfg(mobile)]
|
||||||
|
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, PluginHandle, TauriPlugin},
|
|
||||||
Manager, Runtime,
|
Manager, Runtime,
|
||||||
|
plugin::{Builder, PluginHandle, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use models::*;
|
pub use models::*;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::{ser::Serializer, Serialize};
|
use serde::{Serialize, ser::Serializer};
|
||||||
|
|
||||||
/// Alias for a [`Result`](std::result::Result) with the error type [`Error`].
|
/// Alias for a [`Result`](std::result::Result) with the error type [`Error`].
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, PluginHandle, TauriPlugin},
|
|
||||||
Manager, Runtime,
|
Manager, Runtime,
|
||||||
|
plugin::{Builder, PluginHandle, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use models::*;
|
pub use models::*;
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
)]
|
)]
|
||||||
|
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, PluginApi, TauriPlugin},
|
|
||||||
AppHandle, Manager, Runtime, State,
|
AppHandle, Manager, Runtime, State,
|
||||||
|
plugin::{Builder, PluginApi, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use clap::{
|
use clap::{
|
||||||
|
Arg as ClapArg, ArgAction, ArgMatches, Command,
|
||||||
builder::{PossibleValue, PossibleValuesParser},
|
builder::{PossibleValue, PossibleValuesParser},
|
||||||
error::ErrorKind,
|
error::ErrorKind,
|
||||||
Arg as ClapArg, ArgAction, ArgMatches, Command,
|
|
||||||
};
|
};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
@@ -134,8 +134,8 @@ fn get_matches_internal(config: &Config, matches: &ArgMatches) -> Matches {
|
|||||||
let mut cli_matches = Matches::default();
|
let mut cli_matches = Matches::default();
|
||||||
map_matches(config, matches, &mut cli_matches);
|
map_matches(config, matches, &mut cli_matches);
|
||||||
|
|
||||||
if let Some((subcommand_name, subcommand_matches)) = matches.subcommand() {
|
if let Some((subcommand_name, subcommand_matches)) = matches.subcommand()
|
||||||
if let Some(subcommand_config) = config
|
&& let Some(subcommand_config) = config
|
||||||
.subcommands
|
.subcommands
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|s| s.get(subcommand_name))
|
.and_then(|s| s.get(subcommand_name))
|
||||||
@@ -145,7 +145,6 @@ fn get_matches_internal(config: &Config, matches: &ArgMatches) -> Matches {
|
|||||||
get_matches_internal(subcommand_config, subcommand_matches),
|
get_matches_internal(subcommand_config, subcommand_matches),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
cli_matches
|
cli_matches
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use tauri::{command, image::JsImage, AppHandle, Manager, ResourceId, Runtime, State, Webview};
|
use tauri::{AppHandle, Manager, ResourceId, Runtime, State, Webview, command, image::JsImage};
|
||||||
|
|
||||||
use crate::{Clipboard, Result};
|
use crate::{Clipboard, Result};
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
use arboard::ImageData;
|
use arboard::ImageData;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use tauri::{image::Image, plugin::PluginApi, AppHandle, Runtime};
|
use tauri::{AppHandle, Runtime, image::Image, plugin::PluginApi};
|
||||||
|
|
||||||
use std::{borrow::Cow, sync::Mutex};
|
use std::{borrow::Cow, sync::Mutex};
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::{ser::Serializer, Serialize};
|
use serde::{Serialize, ser::Serializer};
|
||||||
|
|
||||||
/// Alias for `Result<T, Error>` used throughout this crate.
|
/// Alias for `Result<T, Error>` used throughout this crate.
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
)]
|
)]
|
||||||
|
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, TauriPlugin},
|
|
||||||
Manager, RunEvent, Runtime,
|
Manager, RunEvent, Runtime,
|
||||||
|
plugin::{Builder, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(desktop)]
|
#[cfg(desktop)]
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
|
AppHandle, Runtime,
|
||||||
image::Image,
|
image::Image,
|
||||||
plugin::{PluginApi, PluginHandle},
|
plugin::{PluginApi, PluginHandle},
|
||||||
AppHandle, Runtime,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ description = "A Tauri App"
|
|||||||
authors = ["you"]
|
authors = ["you"]
|
||||||
license = ""
|
license = ""
|
||||||
repository = ""
|
repository = ""
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
rust-version = "1.90"
|
rust-version = "1.90"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use tauri::{command, AppHandle, Runtime, State, Window};
|
use tauri::{AppHandle, Runtime, State, Window, command};
|
||||||
|
|
||||||
use crate::{DeepLink, Result};
|
use crate::{DeepLink, Result};
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,9 @@ impl AssociatedDomain {
|
|||||||
}
|
}
|
||||||
if self.scheme.iter().any(|s| s == "http") && !self.scheme.iter().any(|s| s == "https")
|
if self.scheme.iter().any(|s| s == "http") && !self.scheme.iter().any(|s| s == "https")
|
||||||
{
|
{
|
||||||
eprintln!("Warning: AppLink uses only 'http' — allowed on Android but not secure for production.");
|
eprintln!(
|
||||||
|
"Warning: AppLink uses only 'http' — allowed on Android but not secure for production."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,13 +70,12 @@ where
|
|||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
let opt = Option::<String>::deserialize(deserializer)?;
|
let opt = Option::<String>::deserialize(deserializer)?;
|
||||||
if let Some(ref host) = opt {
|
if let Some(ref host) = opt
|
||||||
if let Some((scheme, _)) = host.split_once("://") {
|
&& let Some((scheme, _)) = host.split_once("://") {
|
||||||
return Err(serde::de::Error::custom(format!(
|
return Err(serde::de::Error::custom(format!(
|
||||||
"host `{host}` cannot start with a scheme, please remove the `{scheme}://` prefix"
|
"host `{host}` cannot start with a scheme, please remove the `{scheme}://` prefix"
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(opt)
|
Ok(opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::{ser::Serializer, Serialize};
|
use serde::{Serialize, ser::Serializer};
|
||||||
|
|
||||||
/// Alias for a [`Result`](std::result::Result) with the error type [`Error`].
|
/// Alias for a [`Result`](std::result::Result) with the error type [`Error`].
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
//! calling those methods returns [`Error::UnsupportedPlatform`].
|
//! calling those methods returns [`Error::UnsupportedPlatform`].
|
||||||
|
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, PluginApi, TauriPlugin},
|
|
||||||
AppHandle, EventId, Listener, Manager, Runtime,
|
AppHandle, EventId, Listener, Manager, Runtime,
|
||||||
|
plugin::{Builder, PluginApi, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
@@ -33,8 +33,8 @@ fn init_deep_link<R: Runtime>(
|
|||||||
let _api = api;
|
let _api = api;
|
||||||
|
|
||||||
use tauri::{
|
use tauri::{
|
||||||
ipc::{Channel, InvokeResponseBody},
|
|
||||||
Emitter,
|
Emitter,
|
||||||
|
ipc::{Channel, InvokeResponseBody},
|
||||||
};
|
};
|
||||||
|
|
||||||
let handle = _api.register_android_plugin(PLUGIN_IDENTIFIER, "DeepLinkPlugin")?;
|
let handle = _api.register_android_plugin(PLUGIN_IDENTIFIER, "DeepLinkPlugin")?;
|
||||||
@@ -94,7 +94,7 @@ fn init_deep_link<R: Runtime>(
|
|||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
mod imp {
|
mod imp {
|
||||||
use tauri::{ipc::Channel, plugin::PluginHandle, AppHandle, Runtime};
|
use tauri::{AppHandle, Runtime, ipc::Channel, plugin::PluginHandle};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ mod imp {
|
|||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use std::{
|
use std::{
|
||||||
fs::{create_dir_all, File},
|
fs::{File, create_dir_all},
|
||||||
io::Write,
|
io::Write,
|
||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
@@ -223,7 +223,9 @@ mod imp {
|
|||||||
current.replace(vec![url.clone()]);
|
current.replace(vec![url.clone()]);
|
||||||
let _ = self.app.emit("deep-link://new-url", vec![url]);
|
let _ = self.app.emit("deep-link://new-url", vec![url]);
|
||||||
} else if cfg!(debug_assertions) {
|
} else if cfg!(debug_assertions) {
|
||||||
tracing::warn!("argument {url} does not match any configured deep link scheme; skipping it");
|
tracing::warn!(
|
||||||
|
"argument {url} does not match any configured deep link scheme; skipping it"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -414,11 +416,10 @@ mod imp {
|
|||||||
let mimeapps_path = self.app.path().config_dir()?.join("mimeapps.list");
|
let mimeapps_path = self.app.path().config_dir()?.join("mimeapps.list");
|
||||||
if mimeapps_path.exists() {
|
if mimeapps_path.exists() {
|
||||||
let mut mimeapps = ini::Ini::load_from_file(&mimeapps_path)?;
|
let mut mimeapps = ini::Ini::load_from_file(&mimeapps_path)?;
|
||||||
if let Some(section) = mimeapps.section_mut(Some("Default Applications")) {
|
if let Some(section) = mimeapps.section_mut(Some("Default Applications"))
|
||||||
if section.get(&mime_type).unwrap_or_default() == file_name {
|
&& section.get(&mime_type).unwrap_or_default() == file_name {
|
||||||
section.remove(&mime_type);
|
section.remove(&mime_type);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
mimeapps.write_to_file(&mimeapps_path)?;
|
mimeapps.write_to_file(&mimeapps_path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -558,16 +559,16 @@ impl<R: Runtime> DeepLink<R> {
|
|||||||
///
|
///
|
||||||
/// Use `get_current` on app load to check whether your app was started via a deep link.
|
/// Use `get_current` on app load to check whether your app was started via a deep link.
|
||||||
pub fn on_open_url<F: Fn(OpenUrlEvent) + Send + Sync + 'static>(&self, f: F) -> EventId {
|
pub fn on_open_url<F: Fn(OpenUrlEvent) + Send + Sync + 'static>(&self, f: F) -> EventId {
|
||||||
let event_id = self.app.listen("deep-link://new-url", move |event| {
|
|
||||||
|
|
||||||
|
self.app.listen("deep-link://new-url", move |event| {
|
||||||
if let Ok(urls) = serde_json::from_str(event.payload()) {
|
if let Ok(urls) = serde_json::from_str(event.payload()) {
|
||||||
f(OpenUrlEvent {
|
f(OpenUrlEvent {
|
||||||
id: event.id(),
|
id: event.id(),
|
||||||
urls,
|
urls,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
event_id
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tauri::{command, Manager, Runtime, State, Window};
|
use tauri::{Manager, Runtime, State, Window, command};
|
||||||
use tauri_plugin_fs::FsExt;
|
use tauri_plugin_fs::FsExt;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -171,14 +171,13 @@ pub(crate) async fn open<R: Runtime>(
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let folder = dialog_builder.blocking_pick_folder();
|
let folder = dialog_builder.blocking_pick_folder();
|
||||||
if let Some(folder) = &folder {
|
if let Some(folder) = &folder
|
||||||
if let Ok(path) = folder.clone().into_path() {
|
&& let Ok(path) = folder.clone().into_path() {
|
||||||
if let Some(s) = window.try_fs_scope() {
|
if let Some(s) = window.try_fs_scope() {
|
||||||
s.allow_directory(&path, options.recursive)?;
|
s.allow_directory(&path, options.recursive)?;
|
||||||
}
|
}
|
||||||
tauri_scope.allow_directory(&path, options.directory)?;
|
tauri_scope.allow_directory(&path, options.directory)?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
OpenResponse::Folder(folder.map(|p| p.simplified()))
|
OpenResponse::Folder(folder.map(|p| p.simplified()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,14 +203,13 @@ pub(crate) async fn open<R: Runtime>(
|
|||||||
let tauri_scope = window.state::<tauri::scope::Scopes>();
|
let tauri_scope = window.state::<tauri::scope::Scopes>();
|
||||||
let file = dialog_builder.blocking_pick_file();
|
let file = dialog_builder.blocking_pick_file();
|
||||||
|
|
||||||
if let Some(file) = &file {
|
if let Some(file) = &file
|
||||||
if let Ok(path) = file.clone().into_path() {
|
&& let Ok(path) = file.clone().into_path() {
|
||||||
if let Some(s) = window.try_fs_scope() {
|
if let Some(s) = window.try_fs_scope() {
|
||||||
s.allow_file(&path)?;
|
s.allow_file(&path)?;
|
||||||
}
|
}
|
||||||
tauri_scope.allow_file(&path)?;
|
tauri_scope.allow_file(&path)?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
OpenResponse::File(file.map(|f| f.simplified()))
|
OpenResponse::File(file.map(|f| f.simplified()))
|
||||||
};
|
};
|
||||||
Ok(res)
|
Ok(res)
|
||||||
@@ -246,14 +244,13 @@ pub(crate) async fn save<R: Runtime>(
|
|||||||
let tauri_scope = window.state::<tauri::scope::Scopes>();
|
let tauri_scope = window.state::<tauri::scope::Scopes>();
|
||||||
|
|
||||||
let path = dialog_builder.blocking_save_file();
|
let path = dialog_builder.blocking_save_file();
|
||||||
if let Some(p) = &path {
|
if let Some(p) = &path
|
||||||
if let Ok(path) = p.clone().into_path() {
|
&& let Ok(path) = p.clone().into_path() {
|
||||||
if let Some(s) = window.try_fs_scope() {
|
if let Some(s) = window.try_fs_scope() {
|
||||||
s.allow_file(&path)?;
|
s.allow_file(&path)?;
|
||||||
}
|
}
|
||||||
tauri_scope.allow_file(&path)?;
|
tauri_scope.allow_file(&path)?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(path.map(|p| p.simplified()))
|
Ok(path.map(|p| p.simplified()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,9 @@
|
|||||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
|
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
|
||||||
use rfd::{AsyncFileDialog, AsyncMessageDialog};
|
use rfd::{AsyncFileDialog, AsyncMessageDialog};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use tauri::{plugin::PluginApi, AppHandle, Runtime};
|
use tauri::{AppHandle, Runtime, plugin::PluginApi};
|
||||||
|
|
||||||
use crate::{models::*, FileDialogBuilder, FilePath, MessageDialogBuilder};
|
use crate::{FileDialogBuilder, FilePath, MessageDialogBuilder, models::*};
|
||||||
|
|
||||||
pub fn init<R: Runtime, C: DeserializeOwned>(
|
pub fn init<R: Runtime, C: DeserializeOwned>(
|
||||||
app: &AppHandle<R>,
|
app: &AppHandle<R>,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::{ser::Serializer, Serialize};
|
use serde::{Serialize, ser::Serializer};
|
||||||
|
|
||||||
/// Alias for `Result<T, Error>` used throughout this crate.
|
/// Alias for `Result<T, Error>` used throughout this crate.
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, TauriPlugin},
|
|
||||||
Manager, Runtime,
|
Manager, Runtime,
|
||||||
|
plugin::{Builder, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::{de::DeserializeOwned, Deserialize};
|
use serde::{Deserialize, de::DeserializeOwned};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{PluginApi, PluginHandle},
|
|
||||||
AppHandle, Runtime,
|
AppHandle, Runtime,
|
||||||
|
plugin::{PluginApi, PluginHandle},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{FileDialogBuilder, FilePath, MessageDialogBuilder, MessageDialogResult};
|
use crate::{FileDialogBuilder, FilePath, MessageDialogBuilder, MessageDialogResult};
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use tauri::{plugin::PluginApi, AppHandle, Runtime};
|
use tauri::{AppHandle, Runtime, plugin::PluginApi};
|
||||||
|
|
||||||
use crate::{models::*, FilePath, OpenOptions};
|
use crate::{FilePath, OpenOptions, models::*};
|
||||||
|
|
||||||
const PLUGIN_IDENTIFIER: &str = "com.plugin.fs";
|
const PLUGIN_IDENTIFIER: &str = "com.plugin.fs";
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
use serde::{Deserialize, Serialize, Serializer};
|
use serde::{Deserialize, Serialize, Serializer};
|
||||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
|
Manager, Resource, ResourceId, Runtime, Webview,
|
||||||
ipc::{CommandScope, GlobalScope},
|
ipc::{CommandScope, GlobalScope},
|
||||||
path::BaseDirectory,
|
path::BaseDirectory,
|
||||||
utils::config::FsScope,
|
utils::config::FsScope,
|
||||||
Manager, Resource, ResourceId, Runtime, Webview,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
@@ -23,7 +23,7 @@ use std::{
|
|||||||
time::{SystemTime, UNIX_EPOCH},
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{scope::Entry, Error, SafeFilePath};
|
use crate::{Error, SafeFilePath, scope::Entry};
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum CommandError {
|
pub enum CommandError {
|
||||||
@@ -175,7 +175,9 @@ impl<R: Runtime> Drop for FileHandle<R> {
|
|||||||
.stop_accessing_security_scoped_resource(FilePath::Url(url.clone()));
|
.stop_accessing_security_scoped_resource(FilePath::Url(url.clone()));
|
||||||
security_scoped_resources.remove(url.as_str());
|
security_scoped_resources.remove(url.as_str());
|
||||||
} else {
|
} else {
|
||||||
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)");
|
log::debug!(
|
||||||
|
"Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,7 +253,9 @@ impl<R: Runtime> Drop for PathHandle<R> {
|
|||||||
.stop_accessing_security_scoped_resource(FilePath::Url(url.clone()));
|
.stop_accessing_security_scoped_resource(FilePath::Url(url.clone()));
|
||||||
security_scoped_resources.remove(url.as_str());
|
security_scoped_resources.remove(url.as_str());
|
||||||
} else {
|
} else {
|
||||||
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)");
|
log::debug!(
|
||||||
|
"Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1530,7 +1534,10 @@ pub fn resolve_path<R: Runtime>(
|
|||||||
unsafe {
|
unsafe {
|
||||||
let success = ns_url.startAccessingSecurityScopedResource();
|
let success = ns_url.startAccessingSecurityScopedResource();
|
||||||
if success {
|
if success {
|
||||||
log::debug!("Started accessing security-scoped resource for URL: {} (via resolve_path)", url.as_str());
|
log::debug!(
|
||||||
|
"Started accessing security-scoped resource for URL: {} (via resolve_path)",
|
||||||
|
url.as_str()
|
||||||
|
);
|
||||||
// Track it so we know to clean it up
|
// Track it so we know to clean it up
|
||||||
security_scoped_resources.track_manually(url.as_str().to_string());
|
security_scoped_resources.track_manually(url.as_str().to_string());
|
||||||
} else {
|
} else {
|
||||||
@@ -1541,10 +1548,16 @@ pub fn resolve_path<R: Runtime>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::debug!("Failed to create NSURL from URL: {}, ignoring security-scoped resource access request", url.as_str());
|
log::debug!(
|
||||||
|
"Failed to create NSURL from URL: {}, ignoring security-scoped resource access request",
|
||||||
|
url.as_str()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::debug!("Security-scoped resource already active for URL: {} (started via start_accessing_security_scoped_resource), skipping", url.as_str());
|
log::debug!(
|
||||||
|
"Security-scoped resource already active for URL: {} (started via start_accessing_security_scoped_resource), skipping",
|
||||||
|
url.as_str()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,11 +190,10 @@ impl<'de> serde::Deserialize<'de> for SafeFilePath {
|
|||||||
impl FromStr for FilePath {
|
impl FromStr for FilePath {
|
||||||
type Err = Infallible;
|
type Err = Infallible;
|
||||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||||
if let Ok(url) = url::Url::from_str(s) {
|
if let Ok(url) = url::Url::from_str(s)
|
||||||
if url.scheme().len() != 1 {
|
&& url.scheme().len() != 1 {
|
||||||
return Ok(Self::Url(url));
|
return Ok(Self::Url(url));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(Self::Path(PathBuf::from(s)))
|
Ok(Self::Path(PathBuf::from(s)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,11 +201,10 @@ impl FromStr for FilePath {
|
|||||||
impl FromStr for SafeFilePath {
|
impl FromStr for SafeFilePath {
|
||||||
type Err = Error;
|
type Err = Error;
|
||||||
fn from_str(s: &str) -> Result<Self> {
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
if let Ok(url) = url::Url::from_str(s) {
|
if let Ok(url) = url::Url::from_str(s)
|
||||||
if url.scheme().len() != 1 {
|
&& url.scheme().len() != 1 {
|
||||||
return Ok(Self::Url(url));
|
return Ok(Self::Url(url));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
SafePathBuf::new(s.into())
|
SafePathBuf::new(s.into())
|
||||||
.map(SafeFilePath::Path)
|
.map(SafeFilePath::Path)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use tauri::{plugin::PluginApi, AppHandle, Runtime};
|
use tauri::{AppHandle, Runtime, plugin::PluginApi};
|
||||||
|
|
||||||
use crate::{FilePath, OpenOptions};
|
use crate::{FilePath, OpenOptions};
|
||||||
|
|
||||||
@@ -69,7 +69,10 @@ impl<R: Runtime> Fs<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::debug!("Failed to create NSURL from URL: {}, ignoring security-scoped resource access request", url_string);
|
log::debug!(
|
||||||
|
"Failed to create NSURL from URL: {}, ignoring security-scoped resource access request",
|
||||||
|
url_string
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert URL to path and open the file
|
// Convert URL to path and open the file
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ use std::sync::Mutex;
|
|||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
|
AppHandle, DragDropEvent, Manager, RunEvent, Runtime, WindowEvent,
|
||||||
ipc::ScopeObject,
|
ipc::ScopeObject,
|
||||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||||
utils::{acl::Value, config::FsScope},
|
utils::{acl::Value, config::FsScope},
|
||||||
AppHandle, DragDropEvent, Manager, RunEvent, Runtime, WindowEvent,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
|
|||||||
@@ -3,20 +3,20 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
|
use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
|
||||||
use notify_debouncer_full::{new_debouncer, DebouncedEvent, Debouncer, RecommendedCache};
|
use notify_debouncer_full::{DebouncedEvent, Debouncer, RecommendedCache, new_debouncer};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
|
Manager, Resource, ResourceId, Runtime, Webview,
|
||||||
ipc::{Channel, CommandScope, GlobalScope},
|
ipc::{Channel, CommandScope, GlobalScope},
|
||||||
path::BaseDirectory,
|
path::BaseDirectory,
|
||||||
Manager, Resource, ResourceId, Runtime, Webview,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commands::{resolve_path, CommandResult},
|
|
||||||
scope::Entry,
|
|
||||||
SafeFilePath,
|
SafeFilePath,
|
||||||
|
commands::{CommandResult, resolve_path},
|
||||||
|
scope::Entry,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use tauri::{command, ipc::Channel, AppHandle, Runtime};
|
use tauri::{AppHandle, Runtime, command, ipc::Channel};
|
||||||
|
|
||||||
use crate::{GeolocationExt, PermissionStatus, PermissionType, Position, PositionOptions, Result};
|
use crate::{GeolocationExt, PermissionStatus, PermissionType, Position, PositionOptions, Result};
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{Serialize, de::DeserializeOwned};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
|
AppHandle, Runtime,
|
||||||
ipc::{Channel, InvokeResponseBody},
|
ipc::{Channel, InvokeResponseBody},
|
||||||
plugin::PluginApi,
|
plugin::PluginApi,
|
||||||
AppHandle, Runtime,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::models::*;
|
use crate::models::*;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::{ser::Serializer, Serialize};
|
use serde::{Serialize, ser::Serializer};
|
||||||
|
|
||||||
/// Alias for the result type returned by the geolocation APIs.
|
/// Alias for the result type returned by the geolocation APIs.
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
//! - **specta**: Add support for [`specta::specta`](https://docs.rs/specta/2.0.0-rc.25/specta/attr.specta.html) on structs like [`PermissionStatus`], [`PositionOptions`].
|
//! - **specta**: Add support for [`specta::specta`](https://docs.rs/specta/2.0.0-rc.25/specta/attr.specta.html) on structs like [`PermissionStatus`], [`PositionOptions`].
|
||||||
|
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, TauriPlugin},
|
|
||||||
Manager, Runtime,
|
Manager, Runtime,
|
||||||
|
plugin::{Builder, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use models::*;
|
pub use models::*;
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{Serialize, de::DeserializeOwned};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
|
AppHandle, Runtime,
|
||||||
ipc::{Channel, InvokeResponseBody},
|
ipc::{Channel, InvokeResponseBody},
|
||||||
plugin::{PluginApi, PluginHandle},
|
plugin::{PluginApi, PluginHandle},
|
||||||
AppHandle, Runtime,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::models::*;
|
use crate::models::*;
|
||||||
|
|||||||
@@ -22,14 +22,14 @@ use std::{
|
|||||||
|
|
||||||
use global_hotkey::GlobalHotKeyEvent;
|
use global_hotkey::GlobalHotKeyEvent;
|
||||||
pub use global_hotkey::{
|
pub use global_hotkey::{
|
||||||
hotkey::{Code, HotKey as Shortcut, Modifiers},
|
|
||||||
GlobalHotKeyEvent as ShortcutEvent, HotKeyState as ShortcutState,
|
GlobalHotKeyEvent as ShortcutEvent, HotKeyState as ShortcutState,
|
||||||
|
hotkey::{Code, HotKey as Shortcut, Modifiers},
|
||||||
};
|
};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
|
AppHandle, Manager, Runtime, State,
|
||||||
ipc::Channel,
|
ipc::Channel,
|
||||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||||
AppHandle, Manager, Runtime, State,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use tauri::{command, AppHandle, Runtime};
|
use tauri::{AppHandle, Runtime, command};
|
||||||
|
|
||||||
use crate::{HapticsExt, ImpactFeedbackStyle, NotificationFeedbackType, Result};
|
use crate::{HapticsExt, ImpactFeedbackStyle, NotificationFeedbackType, Result};
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use tauri::{plugin::PluginApi, AppHandle, Runtime};
|
use tauri::{AppHandle, Runtime, plugin::PluginApi};
|
||||||
|
|
||||||
use crate::models::*;
|
use crate::models::*;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::{ser::Serializer, Serialize};
|
use serde::{Serialize, ser::Serializer};
|
||||||
|
|
||||||
/// Alias for a [`std::result::Result`] with the error type [`Error`].
|
/// Alias for a [`std::result::Result`] with the error type [`Error`].
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
//! - **specta**: Add support for [`specta::specta`](https://docs.rs/specta/2.0.0-rc.25/specta/attr.specta.html) on structs like [`ImpactFeedbackStyle`], [`NotificationFeedbackType`].
|
//! - **specta**: Add support for [`specta::specta`](https://docs.rs/specta/2.0.0-rc.25/specta/attr.specta.html) on structs like [`ImpactFeedbackStyle`], [`NotificationFeedbackType`].
|
||||||
|
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, TauriPlugin},
|
|
||||||
Manager, Runtime,
|
Manager, Runtime,
|
||||||
|
plugin::{Builder, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use models::*;
|
pub use models::*;
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{Serialize, de::DeserializeOwned};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{PluginApi, PluginHandle},
|
|
||||||
AppHandle, Runtime,
|
AppHandle, Runtime,
|
||||||
|
plugin::{PluginApi, PluginHandle},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::models::*;
|
use crate::models::*;
|
||||||
|
|||||||
@@ -4,20 +4,20 @@
|
|||||||
|
|
||||||
use std::{future::Future, pin::Pin, str::FromStr, sync::Arc, time::Duration};
|
use std::{future::Future, pin::Pin, str::FromStr, sync::Arc, time::Duration};
|
||||||
|
|
||||||
use http::{header, HeaderMap, HeaderName, HeaderValue, Method, StatusCode};
|
use http::{HeaderMap, HeaderName, HeaderValue, Method, StatusCode, header};
|
||||||
use reqwest::{redirect::Policy, NoProxy};
|
use reqwest::{NoProxy, redirect::Policy};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
|
Manager, ResourceId, ResourceTable, Runtime, State, Webview,
|
||||||
async_runtime::Mutex,
|
async_runtime::Mutex,
|
||||||
command,
|
command,
|
||||||
ipc::{CommandScope, GlobalScope},
|
ipc::{CommandScope, GlobalScope},
|
||||||
Manager, ResourceId, ResourceTable, Runtime, State, Webview,
|
|
||||||
};
|
};
|
||||||
use tokio::sync::oneshot::{channel, Receiver, Sender};
|
use tokio::sync::oneshot::{Receiver, Sender, channel};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
scope::{Entry, Scope},
|
|
||||||
Error, Http, Result,
|
Error, Http, Result,
|
||||||
|
scope::{Entry, Scope},
|
||||||
};
|
};
|
||||||
|
|
||||||
const HTTP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
|
const HTTP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
|
||||||
@@ -257,8 +257,12 @@ pub async fn fetch<R: Runtime>(
|
|||||||
if is_unsafe_header(&name) {
|
if is_unsafe_header(&name) {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
eprintln!("[\x1b[33mWARNING\x1b[0m] Skipping {name} header as it is a forbidden header per fetch spec https://fetch.spec.whatwg.org/#terminology-headers");
|
eprintln!(
|
||||||
eprintln!("[\x1b[33mWARNING\x1b[0m] if keeping the header is a desired behavior, you can enable `unsafe-headers` feature flag in your Cargo.toml");
|
"[\x1b[33mWARNING\x1b[0m] Skipping {name} header as it is a forbidden header per fetch spec https://fetch.spec.whatwg.org/#terminology-headers"
|
||||||
|
);
|
||||||
|
eprintln!(
|
||||||
|
"[\x1b[33mWARNING\x1b[0m] if keeping the header is a desired behavior, you can enable `unsafe-headers` feature flag in your Cargo.toml"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -294,7 +298,9 @@ pub async fn fetch<R: Runtime>(
|
|||||||
{
|
{
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
eprintln!("[\x1b[33mWARNING\x1b[0m] using dangerous settings requires `dangerous-settings` feature flag in your Cargo.toml");
|
eprintln!(
|
||||||
|
"[\x1b[33mWARNING\x1b[0m] using dangerous settings requires `dangerous-settings` feature flag in your Cargo.toml"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let _ = danger_config;
|
let _ = danger_config;
|
||||||
return Err(Error::DangerousSettings);
|
return Err(Error::DangerousSettings);
|
||||||
@@ -342,8 +348,8 @@ pub async fn fetch<R: Runtime>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ensure we have an Origin header set
|
// ensure we have an Origin header set
|
||||||
if cfg!(not(feature = "unsafe-headers")) || !headers.contains_key(header::ORIGIN) {
|
if (cfg!(not(feature = "unsafe-headers")) || !headers.contains_key(header::ORIGIN))
|
||||||
if let Ok(url) = webview.url() {
|
&& let Ok(url) = webview.url() {
|
||||||
// The url crate returns OpaqueOrigin for tauri://localhost which serializes to "null"
|
// The url crate returns OpaqueOrigin for tauri://localhost which serializes to "null"
|
||||||
let origin = if url.scheme() == "tauri" {
|
let origin = if url.scheme() == "tauri" {
|
||||||
"tauri://localhost".to_string()
|
"tauri://localhost".to_string()
|
||||||
@@ -352,7 +358,6 @@ pub async fn fetch<R: Runtime>(
|
|||||||
};
|
};
|
||||||
headers.append(header::ORIGIN, HeaderValue::from_str(&origin)?);
|
headers.append(header::ORIGIN, HeaderValue::from_str(&origin)?);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// In case empty origin is passed, remove it. Some services do not like Origin header
|
// In case empty origin is passed, remove it. Some services do not like Origin header
|
||||||
// so this way we can remove it in explicit way. The default behaviour is still to set it
|
// so this way we can remove it in explicit way. The default behaviour is still to set it
|
||||||
@@ -593,8 +598,10 @@ mod tests {
|
|||||||
Some(location) => format!(
|
Some(location) => format!(
|
||||||
"HTTP/1.1 302 Found\r\nLocation: {location}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
|
"HTTP/1.1 302 Found\r\nLocation: {location}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
|
||||||
),
|
),
|
||||||
None => "HTTP/1.1 200 OK\r\nContent-Length: 6\r\nConnection: close\r\n\r\nsecret"
|
None => {
|
||||||
.to_string(),
|
"HTTP/1.1 200 OK\r\nContent-Length: 6\r\nConnection: close\r\n\r\nsecret"
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = stream.write_all(response.as_bytes());
|
let _ = stream.write_all(response.as_bytes());
|
||||||
|
|||||||
@@ -61,8 +61,8 @@
|
|||||||
|
|
||||||
pub use reqwest;
|
pub use reqwest;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, TauriPlugin},
|
|
||||||
Manager, Runtime,
|
Manager, Runtime,
|
||||||
|
plugin::{Builder, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use config::Config;
|
pub use config::Config;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{mpsc::Receiver, Mutex},
|
sync::{Mutex, mpsc::Receiver},
|
||||||
};
|
};
|
||||||
|
|
||||||
use cookie_store::{CookieStore, RawCookie, RawCookieParseError};
|
use cookie_store::{CookieStore, RawCookie, RawCookieParseError};
|
||||||
|
|||||||
+14
-10
@@ -154,11 +154,13 @@ mod tests {
|
|||||||
assert!(scope.is_allowed(&"http://localhost:8080/file.png".parse().unwrap()));
|
assert!(scope.is_allowed(&"http://localhost:8080/file.png".parse().unwrap()));
|
||||||
assert!(scope.is_allowed(&"http://localhost:8080/file.png#head".parse().unwrap()));
|
assert!(scope.is_allowed(&"http://localhost:8080/file.png#head".parse().unwrap()));
|
||||||
assert!(scope.is_allowed(&"http://localhost:8080/assets/file.png".parse().unwrap()));
|
assert!(scope.is_allowed(&"http://localhost:8080/assets/file.png".parse().unwrap()));
|
||||||
assert!(scope.is_allowed(
|
assert!(
|
||||||
&"http://localhost:8080/assets/file.png?width=100&height=200"
|
scope.is_allowed(
|
||||||
.parse()
|
&"http://localhost:8080/assets/file.png?width=100&height=200"
|
||||||
.unwrap()
|
.parse()
|
||||||
));
|
.unwrap()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
assert!(!scope.is_allowed(&"http://localhost:8080/file.jpeg".parse().unwrap()));
|
assert!(!scope.is_allowed(&"http://localhost:8080/file.jpeg".parse().unwrap()));
|
||||||
}
|
}
|
||||||
@@ -172,11 +174,13 @@ mod tests {
|
|||||||
assert!(scope.is_allowed(&"http://something.else#tauri".parse().unwrap()));
|
assert!(scope.is_allowed(&"http://something.else#tauri".parse().unwrap()));
|
||||||
assert!(scope.is_allowed(&"http://something.else/path/to/file".parse().unwrap()));
|
assert!(scope.is_allowed(&"http://something.else/path/to/file".parse().unwrap()));
|
||||||
assert!(scope.is_allowed(&"http://something.else?rel=tauri".parse().unwrap()));
|
assert!(scope.is_allowed(&"http://something.else?rel=tauri".parse().unwrap()));
|
||||||
assert!(scope.is_allowed(
|
assert!(
|
||||||
&"http://something.else/path/to/file.mp4?start=500"
|
scope.is_allowed(
|
||||||
.parse()
|
&"http://something.else/path/to/file.mp4?start=500"
|
||||||
.unwrap()
|
.parse()
|
||||||
));
|
.unwrap()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
assert!(!scope.is_allowed(&"https://something.else".parse().unwrap()));
|
assert!(!scope.is_allowed(&"https://something.else".parse().unwrap()));
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use http::Uri;
|
use http::Uri;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
|
||||||
Runtime,
|
Runtime,
|
||||||
|
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||||
};
|
};
|
||||||
use tiny_http::{Header, Response as HttpResponse, Server};
|
use tiny_http::{Header, Response as HttpResponse, Server};
|
||||||
|
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ use std::{
|
|||||||
iter::FromIterator,
|
iter::FromIterator,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
use tauri::{
|
|
||||||
plugin::{self, TauriPlugin},
|
|
||||||
Manager, Runtime,
|
|
||||||
};
|
|
||||||
use tauri::{AppHandle, Emitter};
|
use tauri::{AppHandle, Emitter};
|
||||||
use time::{macros::format_description, OffsetDateTime};
|
use tauri::{
|
||||||
|
Manager, Runtime,
|
||||||
|
plugin::{self, TauriPlugin},
|
||||||
|
};
|
||||||
|
use time::{OffsetDateTime, macros::format_description};
|
||||||
|
|
||||||
pub use fern;
|
pub use fern;
|
||||||
pub use log;
|
pub use log;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::{ser::Serializer, Serialize};
|
use serde::{Serialize, ser::Serializer};
|
||||||
|
|
||||||
/// Alias for a [`std::result::Result`] with the error type [`Error`].
|
/// Alias for a [`std::result::Result`] with the error type [`Error`].
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, PluginHandle, TauriPlugin},
|
|
||||||
Manager, Runtime,
|
Manager, Runtime,
|
||||||
|
plugin::{Builder, PluginHandle, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use models::*;
|
pub use models::*;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use tauri::{command, plugin::PermissionState, AppHandle, Runtime, State};
|
use tauri::{AppHandle, Runtime, State, command, plugin::PermissionState};
|
||||||
|
|
||||||
use crate::{Notification, NotificationData, Result};
|
use crate::{Notification, NotificationData, Result};
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{PermissionState, PluginApi},
|
|
||||||
AppHandle, Runtime,
|
AppHandle, Runtime,
|
||||||
|
plugin::{PermissionState, PluginApi},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::NotificationBuilder;
|
use crate::NotificationBuilder;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::{ser::Serializer, Serialize};
|
use serde::{Serialize, ser::Serializer};
|
||||||
|
|
||||||
/// Alias for a [`std::result::Result`] with the error type set to [`Error`].
|
/// Alias for a [`std::result::Result`] with the error type set to [`Error`].
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|||||||
@@ -14,13 +14,13 @@
|
|||||||
)]
|
)]
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
#[cfg(mobile)]
|
|
||||||
use tauri::plugin::PluginHandle;
|
|
||||||
#[cfg(desktop)]
|
#[cfg(desktop)]
|
||||||
use tauri::AppHandle;
|
use tauri::AppHandle;
|
||||||
|
#[cfg(mobile)]
|
||||||
|
use tauri::plugin::PluginHandle;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, TauriPlugin},
|
|
||||||
Manager, Runtime,
|
Manager, Runtime,
|
||||||
|
plugin::{Builder, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use models::*;
|
pub use models::*;
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::{de::DeserializeOwned, Deserialize};
|
use serde::{Deserialize, de::DeserializeOwned};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{PermissionState, PluginApi, PluginHandle},
|
|
||||||
AppHandle, Runtime,
|
AppHandle, Runtime,
|
||||||
|
plugin::{PermissionState, PluginApi, PluginHandle},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::models::*;
|
use crate::models::*;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
use std::{collections::HashMap, fmt::Display};
|
use std::{collections::HashMap, fmt::Display};
|
||||||
|
|
||||||
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeError};
|
||||||
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@@ -188,11 +188,11 @@ pub enum Schedule {
|
|||||||
|
|
||||||
// custom ISO-8601 serialization that does not use 6 digits for years.
|
// custom ISO-8601 serialization that does not use 6 digits for years.
|
||||||
mod iso8601 {
|
mod iso8601 {
|
||||||
use serde::{ser::Error as _, Serialize, Serializer};
|
use serde::{Serialize, Serializer, ser::Error as _};
|
||||||
use time::{
|
use time::{
|
||||||
format_description::well_known::iso8601::{Config, EncodedConfig},
|
|
||||||
format_description::well_known::Iso8601,
|
|
||||||
OffsetDateTime,
|
OffsetDateTime,
|
||||||
|
format_description::well_known::Iso8601,
|
||||||
|
format_description::well_known::iso8601::{Config, EncodedConfig},
|
||||||
};
|
};
|
||||||
|
|
||||||
const SERDE_CONFIG: EncodedConfig = Config::DEFAULT.encode();
|
const SERDE_CONFIG: EncodedConfig = Config::DEFAULT.encode();
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use tauri::{
|
use tauri::{
|
||||||
ipc::{CommandScope, GlobalScope},
|
|
||||||
AppHandle, Runtime,
|
AppHandle, Runtime,
|
||||||
|
ipc::{CommandScope, GlobalScope},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{scope::Scope, Error, OpenerExt};
|
use crate::{Error, OpenerExt, scope::Scope};
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn open_url<R: Runtime>(
|
pub async fn open_url<R: Runtime>(
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use tauri::{plugin::TauriPlugin, Manager, Runtime};
|
use tauri::{Manager, Runtime, plugin::TauriPlugin};
|
||||||
|
|
||||||
#[cfg(mobile)]
|
#[cfg(mobile)]
|
||||||
use tauri::plugin::PluginHandle;
|
use tauri::plugin::PluginHandle;
|
||||||
|
|||||||
@@ -93,18 +93,18 @@ mod imp {
|
|||||||
|
|
||||||
use windows::Win32::UI::Shell::Common::ITEMIDLIST;
|
use windows::Win32::UI::Shell::Common::ITEMIDLIST;
|
||||||
use windows::{
|
use windows::{
|
||||||
core::{w, HSTRING, PCWSTR},
|
|
||||||
Win32::{
|
Win32::{
|
||||||
Foundation::ERROR_FILE_NOT_FOUND,
|
Foundation::ERROR_FILE_NOT_FOUND,
|
||||||
System::Com::CoInitialize,
|
System::Com::CoInitialize,
|
||||||
UI::{
|
UI::{
|
||||||
Shell::{
|
Shell::{
|
||||||
ILCreateFromPathW, ILFree, SHOpenFolderAndSelectItems, ShellExecuteExW,
|
ILCreateFromPathW, ILFree, SHELLEXECUTEINFOW, SHOpenFolderAndSelectItems,
|
||||||
SHELLEXECUTEINFOW,
|
ShellExecuteExW,
|
||||||
},
|
},
|
||||||
WindowsAndMessaging::SW_SHOWNORMAL,
|
WindowsAndMessaging::SW_SHOWNORMAL,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
core::{HSTRING, PCWSTR, w},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn reveal_items_in_dir(paths: &[PathBuf]) -> crate::Result<()> {
|
pub fn reveal_items_in_dir(paths: &[PathBuf]) -> crate::Result<()> {
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ use std::{
|
|||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use tauri::{ipc::ScopeObject, utils::acl::Value, AppHandle, Manager, Runtime};
|
use tauri::{AppHandle, Manager, Runtime, ipc::ScopeObject, utils::acl::Value};
|
||||||
|
|
||||||
use crate::{scope_entry::EntryRaw, Error};
|
use crate::{Error, scope_entry::EntryRaw};
|
||||||
|
|
||||||
pub use crate::scope_entry::Application;
|
pub use crate::scope_entry::Application;
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use std::{
|
|||||||
path::{Component, Path, PathBuf, Prefix, PrefixComponent},
|
path::{Component, Path, PathBuf, Prefix, PrefixComponent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use windows::{core::HSTRING, Win32::Storage::FileSystem::GetFullPathNameW};
|
use windows::{Win32::Storage::FileSystem::GetFullPathNameW, core::HSTRING};
|
||||||
|
|
||||||
pub fn absolute_and_check_exists(path: &Path) -> io::Result<PathBuf> {
|
pub fn absolute_and_check_exists(path: &Path) -> io::Result<PathBuf> {
|
||||||
let path = absolute(path)?;
|
let path = absolute(path)?;
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
pub use os_info::Version;
|
pub use os_info::Version;
|
||||||
use serialize_to_javascript::{default_template, DefaultTemplate, Template};
|
use serialize_to_javascript::{DefaultTemplate, Template, default_template};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, TauriPlugin},
|
|
||||||
Runtime,
|
Runtime,
|
||||||
|
plugin::{Builder, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ use aho_corasick::AhoCorasick;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, TauriPlugin},
|
|
||||||
Manager, Runtime,
|
Manager, Runtime,
|
||||||
|
plugin::{Builder, TauriPlugin},
|
||||||
};
|
};
|
||||||
use tauri_plugin_fs::FsExt;
|
use tauri_plugin_fs::FsExt;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::{create_dir_all, File},
|
fs::{File, create_dir_all},
|
||||||
io::Write,
|
io::Write,
|
||||||
path::Path,
|
path::Path,
|
||||||
};
|
};
|
||||||
@@ -198,8 +198,8 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
|||||||
// We will still save some semi-broken values because the scope events are quite spammy and we don't want to reduce runtime performance any further.
|
// We will still save some semi-broken values because the scope events are quite spammy and we don't want to reduce runtime performance any further.
|
||||||
let ac = AhoCorasick::new(PATTERNS).unwrap(/* This should be impossible to fail since we're using a small static input */);
|
let ac = AhoCorasick::new(PATTERNS).unwrap(/* This should be impossible to fail since we're using a small static input */);
|
||||||
|
|
||||||
if let Some(fs_scope) = &fs_scope {
|
if let Some(fs_scope) = &fs_scope
|
||||||
if fs_scope_state_path.exists() {
|
&& fs_scope_state_path.exists() {
|
||||||
let scope: Scope = std::fs::read(&fs_scope_state_path)
|
let scope: Scope = std::fs::read(&fs_scope_state_path)
|
||||||
.map_err(Error::from)
|
.map_err(Error::from)
|
||||||
.and_then(|scope| bincode::deserialize(&scope).map_err(Into::into))
|
.and_then(|scope| bincode::deserialize(&scope).map_err(Into::into))
|
||||||
@@ -218,7 +218,6 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
|||||||
// This is needed to fix broken .peristed-scope files in case the app doesn't update the scope itself.
|
// This is needed to fix broken .peristed-scope files in case the app doesn't update the scope itself.
|
||||||
save_scopes(fs_scope, &app_dir, &fs_scope_state_path);
|
save_scopes(fs_scope, &app_dir, &fs_scope_state_path);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "protocol-asset")]
|
#[cfg(feature = "protocol-asset")]
|
||||||
if asset_scope_state_path.exists() {
|
if asset_scope_state_path.exists() {
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ mod ext;
|
|||||||
|
|
||||||
pub use ext::*;
|
pub use ext::*;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{self, TauriPlugin},
|
|
||||||
Result, Runtime,
|
Result, Runtime,
|
||||||
|
plugin::{self, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "tray-icon")]
|
#[cfg(feature = "tray-icon")]
|
||||||
use tauri::{tray::TrayIconEvent, AppHandle, Manager, PhysicalPosition, PhysicalSize};
|
use tauri::{AppHandle, Manager, PhysicalPosition, PhysicalSize, tray::TrayIconEvent};
|
||||||
|
|
||||||
#[cfg(feature = "tray-icon")]
|
#[cfg(feature = "tray-icon")]
|
||||||
struct Tray(std::sync::Mutex<Option<(PhysicalPosition<f64>, PhysicalSize<f64>)>>);
|
struct Tray(std::sync::Mutex<Option<(PhysicalPosition<f64>, PhysicalSize<f64>)>>);
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
)]
|
)]
|
||||||
|
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, TauriPlugin},
|
|
||||||
Runtime,
|
Runtime,
|
||||||
|
plugin::{Builder, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
|
|||||||
@@ -7,16 +7,16 @@ use std::{collections::HashMap, future::Future, path::PathBuf, pin::Pin, string:
|
|||||||
use encoding_rs::Encoding;
|
use encoding_rs::Encoding;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
ipc::{Channel, CommandScope, GlobalScope},
|
|
||||||
Manager, Runtime, State, Window,
|
Manager, Runtime, State, Window,
|
||||||
|
ipc::{Channel, CommandScope, GlobalScope},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
use crate::open::Program;
|
use crate::open::Program;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
Shell,
|
||||||
process::{CommandEvent, TerminatedPayload},
|
process::{CommandEvent, TerminatedPayload},
|
||||||
scope::ExecuteArgs,
|
scope::ExecuteArgs,
|
||||||
Shell,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type ChildId = u32;
|
type ChildId = u32;
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ use std::{
|
|||||||
use process::{Command, CommandChild};
|
use process::{Command, CommandChild};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, TauriPlugin},
|
|
||||||
AppHandle, Manager, RunEvent, Runtime,
|
AppHandle, Manager, RunEvent, Runtime,
|
||||||
|
plugin::{Builder, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ use std::os::windows::process::CommandExt;
|
|||||||
const CREATE_NO_WINDOW: u32 = 0x0800_0000;
|
const CREATE_NO_WINDOW: u32 = 0x0800_0000;
|
||||||
const NEWLINE_BYTE: u8 = b'\n';
|
const NEWLINE_BYTE: u8 = b'\n';
|
||||||
|
|
||||||
use tauri::async_runtime::{block_on as block_on_task, channel, Receiver, Sender};
|
use tauri::async_runtime::{Receiver, Sender, block_on as block_on_task, channel};
|
||||||
|
|
||||||
pub use encoding_rs::Encoding;
|
pub use encoding_rs::Encoding;
|
||||||
use os_pipe::{pipe, PipeReader, PipeWriter};
|
use os_pipe::{PipeReader, PipeWriter, pipe};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use shared_child::SharedChild;
|
use shared_child::SharedChild;
|
||||||
use tauri::utils::platform;
|
use tauri::utils::platform;
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ use crate::open::Program;
|
|||||||
use crate::process::Command;
|
use crate::process::Command;
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use tauri::ipc::ScopeObject;
|
|
||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
|
use tauri::ipc::ScopeObject;
|
||||||
|
|
||||||
/// Allowed representation of `Execute` command arguments.
|
/// Allowed representation of `Execute` command arguments.
|
||||||
#[derive(Debug, Clone, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Deserialize)]
|
||||||
@@ -162,8 +162,8 @@ pub enum Error {
|
|||||||
|
|
||||||
/// The sidecar program validated but failed to find the sidecar path.
|
/// The sidecar program validated but failed to find the sidecar path.
|
||||||
#[error(
|
#[error(
|
||||||
"The scoped sidecar command was validated, but failed to create the path to the command: {0}"
|
"The scoped sidecar command was validated, but failed to create the path to the command: {0}"
|
||||||
)]
|
)]
|
||||||
Sidecar(String),
|
Sidecar(String),
|
||||||
|
|
||||||
/// The named command was not found in the scoped config.
|
/// The named command was not found in the scoped config.
|
||||||
@@ -172,12 +172,14 @@ pub enum Error {
|
|||||||
|
|
||||||
/// A command variable has no value set in the arguments.
|
/// A command variable has no value set in the arguments.
|
||||||
#[error(
|
#[error(
|
||||||
"Scoped command argument at position {0} must match regex validation {1} but it was not found"
|
"Scoped command argument at position {0} must match regex validation {1} but it was not found"
|
||||||
)]
|
)]
|
||||||
MissingVar(usize, String),
|
MissingVar(usize, String),
|
||||||
|
|
||||||
/// At least one argument did not pass input validation.
|
/// At least one argument did not pass input validation.
|
||||||
#[error("Scoped command argument at position {index} was found, but failed regex validation {validation}")]
|
#[error(
|
||||||
|
"Scoped command argument at position {index} was found, but failed regex validation {validation}"
|
||||||
|
)]
|
||||||
Validation {
|
Validation {
|
||||||
/// Index of the variable.
|
/// Index of the variable.
|
||||||
index: usize,
|
index: usize,
|
||||||
@@ -214,7 +216,9 @@ impl OpenScope {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::warn!("open() command called but the plugin configuration denies calls from JavaScript; set `tauri.conf.json > plugins > shell > open` to true or a validation regex string");
|
log::warn!(
|
||||||
|
"open() command called but the plugin configuration denies calls from JavaScript; set `tauri.conf.json > plugins > shell > open` to true or a validation regex string"
|
||||||
|
);
|
||||||
return Err(Error::Validation {
|
return Err(Error::Validation {
|
||||||
index: 0,
|
index: 0,
|
||||||
validation: "tauri^".to_string(), // purposefully impossible regex
|
validation: "tauri^".to_string(), // purposefully impossible regex
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde::{de::Error as DeError, Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer, de::Error as DeError};
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ version = "0.1.0"
|
|||||||
description = "A Tauri App"
|
description = "A Tauri App"
|
||||||
authors = ["You"]
|
authors = ["You"]
|
||||||
repository = ""
|
repository = ""
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
rust-version = "1.90"
|
rust-version = "1.90"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
)]
|
)]
|
||||||
#![cfg(not(any(target_os = "android", target_os = "ios")))]
|
#![cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
|
|
||||||
use tauri::{plugin::TauriPlugin, AppHandle, Manager, Runtime};
|
use tauri::{AppHandle, Manager, Runtime, plugin::TauriPlugin};
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
#[path = "platform_impl/windows.rs"]
|
#[path = "platform_impl/windows.rs"]
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ use crate::semver_compat::semver_compat_string;
|
|||||||
|
|
||||||
use crate::SingleInstanceCallback;
|
use crate::SingleInstanceCallback;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{self, TauriPlugin},
|
|
||||||
AppHandle, Manager, RunEvent, Runtime,
|
AppHandle, Manager, RunEvent, Runtime,
|
||||||
|
plugin::{self, TauriPlugin},
|
||||||
};
|
};
|
||||||
use zbus::{blocking::Connection, interface, names::WellKnownName};
|
use zbus::{blocking::Connection, interface, names::WellKnownName};
|
||||||
|
|
||||||
@@ -101,12 +101,11 @@ pub fn init<R: Runtime>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy<R: Runtime, M: Manager<R>>(manager: &M) {
|
pub fn destroy<R: Runtime, M: Manager<R>>(manager: &M) {
|
||||||
if let Some(connection) = manager.try_state::<ConnectionHandle>() {
|
if let Some(connection) = manager.try_state::<ConnectionHandle>()
|
||||||
if let Some(dbus_name) = manager
|
&& let Some(dbus_name) = manager
|
||||||
.try_state::<DBusName>()
|
.try_state::<DBusName>()
|
||||||
.and_then(|name| WellKnownName::try_from(name.0.clone()).ok())
|
.and_then(|name| WellKnownName::try_from(name.0.clone()).ok())
|
||||||
{
|
{
|
||||||
let _ = connection.0.release_name(dbus_name);
|
let _ = connection.0.release_name(dbus_name);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ use std::{
|
|||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::SingleInstanceCallback;
|
||||||
#[cfg(feature = "semver")]
|
#[cfg(feature = "semver")]
|
||||||
use crate::semver_compat::semver_compat_string;
|
use crate::semver_compat::semver_compat_string;
|
||||||
use crate::SingleInstanceCallback;
|
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{self, TauriPlugin},
|
|
||||||
AppHandle, Config, Manager, RunEvent, Runtime,
|
AppHandle, Config, Manager, RunEvent, Runtime,
|
||||||
|
plugin::{self, TauriPlugin},
|
||||||
};
|
};
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
|
|||||||
@@ -8,20 +8,20 @@ use crate::semver_compat::semver_compat_string;
|
|||||||
use crate::SingleInstanceCallback;
|
use crate::SingleInstanceCallback;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{self, TauriPlugin},
|
|
||||||
AppHandle, Manager, RunEvent, Runtime,
|
AppHandle, Manager, RunEvent, Runtime,
|
||||||
|
plugin::{self, TauriPlugin},
|
||||||
};
|
};
|
||||||
use windows_sys::Win32::{
|
use windows_sys::Win32::{
|
||||||
Foundation::{CloseHandle, GetLastError, ERROR_ALREADY_EXISTS, HWND, LPARAM, LRESULT, WPARAM},
|
Foundation::{CloseHandle, ERROR_ALREADY_EXISTS, GetLastError, HWND, LPARAM, LRESULT, WPARAM},
|
||||||
System::{
|
System::{
|
||||||
DataExchange::COPYDATASTRUCT,
|
DataExchange::COPYDATASTRUCT,
|
||||||
LibraryLoader::GetModuleHandleW,
|
LibraryLoader::GetModuleHandleW,
|
||||||
Threading::{CreateMutexW, ReleaseMutex},
|
Threading::{CreateMutexW, ReleaseMutex},
|
||||||
},
|
},
|
||||||
UI::WindowsAndMessaging::{
|
UI::WindowsAndMessaging::{
|
||||||
self as w32wm, AllowSetForegroundWindow, CreateWindowExW, DefWindowProcW, DestroyWindow,
|
self as w32wm, AllowSetForegroundWindow, CREATESTRUCTW, CreateWindowExW, DefWindowProcW,
|
||||||
FindWindowW, GetWindowThreadProcessId, RegisterClassExW, SendMessageW, CREATESTRUCTW,
|
DestroyWindow, FindWindowW, GWL_STYLE, GWLP_USERDATA, GetWindowThreadProcessId,
|
||||||
GWLP_USERDATA, GWL_STYLE, WINDOW_LONG_PTR_INDEX, WM_COPYDATA, WM_CREATE, WM_DESTROY,
|
RegisterClassExW, SendMessageW, WINDOW_LONG_PTR_INDEX, WM_COPYDATA, WM_CREATE, WM_DESTROY,
|
||||||
WNDCLASSEXW, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT,
|
WNDCLASSEXW, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT,
|
||||||
WS_OVERLAPPED, WS_POPUP, WS_VISIBLE,
|
WS_OVERLAPPED, WS_POPUP, WS_VISIBLE,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use serde_json::Value as JsonValue;
|
use serde_json::Value as JsonValue;
|
||||||
use sqlx::migrate::Migrator;
|
use sqlx::migrate::Migrator;
|
||||||
use tauri::{command, AppHandle, Runtime, State};
|
use tauri::{AppHandle, Runtime, State, command};
|
||||||
|
|
||||||
use crate::{DbInstances, DbPool, Error, LastInsertId, Migrations};
|
use crate::{DbInstances, DbPool, Error, LastInsertId, Migrations};
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde_json::Value as JsonValue;
|
use serde_json::Value as JsonValue;
|
||||||
use sqlx::{mysql::MySqlValueRef, TypeInfo, Value, ValueRef};
|
use sqlx::{TypeInfo, Value, ValueRef, mysql::MySqlValueRef};
|
||||||
use time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
|
use time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
|
||||||
|
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
use rust_decimal::prelude::ToPrimitive;
|
use rust_decimal::prelude::ToPrimitive;
|
||||||
use serde_json::Value as JsonValue;
|
use serde_json::Value as JsonValue;
|
||||||
use sqlx::{postgres::PgValueRef, TypeInfo, Value, ValueRef};
|
use sqlx::{TypeInfo, Value, ValueRef, postgres::PgValueRef};
|
||||||
use time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
|
use time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use serde_json::Value as JsonValue;
|
use serde_json::Value as JsonValue;
|
||||||
use sqlx::{sqlite::SqliteValueRef, TypeInfo, Value, ValueRef};
|
use sqlx::{TypeInfo, Value, ValueRef, sqlite::SqliteValueRef};
|
||||||
use time::{Date, PrimitiveDateTime, Time};
|
use time::{Date, PrimitiveDateTime, Time};
|
||||||
|
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ use sqlx::{
|
|||||||
migrate::{Migration as SqlxMigration, MigrationSource, MigrationType, Migrator},
|
migrate::{Migration as SqlxMigration, MigrationSource, MigrationType, Migrator},
|
||||||
};
|
};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
|
||||||
Manager, RunEvent, Runtime,
|
Manager, RunEvent, Runtime,
|
||||||
|
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||||
};
|
};
|
||||||
use tokio::sync::{Mutex, RwLock};
|
use tokio::sync::{Mutex, RwLock};
|
||||||
|
|
||||||
@@ -158,7 +158,9 @@ impl Builder {
|
|||||||
/// connected to in that case.
|
/// connected to in that case.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
#[cfg(not(any(feature = "sqlite", feature = "mysql", feature = "postgres")))]
|
#[cfg(not(any(feature = "sqlite", feature = "mysql", feature = "postgres")))]
|
||||||
eprintln!("No sql driver enabled. Please set at least one of the \"sqlite\", \"mysql\", \"postgres\" feature flags.");
|
eprintln!(
|
||||||
|
"No sql driver enabled. Please set at least one of the \"sqlite\", \"mysql\", \"postgres\" feature flags."
|
||||||
|
);
|
||||||
|
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use std::fs::create_dir_all;
|
|||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use serde_json::Value as JsonValue;
|
use serde_json::Value as JsonValue;
|
||||||
#[cfg(any(feature = "sqlite", feature = "mysql", feature = "postgres"))]
|
#[cfg(any(feature = "sqlite", feature = "mysql", feature = "postgres"))]
|
||||||
use sqlx::{migrate::MigrateDatabase, Column, Executor, Pool, Row};
|
use sqlx::{Column, Executor, Pool, Row, migrate::MigrateDatabase};
|
||||||
#[cfg(any(feature = "sqlite", feature = "mysql", feature = "postgres"))]
|
#[cfg(any(feature = "sqlite", feature = "mysql", feature = "postgres"))]
|
||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
use tauri::{AppHandle, Runtime};
|
use tauri::{AppHandle, Runtime};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ description = "A Tauri App"
|
|||||||
authors = ["you"]
|
authors = ["you"]
|
||||||
license = ""
|
license = ""
|
||||||
repository = ""
|
repository = ""
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ use std::{
|
|||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
pub use store::{resolve_store_path, DeserializeFn, SerializeFn, Store, StoreBuilder};
|
pub use store::{DeserializeFn, SerializeFn, Store, StoreBuilder, resolve_store_path};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{self, TauriPlugin},
|
|
||||||
AppHandle, Manager, ResourceId, RunEvent, Runtime, State,
|
AppHandle, Manager, ResourceId, RunEvent, Runtime, State,
|
||||||
|
plugin::{self, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
@@ -470,11 +470,10 @@ impl Builder {
|
|||||||
let collection = app_handle.state::<StoreState>();
|
let collection = app_handle.state::<StoreState>();
|
||||||
let stores = collection.stores.read().unwrap();
|
let stores = collection.stores.read().unwrap();
|
||||||
for (path, rid) in stores.iter() {
|
for (path, rid) in stores.iter() {
|
||||||
if let Ok(store) = app_handle.resources_table().get::<Store<R>>(*rid) {
|
if let Ok(store) = app_handle.resources_table().get::<Store<R>>(*rid)
|
||||||
if let Err(err) = store.save() {
|
&& let Err(err) = store.save() {
|
||||||
tracing::error!("failed to save store {path:?} with error {err:?}");
|
tracing::error!("failed to save store {path:?} with error {err:?}");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ use std::{
|
|||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
use tauri::{path::BaseDirectory, AppHandle, Emitter, Manager, Resource, ResourceId, Runtime};
|
use tauri::{AppHandle, Emitter, Manager, Resource, ResourceId, Runtime, path::BaseDirectory};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
select,
|
select,
|
||||||
sync::mpsc::{unbounded_channel, UnboundedSender},
|
sync::mpsc::{UnboundedSender, unbounded_channel},
|
||||||
time::sleep,
|
time::sleep,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ fn create_or_get_salt(salt: &mut [u8], salt_path: &Path) {
|
|||||||
salt.clone_from_slice(&tmp);
|
salt.clone_from_slice(&tmp);
|
||||||
} else {
|
} else {
|
||||||
// Generate new salt
|
// Generate new salt
|
||||||
let mut gen = ChaCha20Rng::from_os_rng();
|
let mut rng = ChaCha20Rng::from_os_rng();
|
||||||
gen.fill_bytes(salt);
|
rng.fill_bytes(salt);
|
||||||
std::fs::write(salt_path, salt).expect("Failed to write salt for Stronghold")
|
std::fs::write(salt_path, salt).expect("Failed to write salt for Stronghold")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,18 +23,18 @@ use std::{
|
|||||||
|
|
||||||
use crypto::keys::bip39;
|
use crypto::keys::bip39;
|
||||||
use iota_stronghold::{
|
use iota_stronghold::{
|
||||||
|
Client, Location,
|
||||||
procedures::{
|
procedures::{
|
||||||
BIP39Generate, BIP39Recover, Curve, Ed25519Sign, KeyType as StrongholdKeyType,
|
BIP39Generate, BIP39Recover, Curve, Ed25519Sign, KeyType as StrongholdKeyType,
|
||||||
MnemonicLanguage, PublicKey, Slip10Derive, Slip10DeriveInput, Slip10Generate,
|
MnemonicLanguage, PublicKey, Slip10Derive, Slip10DeriveInput, Slip10Generate,
|
||||||
StrongholdProcedure,
|
StrongholdProcedure,
|
||||||
},
|
},
|
||||||
Client, Location,
|
|
||||||
};
|
};
|
||||||
use serde::{de::Visitor, Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer, de::Visitor};
|
||||||
use stronghold::{Error, Result, Stronghold};
|
use stronghold::{Error, Result, Stronghold};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
|
||||||
Manager, Runtime, State,
|
Manager, Runtime, State,
|
||||||
|
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||||
};
|
};
|
||||||
use zeroize::{Zeroize, Zeroizing};
|
use zeroize::{Zeroize, Zeroizing};
|
||||||
|
|
||||||
@@ -270,12 +270,11 @@ async fn destroy(
|
|||||||
snapshot_path: PathBuf,
|
snapshot_path: PathBuf,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut collection = collection.0.lock().unwrap();
|
let mut collection = collection.0.lock().unwrap();
|
||||||
if let Some(stronghold) = collection.remove(&snapshot_path) {
|
if let Some(stronghold) = collection.remove(&snapshot_path)
|
||||||
if let Err(e) = stronghold.save() {
|
&& let Err(e) = stronghold.save() {
|
||||||
collection.insert(snapshot_path, stronghold);
|
collection.insert(snapshot_path, stronghold);
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use crate::{Result, Update, UpdaterExt};
|
|||||||
|
|
||||||
use http::{HeaderMap, HeaderName, HeaderValue};
|
use http::{HeaderMap, HeaderName, HeaderValue};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tauri::{ipc::Channel, Manager, Resource, ResourceId, Runtime, Webview};
|
use tauri::{Manager, Resource, ResourceId, Runtime, Webview, ipc::Channel};
|
||||||
|
|
||||||
use std::{str::FromStr, time::Duration};
|
use std::{str::FromStr, time::Duration};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|||||||
@@ -204,8 +204,12 @@ pub(crate) fn validate_endpoints(
|
|||||||
if url.scheme() != "https" {
|
if url.scheme() != "https" {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
eprintln!("[\x1b[33mWARNING\x1b[0m] The updater endpoint \"{url}\" doesn't use `https` protocol. This is allowed in development but will fail in release builds.");
|
eprintln!(
|
||||||
eprintln!("[\x1b[33mWARNING\x1b[0m] if this is a desired behavior, you can enable `dangerousInsecureTransportProtocol` in the plugin configuration");
|
"[\x1b[33mWARNING\x1b[0m] The updater endpoint \"{url}\" doesn't use `https` protocol. This is allowed in development but will fail in release builds."
|
||||||
|
);
|
||||||
|
eprintln!(
|
||||||
|
"[\x1b[33mWARNING\x1b[0m] if this is a desired behavior, you can enable `dangerousInsecureTransportProtocol` in the plugin configuration"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
return Err(crate::Error::InsecureTransportProtocol);
|
return Err(crate::Error::InsecureTransportProtocol);
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ pub enum Error {
|
|||||||
#[error("Could not fetch a valid release JSON from the remote")]
|
#[error("Could not fetch a valid release JSON from the remote")]
|
||||||
ReleaseNotFound,
|
ReleaseNotFound,
|
||||||
/// Unsupported app architecture.
|
/// Unsupported app architecture.
|
||||||
#[error("Unsupported application architecture, expected one of `x86`, `x86_64`, `arm` or `aarch64`.")]
|
#[error(
|
||||||
|
"Unsupported application architecture, expected one of `x86`, `x86_64`, `arm` or `aarch64`."
|
||||||
|
)]
|
||||||
UnsupportedArch,
|
UnsupportedArch,
|
||||||
/// Operating system is not supported.
|
/// Operating system is not supported.
|
||||||
#[error("Unsupported OS, expected one of `linux`, `darwin` or `windows`.")]
|
#[error("Unsupported OS, expected one of `linux`, `darwin` or `windows`.")]
|
||||||
@@ -43,9 +45,7 @@ pub enum Error {
|
|||||||
#[error("the platform `{0}` was not found in the response `platforms` object")]
|
#[error("the platform `{0}` was not found in the response `platforms` object")]
|
||||||
TargetNotFound(String),
|
TargetNotFound(String),
|
||||||
/// Neither the platform nor the fallback platform was found in the updater JSON response.
|
/// Neither the platform nor the fallback platform was found in the updater JSON response.
|
||||||
#[error(
|
#[error("None of the fallback platforms `{0:?}` were found in the response `platforms` object")]
|
||||||
"None of the fallback platforms `{0:?}` were found in the response `platforms` object"
|
|
||||||
)]
|
|
||||||
TargetsNotFound(Vec<String>),
|
TargetsNotFound(Vec<String>),
|
||||||
/// Download failed
|
/// Download failed
|
||||||
#[error("`{0}`")]
|
#[error("`{0}`")]
|
||||||
@@ -57,7 +57,9 @@ pub enum Error {
|
|||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Base64(#[from] base64::DecodeError),
|
Base64(#[from] base64::DecodeError),
|
||||||
/// UTF8 Errors in signature.
|
/// UTF8 Errors in signature.
|
||||||
#[error("The signature {0} could not be decoded, please check if it is a valid base64 string. The signature must be the contents of the `.sig` file generated by the Tauri bundler, as a string.")]
|
#[error(
|
||||||
|
"The signature {0} could not be decoded, please check if it is a valid base64 string. The signature must be the contents of the `.sig` file generated by the Tauri bundler, as a string."
|
||||||
|
)]
|
||||||
SignatureUtf8(String),
|
SignatureUtf8(String),
|
||||||
#[cfg(all(target_os = "windows", feature = "zip"))]
|
#[cfg(all(target_os = "windows", feature = "zip"))]
|
||||||
/// `zip` errors.
|
/// `zip` errors.
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ use std::{ffi::OsString, sync::Arc};
|
|||||||
use http::{HeaderMap, HeaderName, HeaderValue};
|
use http::{HeaderMap, HeaderName, HeaderValue};
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
|
||||||
Manager, Runtime,
|
Manager, Runtime,
|
||||||
|
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
|
|||||||
@@ -17,28 +17,28 @@ use std::ffi::OsStr;
|
|||||||
|
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use http::{header::ACCEPT, HeaderName};
|
use http::{HeaderName, header::ACCEPT};
|
||||||
use minisign_verify::{PublicKey, Signature};
|
use minisign_verify::{PublicKey, Signature};
|
||||||
use percent_encoding::{AsciiSet, CONTROLS};
|
use percent_encoding::{AsciiSet, CONTROLS};
|
||||||
use reqwest::{
|
use reqwest::{
|
||||||
header::{HeaderMap, HeaderValue},
|
|
||||||
ClientBuilder, StatusCode,
|
ClientBuilder, StatusCode,
|
||||||
|
header::{HeaderMap, HeaderValue},
|
||||||
};
|
};
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize, de::Error as DeError};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
|
AppHandle, Resource, Runtime,
|
||||||
utils::{
|
utils::{
|
||||||
config::BundleType,
|
config::BundleType,
|
||||||
platform::{bundle_type, current_exe},
|
platform::{bundle_type, current_exe},
|
||||||
},
|
},
|
||||||
AppHandle, Resource, Runtime,
|
|
||||||
};
|
};
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{Error, Result},
|
|
||||||
Config,
|
Config,
|
||||||
|
error::{Error, Result},
|
||||||
};
|
};
|
||||||
|
|
||||||
const UPDATER_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
|
const UPDATER_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
|
||||||
@@ -937,8 +937,8 @@ impl Update {
|
|||||||
/// └── ...
|
/// └── ...
|
||||||
fn install_inner(&self, bytes: &[u8]) -> Result<()> {
|
fn install_inner(&self, bytes: &[u8]) -> Result<()> {
|
||||||
use windows_sys::{
|
use windows_sys::{
|
||||||
w,
|
|
||||||
Win32::UI::{Shell::ShellExecuteW, WindowsAndMessaging::SW_SHOW},
|
Win32::UI::{Shell::ShellExecuteW, WindowsAndMessaging::SW_SHOW},
|
||||||
|
w,
|
||||||
};
|
};
|
||||||
|
|
||||||
let updater_type = self.extract(bytes)?;
|
let updater_type = self.extract(bytes)?;
|
||||||
@@ -1185,8 +1185,8 @@ impl Update {
|
|||||||
let decoder = flate2::read::GzDecoder::new(archive);
|
let decoder = flate2::read::GzDecoder::new(archive);
|
||||||
let mut archive = tar::Archive::new(decoder);
|
let mut archive = tar::Archive::new(decoder);
|
||||||
for mut entry in archive.entries()?.flatten() {
|
for mut entry in archive.entries()?.flatten() {
|
||||||
if let Ok(path) = entry.path() {
|
if let Ok(path) = entry.path()
|
||||||
if path.extension() == Some(OsStr::new("AppImage")) {
|
&& path.extension() == Some(OsStr::new("AppImage")) {
|
||||||
// if something went wrong during the extraction, we should restore previous app
|
// if something went wrong during the extraction, we should restore previous app
|
||||||
if let Err(err) = entry.unpack(&self.extract_path) {
|
if let Err(err) = entry.unpack(&self.extract_path) {
|
||||||
std::fs::rename(tmp_app_image, &self.extract_path)?;
|
std::fs::rename(tmp_app_image, &self.extract_path)?;
|
||||||
@@ -1195,7 +1195,6 @@ impl Update {
|
|||||||
// early finish we have everything we need here
|
// early finish we have everything we need here
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// if we have not returned early we should restore the backup
|
// if we have not returned early we should restore the backup
|
||||||
std::fs::rename(tmp_app_image, &self.extract_path)?;
|
std::fs::rename(tmp_app_image, &self.extract_path)?;
|
||||||
@@ -1289,20 +1288,17 @@ impl Update {
|
|||||||
.arg(install_arg)
|
.arg(install_arg)
|
||||||
.arg(pkg_path)
|
.arg(pkg_path)
|
||||||
.status()
|
.status()
|
||||||
{
|
&& status.success() {
|
||||||
if status.success() {
|
|
||||||
log::debug!("installed {pkg_path:?} with pkexec");
|
log::debug!("installed {pkg_path:?} with pkexec");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Try zenity or kdialog for a graphical sudo experience
|
// 2. Try zenity or kdialog for a graphical sudo experience
|
||||||
if let Ok(password) = self.get_password_graphically() {
|
if let Ok(password) = self.get_password_graphically()
|
||||||
if self.install_with_sudo(pkg_path, &password, install_cmd, install_arg)? {
|
&& self.install_with_sudo(pkg_path, &password, install_cmd, install_arg)? {
|
||||||
log::debug!("installed {pkg_path:?} with GUI sudo");
|
log::debug!("installed {pkg_path:?} with GUI sudo");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Final fallback: terminal sudo
|
// 3. Final fallback: terminal sudo
|
||||||
let status = std::process::Command::new("sudo")
|
let status = std::process::Command::new("sudo")
|
||||||
@@ -1329,22 +1325,20 @@ impl Update {
|
|||||||
])
|
])
|
||||||
.output();
|
.output();
|
||||||
|
|
||||||
if let Ok(output) = zenity_result {
|
if let Ok(output) = zenity_result
|
||||||
if output.status.success() {
|
&& output.status.success() {
|
||||||
return Ok(String::from_utf8_lossy(&output.stdout).trim().to_string());
|
return Ok(String::from_utf8_lossy(&output.stdout).trim().to_string());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Fall back to kdialog if zenity fails or isn't available
|
// Fall back to kdialog if zenity fails or isn't available
|
||||||
let kdialog_result = std::process::Command::new("kdialog")
|
let kdialog_result = std::process::Command::new("kdialog")
|
||||||
.args(["--password", "Enter your password to install the update:"])
|
.args(["--password", "Enter your password to install the update:"])
|
||||||
.output();
|
.output();
|
||||||
|
|
||||||
if let Ok(output) = kdialog_result {
|
if let Ok(output) = kdialog_result
|
||||||
if output.status.success() {
|
&& output.status.success() {
|
||||||
return Ok(String::from_utf8_lossy(&output.stdout).trim().to_string());
|
return Ok(String::from_utf8_lossy(&output.stdout).trim().to_string());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Err(Error::AuthenticationFailed)
|
Err(Error::AuthenticationFailed)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -818,7 +818,8 @@ fn run_update_cases(
|
|||||||
|
|
||||||
if code != expected_exit_code {
|
if code != expected_exit_code {
|
||||||
panic!(
|
panic!(
|
||||||
"failed to run app bundled as {}, expected exit code {expected_exit_code}, got {code}", bundle_target.name()
|
"failed to run app bundled as {}, expected exit code {expected_exit_code}, got {code}",
|
||||||
|
bundle_target.name()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ fn npm_command() -> Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod v1 {
|
mod v1 {
|
||||||
use super::{npm_command, BundleTarget, UPDATER_PRIVATE_KEY};
|
use super::{BundleTarget, UPDATER_PRIVATE_KEY, npm_command};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::{
|
use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ workspace = {}
|
|||||||
[package]
|
[package]
|
||||||
name = "app-updater-v1"
|
name = "app-updater-v1"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-build = { version = "1", features = [] }
|
tauri-build = { version = "1", features = [] }
|
||||||
|
|||||||
@@ -21,12 +21,11 @@ mod transfer_stats;
|
|||||||
use transfer_stats::TransferStats;
|
use transfer_stats::TransferStats;
|
||||||
|
|
||||||
use futures_util::TryStreamExt;
|
use futures_util::TryStreamExt;
|
||||||
use serde::{ser::Serializer, Deserialize, Serialize};
|
use serde::{Deserialize, Serialize, ser::Serializer};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
command,
|
Runtime, command,
|
||||||
ipc::Channel,
|
ipc::Channel,
|
||||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||||
Runtime,
|
|
||||||
};
|
};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
fs::File,
|
fs::File,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
name = "websocket-example"
|
name = "websocket-example"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "A Tauri App"
|
description = "A Tauri App"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
|||||||
@@ -18,13 +18,13 @@
|
|||||||
html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
|
html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
|
||||||
)]
|
)]
|
||||||
|
|
||||||
use futures_util::{stream::SplitSink, SinkExt, StreamExt};
|
use futures_util::{SinkExt, StreamExt, stream::SplitSink};
|
||||||
use http::header::{HeaderName, HeaderValue};
|
use http::header::{HeaderName, HeaderValue};
|
||||||
use serde::{ser::Serializer, Deserialize, Serialize};
|
use serde::{Deserialize, Serialize, ser::Serializer};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
|
Manager, Runtime, State, Window,
|
||||||
ipc::Channel,
|
ipc::Channel,
|
||||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||||
Manager, Runtime, State, Window,
|
|
||||||
};
|
};
|
||||||
use tokio::{net::TcpStream, sync::Mutex};
|
use tokio::{net::TcpStream, sync::Mutex};
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
@@ -40,12 +40,12 @@ use tokio_tungstenite::connect_async_tls_with_config;
|
|||||||
)))]
|
)))]
|
||||||
use tokio_tungstenite::connect_async_with_config;
|
use tokio_tungstenite::connect_async_with_config;
|
||||||
use tokio_tungstenite::{
|
use tokio_tungstenite::{
|
||||||
|
Connector, MaybeTlsStream, WebSocketStream,
|
||||||
tungstenite::{
|
tungstenite::{
|
||||||
|
Message,
|
||||||
client::IntoClientRequest,
|
client::IntoClientRequest,
|
||||||
protocol::{CloseFrame as ProtocolCloseFrame, WebSocketConfig},
|
protocol::{CloseFrame as ProtocolCloseFrame, WebSocketConfig},
|
||||||
Message,
|
|
||||||
},
|
},
|
||||||
Connector, MaybeTlsStream, WebSocketStream,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use crate::{AppHandleExt, StateFlags, WindowExt};
|
use crate::{AppHandleExt, StateFlags, WindowExt};
|
||||||
use tauri::{command, AppHandle, Manager, Runtime};
|
use tauri::{AppHandle, Manager, Runtime, command};
|
||||||
|
|
||||||
fn get_state_flags<R: Runtime>(
|
fn get_state_flags<R: Runtime>(
|
||||||
app: &AppHandle<R>,
|
app: &AppHandle<R>,
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
|
||||||
AppHandle, Manager, Monitor, PhysicalPosition, PhysicalSize, RunEvent, Runtime, WebviewWindow,
|
AppHandle, Manager, Monitor, PhysicalPosition, PhysicalSize, RunEvent, Runtime, WebviewWindow,
|
||||||
Window, WindowEvent,
|
Window, WindowEvent,
|
||||||
|
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
|||||||
Reference in New Issue
Block a user