mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-06-06 13:53:54 +02:00
feat: use tauri next branch, fix tests, MSRV 1.65 (#354)
This commit is contained in:
committed by
GitHub
parent
e0e7b4fc71
commit
937e6a5be6
@@ -4,7 +4,7 @@ This plugin provides APIs to read application metadata and macOS app visibility
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Use hardware security-keys in your Tauri App.
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Automatically launch your application at startup. Supports Windows, Mac (via App
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ pub fn init<R: Runtime>(
|
||||
let exe_path = current_exe.canonicalize()?.display().to_string();
|
||||
let parts: Vec<&str> = exe_path.split(".app/").collect();
|
||||
let app_path = if parts.len() == 2 {
|
||||
format!("{}.app", parts.get(0).unwrap().to_string())
|
||||
format!("{}.app", parts.first().unwrap())
|
||||
} else {
|
||||
exe_path
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -72,10 +72,10 @@ impl Matches {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri_plugin_cli::get_matches;
|
||||
/// use tauri_plugin_cli::CliExt;
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// let matches = get_matches(app.config().tauri.cli.as_ref().unwrap(), app.package_info())?;
|
||||
/// let matches = app.cli().matches()?;
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
+35
-35
@@ -324,12 +324,12 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri::api::dialog::FileDialogBuilder;
|
||||
/// use tauri_plugin_dialog::DialogExt;
|
||||
/// tauri::Builder::default()
|
||||
/// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
|
||||
/// .build(tauri::generate_context!("test/tauri.conf.json"))
|
||||
/// .expect("failed to build tauri app")
|
||||
/// .run(|_app, _event| {
|
||||
/// FileDialogBuilder::new().pick_file(|file_path| {
|
||||
/// .run(|app, _event| {
|
||||
/// app.dialog().file().pick_file(|file_path| {
|
||||
/// // do something with the optional file path here
|
||||
/// // the file path is `None` if the user closed the dialog
|
||||
/// })
|
||||
@@ -348,12 +348,12 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri::api::dialog::FileDialogBuilder;
|
||||
/// use tauri_plugin_dialog::DialogExt;
|
||||
/// tauri::Builder::default()
|
||||
/// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
|
||||
/// .build(tauri::generate_context!("test/tauri.conf.json"))
|
||||
/// .expect("failed to build tauri app")
|
||||
/// .run(|_app, _event| {
|
||||
/// FileDialogBuilder::new().pick_files(|file_paths| {
|
||||
/// .run(|app, _event| {
|
||||
/// app.dialog().file().pick_files(|file_paths| {
|
||||
/// // do something with the optional file paths here
|
||||
/// // the file paths value is `None` if the user closed the dialog
|
||||
/// })
|
||||
@@ -378,12 +378,12 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri::api::dialog::FileDialogBuilder;
|
||||
/// use tauri_plugin_dialog::DialogExt;
|
||||
/// tauri::Builder::default()
|
||||
/// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
|
||||
/// .build(tauri::generate_context!("test/tauri.conf.json"))
|
||||
/// .expect("failed to build tauri app")
|
||||
/// .run(|_app, _event| {
|
||||
/// FileDialogBuilder::new().pick_folder(|folder_path| {
|
||||
/// .run(|app, _event| {
|
||||
/// app.dialog().file().pick_folder(|folder_path| {
|
||||
/// // do something with the optional folder path here
|
||||
/// // the folder path is `None` if the user closed the dialog
|
||||
/// })
|
||||
@@ -401,12 +401,12 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri::api::dialog::FileDialogBuilder;
|
||||
/// use tauri_plugin_dialog::DialogExt;
|
||||
/// tauri::Builder::default()
|
||||
/// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
|
||||
/// .build(tauri::generate_context!("test/tauri.conf.json"))
|
||||
/// .expect("failed to build tauri app")
|
||||
/// .run(|_app, _event| {
|
||||
/// FileDialogBuilder::new().pick_folders(|file_paths| {
|
||||
/// .run(|app, _event| {
|
||||
/// app.dialog().file().pick_folders(|file_paths| {
|
||||
/// // do something with the optional folder paths here
|
||||
/// // the folder paths value is `None` if the user closed the dialog
|
||||
/// })
|
||||
@@ -425,12 +425,12 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri::api::dialog::FileDialogBuilder;
|
||||
/// use tauri_plugin_dialog::DialogExt;
|
||||
/// tauri::Builder::default()
|
||||
/// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
|
||||
/// .build(tauri::generate_context!("test/tauri.conf.json"))
|
||||
/// .expect("failed to build tauri app")
|
||||
/// .run(|_app, _event| {
|
||||
/// FileDialogBuilder::new().save_file(|file_path| {
|
||||
/// .run(|app, _event| {
|
||||
/// app.dialog().file().save_file(|file_path| {
|
||||
/// // do something with the optional file path here
|
||||
/// // the file path is `None` if the user closed the dialog
|
||||
/// })
|
||||
@@ -451,10 +451,10 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri::api::dialog::blocking::FileDialogBuilder;
|
||||
/// use tauri_plugin_dialog::DialogExt;
|
||||
/// #[tauri::command]
|
||||
/// async fn my_command() {
|
||||
/// let file_path = FileDialogBuilder::new().pick_file();
|
||||
/// async fn my_command(app: tauri::AppHandle) {
|
||||
/// let file_path = app.dialog().file().blocking_pick_file();
|
||||
/// // do something with the optional file path here
|
||||
/// // the file path is `None` if the user closed the dialog
|
||||
/// }
|
||||
@@ -470,10 +470,10 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri::api::dialog::blocking::FileDialogBuilder;
|
||||
/// use tauri_plugin_dialog::DialogExt;
|
||||
/// #[tauri::command]
|
||||
/// async fn my_command() {
|
||||
/// let file_path = FileDialogBuilder::new().pick_files();
|
||||
/// async fn my_command(app: tauri::AppHandle) {
|
||||
/// let file_path = app.dialog().file().blocking_pick_files();
|
||||
/// // do something with the optional file paths here
|
||||
/// // the file paths value is `None` if the user closed the dialog
|
||||
/// }
|
||||
@@ -489,10 +489,10 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri::api::dialog::blocking::FileDialogBuilder;
|
||||
/// use tauri_plugin_dialog::DialogExt;
|
||||
/// #[tauri::command]
|
||||
/// async fn my_command() {
|
||||
/// let folder_path = FileDialogBuilder::new().pick_folder();
|
||||
/// async fn my_command(app: tauri::AppHandle) {
|
||||
/// let folder_path = app.dialog().file().blocking_pick_folder();
|
||||
/// // do something with the optional folder path here
|
||||
/// // the folder path is `None` if the user closed the dialog
|
||||
/// }
|
||||
@@ -509,10 +509,10 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri::api::dialog::blocking::FileDialogBuilder;
|
||||
/// use tauri_plugin_dialog::DialogExt;
|
||||
/// #[tauri::command]
|
||||
/// async fn my_command() {
|
||||
/// let folder_paths = FileDialogBuilder::new().pick_folders();
|
||||
/// async fn my_command(app: tauri::AppHandle) {
|
||||
/// let folder_paths = app.dialog().file().blocking_pick_folders();
|
||||
/// // do something with the optional folder paths here
|
||||
/// // the folder paths value is `None` if the user closed the dialog
|
||||
/// }
|
||||
@@ -529,10 +529,10 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri::api::dialog::blocking::FileDialogBuilder;
|
||||
/// use tauri_plugin_dialog::DialogExt;
|
||||
/// #[tauri::command]
|
||||
/// async fn my_command() {
|
||||
/// let file_path = FileDialogBuilder::new().save_file();
|
||||
/// async fn my_command(app: tauri::AppHandle) {
|
||||
/// let file_path = app.dialog().file().blocking_save_file();
|
||||
/// // do something with the optional file path here
|
||||
/// // the file path is `None` if the user closed the dialog
|
||||
/// }
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/.pnpm/@tauri-apps+cli@2.0.0-alpha.8/node_modules/@tauri-apps/cli/schema.json",
|
||||
"build": {
|
||||
"distDir": ".",
|
||||
"devPath": "http://localhost:4000"
|
||||
},
|
||||
"tauri": {
|
||||
"bundle": {
|
||||
"identifier": "studio.tauri.example",
|
||||
"active": true,
|
||||
"icon": ["../../../examples/api/src-tauri/icons/icon.png"]
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"title": "Tauri App"
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ Watch files and directories for changes using [notify](https://github.com/notify
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import { invoke } from "@tauri-apps/api/tauri";
|
||||
import { UnlistenFn } from "@tauri-apps/api/event";
|
||||
import { appWindow, WebviewWindow } from "tauri-plugin-window-api";
|
||||
|
||||
const w: WebviewWindow = appWindow;
|
||||
import { invoke, transformCallback } from "@tauri-apps/api/tauri";
|
||||
|
||||
export interface WatchOptions {
|
||||
recursive?: boolean;
|
||||
@@ -42,11 +38,39 @@ async function unwatch(id: number): Promise<void> {
|
||||
await invoke("plugin:fs-watch|unwatch", { id });
|
||||
}
|
||||
|
||||
// TODO: use channel from @tauri-apps/api on v2
|
||||
class Channel<T = unknown> {
|
||||
id: number;
|
||||
// @ts-expect-error field used by the IPC serializer
|
||||
private readonly __TAURI_CHANNEL_MARKER__ = true;
|
||||
#onmessage: (response: T) => void = () => {
|
||||
// no-op
|
||||
};
|
||||
|
||||
constructor() {
|
||||
this.id = transformCallback((response: T) => {
|
||||
this.#onmessage(response);
|
||||
});
|
||||
}
|
||||
|
||||
set onmessage(handler: (response: T) => void) {
|
||||
this.#onmessage = handler;
|
||||
}
|
||||
|
||||
get onmessage(): (response: T) => void {
|
||||
return this.#onmessage;
|
||||
}
|
||||
|
||||
toJSON(): string {
|
||||
return `__CHANNEL__:${this.id}`;
|
||||
}
|
||||
}
|
||||
|
||||
export async function watch(
|
||||
paths: string | string[],
|
||||
cb: (event: DebouncedEvent) => void,
|
||||
options: DebouncedWatchOptions = {}
|
||||
): Promise<UnlistenFn> {
|
||||
): Promise<() => void> {
|
||||
const opts = {
|
||||
recursive: false,
|
||||
delayMs: 2000,
|
||||
@@ -61,22 +85,18 @@ export async function watch(
|
||||
|
||||
const id = window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||
|
||||
const onEvent = new Channel<DebouncedEvent>();
|
||||
onEvent.onmessage = cb;
|
||||
|
||||
await invoke("plugin:fs-watch|watch", {
|
||||
id,
|
||||
paths: watchPaths,
|
||||
options: opts,
|
||||
onEvent,
|
||||
});
|
||||
|
||||
const unlisten = await w.listen<DebouncedEvent>(
|
||||
`watcher://debounced-event/${id}`,
|
||||
(event) => {
|
||||
cb(event.payload);
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
void unwatch(id);
|
||||
unlisten();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -84,7 +104,7 @@ export async function watchImmediate(
|
||||
paths: string | string[],
|
||||
cb: (event: RawEvent) => void,
|
||||
options: WatchOptions = {}
|
||||
): Promise<UnlistenFn> {
|
||||
): Promise<() => void> {
|
||||
const opts = {
|
||||
recursive: false,
|
||||
...options,
|
||||
@@ -99,21 +119,17 @@ export async function watchImmediate(
|
||||
|
||||
const id = window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||
|
||||
const onEvent = new Channel<RawEvent>();
|
||||
onEvent.onmessage = cb;
|
||||
|
||||
await invoke("plugin:fs-watch|watch", {
|
||||
id,
|
||||
paths: watchPaths,
|
||||
options: opts,
|
||||
onEvent,
|
||||
});
|
||||
|
||||
const unlisten = await w.listen<RawEvent>(
|
||||
`watcher://raw-event/${id}`,
|
||||
(event) => {
|
||||
cb(event.payload);
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
void unwatch(id);
|
||||
unlisten();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
"tslib": "^2.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0",
|
||||
"tauri-plugin-window-api": "0.0.0"
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@ use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Watcher};
|
||||
use notify_debouncer_mini::{new_debouncer, DebounceEventResult, Debouncer};
|
||||
use serde::{ser::Serializer, Deserialize, Serialize};
|
||||
use tauri::{
|
||||
api::ipc::Channel,
|
||||
command,
|
||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||
Manager, Runtime, State, Window,
|
||||
Manager, Runtime, State,
|
||||
};
|
||||
|
||||
use std::{
|
||||
@@ -44,25 +45,23 @@ enum WatcherKind {
|
||||
Watcher(RecommendedWatcher),
|
||||
}
|
||||
|
||||
fn watch_raw<R: Runtime>(window: Window<R>, rx: Receiver<notify::Result<Event>>, id: Id) {
|
||||
fn watch_raw<R: Runtime>(on_event: Channel<R>, rx: Receiver<notify::Result<Event>>) {
|
||||
spawn(move || {
|
||||
let event_name = format!("watcher://raw-event/{id}");
|
||||
while let Ok(event) = rx.recv() {
|
||||
if let Ok(event) = event {
|
||||
// TODO: Should errors be emitted too?
|
||||
let _ = window.emit(&event_name, event);
|
||||
let _ = on_event.send(&event);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn watch_debounced<R: Runtime>(window: Window<R>, rx: Receiver<DebounceEventResult>, id: Id) {
|
||||
fn watch_debounced<R: Runtime>(on_event: Channel<R>, rx: Receiver<DebounceEventResult>) {
|
||||
spawn(move || {
|
||||
let event_name = format!("watcher://debounced-event/{id}");
|
||||
while let Ok(event) = rx.recv() {
|
||||
if let Ok(event) = event {
|
||||
// TODO: Should errors be emitted too?
|
||||
let _ = window.emit(&event_name, event);
|
||||
let _ = on_event.send(&event);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -77,11 +76,11 @@ struct WatchOptions {
|
||||
|
||||
#[command]
|
||||
async fn watch<R: Runtime>(
|
||||
window: Window<R>,
|
||||
watchers: State<'_, WatcherCollection>,
|
||||
id: Id,
|
||||
paths: Vec<PathBuf>,
|
||||
options: WatchOptions,
|
||||
on_event: Channel<R>,
|
||||
) -> Result<()> {
|
||||
let mode = if options.recursive {
|
||||
RecursiveMode::Recursive
|
||||
@@ -96,7 +95,7 @@ async fn watch<R: Runtime>(
|
||||
for path in &paths {
|
||||
watcher.watch(path, mode)?;
|
||||
}
|
||||
watch_debounced(window, rx, id);
|
||||
watch_debounced(on_event, rx);
|
||||
WatcherKind::Debouncer(debouncer)
|
||||
} else {
|
||||
let (tx, rx) = channel();
|
||||
@@ -104,7 +103,7 @@ async fn watch<R: Runtime>(
|
||||
for path in &paths {
|
||||
watcher.watch(path, mode)?;
|
||||
}
|
||||
watch_raw(window, rx, id);
|
||||
watch_raw(on_event, rx);
|
||||
WatcherKind::Watcher(watcher)
|
||||
};
|
||||
|
||||
|
||||
+7
-13
@@ -2,21 +2,15 @@
|
||||
name = "tauri-plugin-fs"
|
||||
version = "0.0.0"
|
||||
description = "Access the file system."
|
||||
edition = "2021"
|
||||
#authors.workspace = true
|
||||
#license.workspace = true
|
||||
#edition.workspace = true
|
||||
#rust-version.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
#serde.workspace = true
|
||||
#serde_json.workspace = true
|
||||
#tauri.workspace = true
|
||||
#log.workspace = true
|
||||
#thiserror.workspace = true
|
||||
serde = "1"
|
||||
thiserror = "1"
|
||||
tauri = { git = "https://github.com/tauri-apps/tauri", branch = "next" }
|
||||
serde.workspace = true
|
||||
tauri.workspace = true
|
||||
thiserror.workspace = true
|
||||
anyhow = "1"
|
||||
|
||||
@@ -4,7 +4,7 @@ Access the file system.
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
+7
-14
@@ -1,22 +1,15 @@
|
||||
[package]
|
||||
name = "tauri-plugin-http"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
#edition.workspace = true
|
||||
#authors.workspace = true
|
||||
#license.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
#serde.workspace = true
|
||||
#serde_json.workspace = true
|
||||
#tauri.workspace = true
|
||||
#log.workspace = true
|
||||
#thiserror.workspace = true
|
||||
tauri = { git = "https://github.com/tauri-apps/tauri", branch = "next" }
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
thiserror = "1"
|
||||
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
tauri.workspace = true
|
||||
thiserror.workspace = true
|
||||
glob = "0.3"
|
||||
rand = "0.8"
|
||||
bytes = { version = "1", features = [ "serde" ] }
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use tauri::{path::SafePathBuf, AppHandle, Runtime, State};
|
||||
|
||||
use crate::{
|
||||
|
||||
ClientId, Http,
|
||||
};
|
||||
use crate::{ClientId, Http};
|
||||
|
||||
mod client;
|
||||
use client::{Body, ClientBuilder, FilePart, FormPart, HttpRequestBuilder, ResponseData};
|
||||
|
||||
+10
-14
@@ -38,12 +38,12 @@ impl Scope {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use tauri_utils::config::HttpAllowlistScope;
|
||||
use tauri::utils::config::HttpAllowlistScope;
|
||||
|
||||
#[test]
|
||||
fn is_allowed() {
|
||||
// plain URL
|
||||
let scope = super::Scope::for_http_api(&HttpAllowlistScope(vec!["http://localhost:8080"
|
||||
let scope = super::Scope::new(&HttpAllowlistScope(vec!["http://localhost:8080"
|
||||
.parse()
|
||||
.unwrap()]));
|
||||
assert!(scope.is_allowed(&"http://localhost:8080".parse().unwrap()));
|
||||
@@ -56,10 +56,9 @@ mod tests {
|
||||
assert!(!scope.is_allowed(&"http://local:8080".parse().unwrap()));
|
||||
|
||||
// URL with fixed path
|
||||
let scope =
|
||||
super::Scope::for_http_api(&HttpAllowlistScope(vec!["http://localhost:8080/file.png"
|
||||
.parse()
|
||||
.unwrap()]));
|
||||
let scope = super::Scope::new(&HttpAllowlistScope(vec!["http://localhost:8080/file.png"
|
||||
.parse()
|
||||
.unwrap()]));
|
||||
|
||||
assert!(scope.is_allowed(&"http://localhost:8080/file.png".parse().unwrap()));
|
||||
|
||||
@@ -68,25 +67,22 @@ mod tests {
|
||||
assert!(!scope.is_allowed(&"http://localhost:8080/file.png/other.jpg".parse().unwrap()));
|
||||
|
||||
// URL with glob pattern
|
||||
let scope =
|
||||
super::Scope::for_http_api(&HttpAllowlistScope(vec!["http://localhost:8080/*.png"
|
||||
.parse()
|
||||
.unwrap()]));
|
||||
let scope = super::Scope::new(&HttpAllowlistScope(vec!["http://localhost:8080/*.png"
|
||||
.parse()
|
||||
.unwrap()]));
|
||||
|
||||
assert!(scope.is_allowed(&"http://localhost:8080/file.png".parse().unwrap()));
|
||||
assert!(scope.is_allowed(&"http://localhost:8080/assets/file.png".parse().unwrap()));
|
||||
|
||||
assert!(!scope.is_allowed(&"http://localhost:8080/file.jpeg".parse().unwrap()));
|
||||
|
||||
let scope =
|
||||
super::Scope::for_http_api(&HttpAllowlistScope(vec!["http://*".parse().unwrap()]));
|
||||
let scope = super::Scope::new(&HttpAllowlistScope(vec!["http://*".parse().unwrap()]));
|
||||
|
||||
assert!(scope.is_allowed(&"http://something.else".parse().unwrap()));
|
||||
assert!(!scope.is_allowed(&"http://something.else/path/to/file".parse().unwrap()));
|
||||
assert!(!scope.is_allowed(&"https://something.else".parse().unwrap()));
|
||||
|
||||
let scope =
|
||||
super::Scope::for_http_api(&HttpAllowlistScope(vec!["http://**".parse().unwrap()]));
|
||||
let scope = super::Scope::new(&HttpAllowlistScope(vec!["http://**".parse().unwrap()]));
|
||||
|
||||
assert!(scope.is_allowed(&"http://something.else".parse().unwrap()));
|
||||
assert!(scope.is_allowed(&"http://something.else/path/to/file".parse().unwrap()));
|
||||
|
||||
@@ -6,7 +6,7 @@ Expose your apps assets through a localhost server instead of the default custom
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Configurable logging for your Tauri app.
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -72,15 +72,16 @@ mod imp {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```rust,no_run
|
||||
/// use tauri::api::notification::Notification;
|
||||
/// use tauri_plugin_notification::NotificationExt;
|
||||
/// // first we build the application to access the Tauri configuration
|
||||
/// let app = tauri::Builder::default()
|
||||
/// // on an actual app, remove the string argument
|
||||
/// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
|
||||
/// .build(tauri::generate_context!("test/tauri.conf.json"))
|
||||
/// .expect("error while building tauri application");
|
||||
///
|
||||
/// // shows a notification with the given title and body
|
||||
/// Notification::new(&app.config().tauri.bundle.identifier)
|
||||
/// app.notification()
|
||||
/// .builder()
|
||||
/// .title("New message")
|
||||
/// .body("You've got a new message.")
|
||||
/// .show();
|
||||
@@ -136,15 +137,20 @@ mod imp {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use tauri::api::notification::Notification;
|
||||
/// use tauri_plugin_notification::NotificationExt;
|
||||
///
|
||||
/// // on an actual app, remove the string argument
|
||||
/// let context = tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json");
|
||||
/// Notification::new(&context.config().tauri.bundle.identifier)
|
||||
/// .title("Tauri")
|
||||
/// .body("Tauri is awesome!")
|
||||
/// .show()
|
||||
/// .unwrap();
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// app.notification()
|
||||
/// .builder()
|
||||
/// .title("Tauri")
|
||||
/// .body("Tauri is awesome!")
|
||||
/// .show()
|
||||
/// .unwrap();
|
||||
/// Ok(())
|
||||
/// })
|
||||
/// .run(tauri::generate_context!("test/tauri.conf.json"))
|
||||
/// .expect("error while running tauri application");
|
||||
/// ```
|
||||
///
|
||||
/// ## Platform-specific
|
||||
@@ -200,22 +206,18 @@ mod imp {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use tauri::api::notification::Notification;
|
||||
///
|
||||
/// // on an actual app, remove the string argument
|
||||
/// let context = tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json");
|
||||
/// let identifier = context.config().tauri.bundle.identifier.clone();
|
||||
/// use tauri_plugin_notification::NotificationExt;
|
||||
///
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(move |app| {
|
||||
/// Notification::new(&identifier)
|
||||
/// app.notification().builder()
|
||||
/// .title("Tauri")
|
||||
/// .body("Tauri is awesome!")
|
||||
/// .notify(&app.handle())
|
||||
/// .show()
|
||||
/// .unwrap();
|
||||
/// Ok(())
|
||||
/// })
|
||||
/// .run(context)
|
||||
/// .run(tauri::generate_context!("test/tauri.conf.json"))
|
||||
/// .expect("error while running tauri application");
|
||||
/// ```
|
||||
#[cfg(feature = "windows7-compat")]
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/.pnpm/@tauri-apps+cli@2.0.0-alpha.8/node_modules/@tauri-apps/cli/schema.json",
|
||||
"build": {
|
||||
"distDir": ".",
|
||||
"devPath": "http://localhost:4000"
|
||||
},
|
||||
"tauri": {
|
||||
"bundle": {
|
||||
"identifier": "studio.tauri.example",
|
||||
"active": true,
|
||||
"icon": ["../../../examples/api/src-tauri/icons/icon.png"]
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"title": "Tauri App"
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ Read information about the operating system.
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Save filesystem and asset scopes and restore them when the app is reopened.
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ This plugin is a port of [electron-positioner](https://github.com/jenslind/elect
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ This plugin provides APIs to access the current process. To spawn child processe
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -200,24 +200,29 @@ impl Command {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri::api::process::{Command, CommandEvent};
|
||||
/// tauri::async_runtime::spawn(async move {
|
||||
/// let (mut rx, mut child) = Command::new("cargo")
|
||||
/// .args(["tauri", "dev"])
|
||||
/// .spawn()
|
||||
/// .expect("Failed to spawn cargo");
|
||||
/// use tauri_plugin_shell::{process::CommandEvent, ShellExt};
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// let handle = app.handle();
|
||||
/// tauri::async_runtime::spawn(async move {
|
||||
/// let (mut rx, mut child) = handle.shell().command("cargo")
|
||||
/// .args(["tauri", "dev"])
|
||||
/// .spawn()
|
||||
/// .expect("Failed to spawn cargo");
|
||||
///
|
||||
/// let mut i = 0;
|
||||
/// while let Some(event) = rx.recv().await {
|
||||
/// if let CommandEvent::Stdout(line) = event {
|
||||
/// println!("got: {}", String::from_utf8(line).unwrap());
|
||||
/// i += 1;
|
||||
/// if i == 4 {
|
||||
/// child.write("message from Rust\n".as_bytes()).unwrap();
|
||||
/// i = 0;
|
||||
/// let mut i = 0;
|
||||
/// while let Some(event) = rx.recv().await {
|
||||
/// if let CommandEvent::Stdout(line) = event {
|
||||
/// println!("got: {}", String::from_utf8(line).unwrap());
|
||||
/// i += 1;
|
||||
/// if i == 4 {
|
||||
/// child.write("message from Rust\n".as_bytes()).unwrap();
|
||||
/// i = 0;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// });
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
pub fn spawn(self) -> crate::Result<(Receiver<CommandEvent>, CommandChild)> {
|
||||
@@ -288,9 +293,13 @@ impl Command {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```rust,no_run
|
||||
/// use tauri::api::process::Command;
|
||||
/// let status = Command::new("which").args(["ls"]).status().unwrap();
|
||||
/// println!("`which` finished with status: {:?}", status.code());
|
||||
/// use tauri_plugin_shell::ShellExt;
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// let status = tauri::async_runtime::block_on(async move { app.shell().command("which").args(["ls"]).status().await.unwrap() });
|
||||
/// println!("`which` finished with status: {:?}", status.code());
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
pub async fn status(self) -> crate::Result<ExitStatus> {
|
||||
let (mut rx, _child) = self.spawn()?;
|
||||
@@ -310,10 +319,14 @@ impl Command {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri::api::process::Command;
|
||||
/// let output = Command::new("echo").args(["TAURI"]).output().unwrap();
|
||||
/// assert!(output.status.success());
|
||||
/// assert_eq!(String::from_utf8(output.stdout).unwrap(), "TAURI");
|
||||
/// use tauri_plugin_shell::ShellExt;
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// let output = tauri::async_runtime::block_on(async move { app.shell().command("echo").args(["TAURI"]).output().await.unwrap() });
|
||||
/// assert!(output.status.success());
|
||||
/// assert_eq!(String::from_utf8(output.stdout).unwrap(), "TAURI");
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
pub async fn output(self) -> crate::Result<Output> {
|
||||
let (mut rx, _child) = self.spawn()?;
|
||||
@@ -387,7 +400,7 @@ mod tests {
|
||||
#[cfg(not(windows))]
|
||||
#[test]
|
||||
fn test_cmd_spawn_output() {
|
||||
let cmd = Command::new("cat").args(["test/api/test.txt"]);
|
||||
let cmd = Command::new("cat").args(["test/test.txt"]);
|
||||
let (mut rx, _) = cmd.spawn().unwrap();
|
||||
|
||||
tauri::async_runtime::block_on(async move {
|
||||
@@ -408,7 +421,7 @@ mod tests {
|
||||
#[cfg(not(windows))]
|
||||
#[test]
|
||||
fn test_cmd_spawn_raw_output() {
|
||||
let cmd = Command::new("cat").args(["test/api/test.txt"]);
|
||||
let cmd = Command::new("cat").args(["test/test.txt"]);
|
||||
let (mut rx, _) = cmd.spawn().unwrap();
|
||||
|
||||
tauri::async_runtime::block_on(async move {
|
||||
@@ -430,7 +443,7 @@ mod tests {
|
||||
#[test]
|
||||
// test the failure case
|
||||
fn test_cmd_spawn_fail() {
|
||||
let cmd = Command::new("cat").args(["test/api/"]);
|
||||
let cmd = Command::new("cat").args(["test/"]);
|
||||
let (mut rx, _) = cmd.spawn().unwrap();
|
||||
|
||||
tauri::async_runtime::block_on(async move {
|
||||
@@ -442,7 +455,7 @@ mod tests {
|
||||
CommandEvent::Stderr(line) => {
|
||||
assert_eq!(
|
||||
String::from_utf8(line).unwrap(),
|
||||
"cat: test/api/: Is a directory"
|
||||
"cat: test/: Is a directory"
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
@@ -455,7 +468,7 @@ mod tests {
|
||||
#[test]
|
||||
// test the failure case (raw encoding)
|
||||
fn test_cmd_spawn_raw_fail() {
|
||||
let cmd = Command::new("cat").args(["test/api/"]);
|
||||
let cmd = Command::new("cat").args(["test/"]);
|
||||
let (mut rx, _) = cmd.spawn().unwrap();
|
||||
|
||||
tauri::async_runtime::block_on(async move {
|
||||
@@ -467,7 +480,7 @@ mod tests {
|
||||
CommandEvent::Stderr(line) => {
|
||||
assert_eq!(
|
||||
String::from_utf8(line).unwrap(),
|
||||
"cat: test/api/: Is a directory"
|
||||
"cat: test/: Is a directory"
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
@@ -479,7 +492,7 @@ mod tests {
|
||||
#[cfg(not(windows))]
|
||||
#[test]
|
||||
fn test_cmd_output_output() {
|
||||
let cmd = Command::new("cat").args(["test/api/test.txt"]);
|
||||
let cmd = Command::new("cat").args(["test/test.txt"]);
|
||||
let output = tauri::async_runtime::block_on(cmd.output()).unwrap();
|
||||
|
||||
assert_eq!(String::from_utf8(output.stderr).unwrap(), "");
|
||||
@@ -492,13 +505,13 @@ mod tests {
|
||||
#[cfg(not(windows))]
|
||||
#[test]
|
||||
fn test_cmd_output_output_fail() {
|
||||
let cmd = Command::new("cat").args(["test/api/"]);
|
||||
let cmd = Command::new("cat").args(["test/"]);
|
||||
let output = tauri::async_runtime::block_on(cmd.output()).unwrap();
|
||||
|
||||
assert_eq!(String::from_utf8(output.stdout).unwrap(), "");
|
||||
assert_eq!(
|
||||
String::from_utf8(output.stderr).unwrap(),
|
||||
"cat: test/api/: Is a directory\n"
|
||||
"cat: test/: Is a directory\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
This is a test doc!
|
||||
@@ -4,7 +4,7 @@ Ensure a single instance of your tauri app is running.
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Interface with SQL databases through [sqlx](https://github.com/launchbadge/sqlx)
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Simple, persistent key-value store.
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
+29
-34
@@ -46,7 +46,7 @@ pub fn with_store<R: Runtime, T, F: FnOnce(&mut Store<R>) -> Result<T, Error>>(
|
||||
if collection.frozen {
|
||||
return Err(Error::NotFound(path.to_path_buf()));
|
||||
}
|
||||
let mut store = StoreBuilder::new(app, path.to_path_buf()).build();
|
||||
let mut store = StoreBuilder::new(path).build(app);
|
||||
// ignore loading errors, just use the default
|
||||
if let Err(err) = store.load() {
|
||||
warn!(
|
||||
@@ -205,15 +205,14 @@ impl<R: Runtime> Builder<R> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// use tauri_plugin_store::{StoreBuilder,PluginBuilder};
|
||||
/// use tauri_plugin_store::{StoreBuilder, Builder};
|
||||
///
|
||||
/// let store = StoreBuilder::new("store.bin".parse()?).build();
|
||||
///
|
||||
/// let builder = PluginBuilder::default().store(store);
|
||||
///
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// let store = StoreBuilder::new("store.bin").build(app.handle());
|
||||
/// let builder = Builder::default().store(store);
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
pub fn store(mut self, store: Store<R>) -> Self {
|
||||
self.stores.insert(store.path.clone(), store);
|
||||
@@ -225,15 +224,14 @@ impl<R: Runtime> Builder<R> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// use tauri_plugin_store::{StoreBuilder,PluginBuilder};
|
||||
/// use tauri_plugin_store::{StoreBuilder, Builder};
|
||||
///
|
||||
/// let store = StoreBuilder::new("store.bin".parse()?).build();
|
||||
///
|
||||
/// let builder = PluginBuilder::default().stores([store]);
|
||||
///
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// let store = StoreBuilder::new("store.bin").build(app.handle());
|
||||
/// let builder = Builder::default().stores([store]);
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
pub fn stores<T: IntoIterator<Item = Store<R>>>(mut self, stores: T) -> Self {
|
||||
self.stores = stores
|
||||
@@ -250,15 +248,14 @@ impl<R: Runtime> Builder<R> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// use tauri_plugin_store::{StoreBuilder,PluginBuilder};
|
||||
/// use tauri_plugin_store::{StoreBuilder, Builder};
|
||||
///
|
||||
/// let store = StoreBuilder::new("store.bin".parse()?).build();
|
||||
///
|
||||
/// let builder = PluginBuilder::default().freeze();
|
||||
///
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// let store = StoreBuilder::new("store.bin").build(app.handle());
|
||||
/// app.handle().plugin(Builder::default().freeze().build());
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
pub fn freeze(mut self) -> Self {
|
||||
self.frozen = true;
|
||||
@@ -270,16 +267,14 @@ impl<R: Runtime> Builder<R> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// use tauri_plugin_store::{StoreBuilder,PluginBuilder};
|
||||
/// use tauri::Wry;
|
||||
/// use tauri_plugin_store::{StoreBuilder, Builder};
|
||||
///
|
||||
/// let store = StoreBuilder::new("store.bin".parse()?).build();
|
||||
///
|
||||
/// let plugin = PluginBuilder::default().build::<Wry>();
|
||||
///
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// let store = StoreBuilder::new("store.bin").build(app.handle());
|
||||
/// app.handle().plugin(Builder::default().build());
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
pub fn build(mut self) -> TauriPlugin<R> {
|
||||
plugin::Builder::new("store")
|
||||
|
||||
+18
-21
@@ -8,7 +8,7 @@ use std::{
|
||||
collections::HashMap,
|
||||
fs::{create_dir_all, read, File},
|
||||
io::Write,
|
||||
path::PathBuf,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use tauri::{AppHandle, Manager, Runtime};
|
||||
|
||||
@@ -30,8 +30,7 @@ fn default_deserialize(
|
||||
}
|
||||
|
||||
/// Builds a [`Store`]
|
||||
pub struct StoreBuilder<R: Runtime> {
|
||||
app: AppHandle<R>,
|
||||
pub struct StoreBuilder {
|
||||
path: PathBuf,
|
||||
defaults: Option<HashMap<String, JsonValue>>,
|
||||
cache: HashMap<String, JsonValue>,
|
||||
@@ -39,7 +38,7 @@ pub struct StoreBuilder<R: Runtime> {
|
||||
deserialize: DeserializeFn,
|
||||
}
|
||||
|
||||
impl<R: Runtime> StoreBuilder<R> {
|
||||
impl StoreBuilder {
|
||||
/// Creates a new [`StoreBuilder`].
|
||||
///
|
||||
/// # Examples
|
||||
@@ -47,15 +46,14 @@ impl<R: Runtime> StoreBuilder<R> {
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// use tauri_plugin_store::StoreBuilder;
|
||||
///
|
||||
/// let builder = StoreBuilder::new("store.bin".parse()?);
|
||||
/// let builder = StoreBuilder::new("store.bin");
|
||||
///
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn new(app: AppHandle<R>, path: PathBuf) -> Self {
|
||||
pub fn new<P: AsRef<Path>>(path: P) -> Self {
|
||||
Self {
|
||||
app,
|
||||
path,
|
||||
path: path.as_ref().to_path_buf(),
|
||||
defaults: None,
|
||||
cache: Default::default(),
|
||||
serialize: default_serialize,
|
||||
@@ -75,7 +73,7 @@ impl<R: Runtime> StoreBuilder<R> {
|
||||
///
|
||||
/// defaults.insert("foo".to_string(), "bar".into());
|
||||
///
|
||||
/// let builder = StoreBuilder::new("store.bin".parse()?)
|
||||
/// let builder = StoreBuilder::new("store.bin")
|
||||
/// .defaults(defaults);
|
||||
///
|
||||
/// # Ok(())
|
||||
@@ -93,7 +91,7 @@ impl<R: Runtime> StoreBuilder<R> {
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// use tauri_plugin_store::StoreBuilder;
|
||||
///
|
||||
/// let builder = StoreBuilder::new("store.bin".parse()?)
|
||||
/// let builder = StoreBuilder::new("store.bin")
|
||||
/// .default("foo".to_string(), "bar".into());
|
||||
///
|
||||
/// # Ok(())
|
||||
@@ -113,7 +111,7 @@ impl<R: Runtime> StoreBuilder<R> {
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// use tauri_plugin_store::StoreBuilder;
|
||||
///
|
||||
/// let builder = StoreBuilder::new("store.json".parse()?)
|
||||
/// let builder = StoreBuilder::new("store.json")
|
||||
/// .serialize(|cache| serde_json::to_vec(&cache).map_err(Into::into));
|
||||
///
|
||||
/// # Ok(())
|
||||
@@ -130,7 +128,7 @@ impl<R: Runtime> StoreBuilder<R> {
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// use tauri_plugin_store::StoreBuilder;
|
||||
///
|
||||
/// let builder = StoreBuilder::new("store.json".parse()?)
|
||||
/// let builder = StoreBuilder::new("store.json")
|
||||
/// .deserialize(|bytes| serde_json::from_slice(&bytes).map_err(Into::into));
|
||||
///
|
||||
/// # Ok(())
|
||||
@@ -144,16 +142,15 @@ impl<R: Runtime> StoreBuilder<R> {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// use tauri_plugin_store::StoreBuilder;
|
||||
///
|
||||
/// let store = StoreBuilder::new("store.bin".parse()?).build();
|
||||
///
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
pub fn build(self) -> Store<R> {
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// let store = tauri_plugin_store::StoreBuilder::new("store.json").build(app.handle());
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
pub fn build<R: Runtime>(self, app: AppHandle<R>) -> Store<R> {
|
||||
Store {
|
||||
app: self.app,
|
||||
app,
|
||||
path: self.path,
|
||||
defaults: self.defaults,
|
||||
cache: self.cache,
|
||||
|
||||
@@ -4,7 +4,7 @@ Store secrets and keys using the [IOTA Stronghold](https://github.com/iotaledger
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
[package]
|
||||
name = "tauri-plugin-updater"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
#edition.workspace = true
|
||||
#authors.workspace = true
|
||||
#license.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
#tauri = { workspace = true, features = ["updater"] }
|
||||
#serde.workspace = true
|
||||
#serde_json.workspace = true
|
||||
#thiserror.workspace = true
|
||||
tauri = { git = "https://github.com/tauri-apps/tauri", branch = "next", features = ["updater", "fs-extract-api"] }
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
thiserror = "1"
|
||||
tauri = { workspace = true, features = ["updater", "fs-extract-api"] }
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
||||
tokio = "1"
|
||||
reqwest = { version = "0.11", default-features = false, features = [ "json", "stream" ] }
|
||||
|
||||
@@ -4,7 +4,7 @@ In-app updates for Tauri applications.
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
[package]
|
||||
name = "app-updater"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
#edition.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { path = "../../../../../tauri/core/tauri-build", features = [] }
|
||||
tauri-build.workspace = true
|
||||
|
||||
[dependencies]
|
||||
tauri = { git = "https://github.com/tauri-apps/tauri", branch = "next" }
|
||||
tauri.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
tauri-plugin-updater = { path = "../.." }
|
||||
tiny_http = "0.11"
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
time = { version = "0.3", features = ["formatting"] }
|
||||
|
||||
[features]
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
tauri_build::build()
|
||||
}
|
||||
|
||||
@@ -7,43 +7,43 @@
|
||||
use tauri_plugin_updater::UpdaterExt;
|
||||
|
||||
fn main() {
|
||||
let mut context = tauri::generate_context!();
|
||||
if std::env::var("TARGET").unwrap_or_default() == "nsis" {
|
||||
// /D sets the default installation directory ($INSTDIR),
|
||||
// overriding InstallDir and InstallDirRegKey.
|
||||
// It must be the last parameter used in the command line and must not contain any quotes, even if the path contains spaces.
|
||||
// Only absolute paths are supported.
|
||||
// NOTE: we only need this because this is an integration test and we don't want to install the app in the programs folder
|
||||
context.config_mut().tauri.updater.windows.installer_args = vec![format!(
|
||||
"/D={}",
|
||||
tauri::utils::platform::current_exe()
|
||||
.unwrap()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.display()
|
||||
)];
|
||||
}
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||
.setup(|app| {
|
||||
let handle = app.handle();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
match handle.updater().check().await {
|
||||
Ok(update) => {
|
||||
if let Err(e) = update.download_and_install().await {
|
||||
println!("{e}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
std::process::exit(0);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{e}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
})
|
||||
.run(context)
|
||||
.expect("error while running tauri application");
|
||||
let mut context = tauri::generate_context!();
|
||||
if std::env::var("TARGET").unwrap_or_default() == "nsis" {
|
||||
// /D sets the default installation directory ($INSTDIR),
|
||||
// overriding InstallDir and InstallDirRegKey.
|
||||
// It must be the last parameter used in the command line and must not contain any quotes, even if the path contains spaces.
|
||||
// Only absolute paths are supported.
|
||||
// NOTE: we only need this because this is an integration test and we don't want to install the app in the programs folder
|
||||
context.config_mut().tauri.updater.windows.installer_args = vec![format!(
|
||||
"/D={}",
|
||||
tauri::utils::platform::current_exe()
|
||||
.unwrap()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.display()
|
||||
)];
|
||||
}
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||
.setup(|app| {
|
||||
let handle = app.handle();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
match handle.updater().check().await {
|
||||
Ok(update) => {
|
||||
if let Err(e) = update.download_and_install(|_event| {}).await {
|
||||
println!("{e}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
std::process::exit(0);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{e}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
})
|
||||
.run(context)
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ fn update_app() {
|
||||
let target =
|
||||
tauri_plugin_updater::target().expect("running updater test in an unsupported platform");
|
||||
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
let root_dir = manifest_dir.clone();
|
||||
let root_dir = manifest_dir.join("../../../..");
|
||||
|
||||
let mut config = Config {
|
||||
package: PackageConfig { version: "1.0.0" },
|
||||
|
||||
@@ -4,7 +4,7 @@ Upload files from disk to a remote server over HTTP.
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -1,30 +1,38 @@
|
||||
import { invoke } from "@tauri-apps/api/tauri";
|
||||
import { appWindow } from "tauri-plugin-window-api";
|
||||
import { invoke, transformCallback } from "@tauri-apps/api/tauri";
|
||||
|
||||
interface ProgressPayload {
|
||||
id: number;
|
||||
progress: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
type ProgressHandler = (progress: number, total: number) => void;
|
||||
const handlers: Map<number, ProgressHandler> = new Map();
|
||||
let listening = false;
|
||||
type ProgressHandler = (progress: ProgressPayload) => void;
|
||||
|
||||
async function listenToEventIfNeeded(event: string): Promise<void> {
|
||||
if (listening) {
|
||||
return await Promise.resolve();
|
||||
}
|
||||
return await appWindow
|
||||
.listen<ProgressPayload>(event, ({ payload }) => {
|
||||
const handler = handlers.get(payload.id);
|
||||
if (handler != null) {
|
||||
handler(payload.progress, payload.total);
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
listening = true;
|
||||
// TODO: use channel from @tauri-apps/api on v2
|
||||
class Channel<T = unknown> {
|
||||
id: number;
|
||||
// @ts-expect-error field used by the IPC serializer
|
||||
private readonly __TAURI_CHANNEL_MARKER__ = true;
|
||||
#onmessage: (response: T) => void = () => {
|
||||
// no-op
|
||||
};
|
||||
|
||||
constructor() {
|
||||
this.id = transformCallback((response: T) => {
|
||||
this.#onmessage(response);
|
||||
});
|
||||
}
|
||||
|
||||
set onmessage(handler: (response: T) => void) {
|
||||
this.#onmessage = handler;
|
||||
}
|
||||
|
||||
get onmessage(): (response: T) => void {
|
||||
return this.#onmessage;
|
||||
}
|
||||
|
||||
toJSON(): string {
|
||||
return `__CHANNEL__:${this.id}`;
|
||||
}
|
||||
}
|
||||
|
||||
async function upload(
|
||||
@@ -37,17 +45,17 @@ async function upload(
|
||||
window.crypto.getRandomValues(ids);
|
||||
const id = ids[0];
|
||||
|
||||
const onProgress = new Channel<ProgressPayload>();
|
||||
if (progressHandler != null) {
|
||||
handlers.set(id, progressHandler);
|
||||
onProgress.onmessage = progressHandler;
|
||||
}
|
||||
|
||||
await listenToEventIfNeeded("upload://progress");
|
||||
|
||||
await invoke("plugin:upload|upload", {
|
||||
id,
|
||||
url,
|
||||
filePath,
|
||||
headers: headers ?? {},
|
||||
onProgress,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -65,17 +73,17 @@ async function download(
|
||||
window.crypto.getRandomValues(ids);
|
||||
const id = ids[0];
|
||||
|
||||
const onProgress = new Channel<ProgressPayload>();
|
||||
if (progressHandler != null) {
|
||||
handlers.set(id, progressHandler);
|
||||
onProgress.onmessage = progressHandler;
|
||||
}
|
||||
|
||||
await listenToEventIfNeeded("download://progress");
|
||||
|
||||
await invoke("plugin:upload|download", {
|
||||
id,
|
||||
url,
|
||||
filePath,
|
||||
headers: headers ?? {},
|
||||
onProgress,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
"tslib": "^2.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0",
|
||||
"tauri-plugin-window-api": "0.0.0"
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
+15
-28
@@ -5,16 +5,17 @@
|
||||
use futures_util::TryStreamExt;
|
||||
use serde::{ser::Serializer, Serialize};
|
||||
use tauri::{
|
||||
api::ipc::Channel,
|
||||
command,
|
||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||
Runtime, Window,
|
||||
Runtime,
|
||||
};
|
||||
use tokio::{fs::File, io::AsyncWriteExt};
|
||||
use tokio_util::codec::{BytesCodec, FramedRead};
|
||||
|
||||
use read_progress_stream::ReadProgressStream;
|
||||
|
||||
use std::{collections::HashMap, sync::Mutex};
|
||||
use std::collections::HashMap;
|
||||
|
||||
type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
@@ -39,19 +40,17 @@ impl Serialize for Error {
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
struct ProgressPayload {
|
||||
id: u32,
|
||||
progress: u64,
|
||||
total: u64,
|
||||
}
|
||||
|
||||
#[command]
|
||||
async fn download<R: Runtime>(
|
||||
window: Window<R>,
|
||||
id: u32,
|
||||
url: &str,
|
||||
file_path: &str,
|
||||
headers: HashMap<String, String>,
|
||||
) -> Result<u32> {
|
||||
on_progress: Channel<R>,
|
||||
) -> Result<()> {
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let mut request = client.get(url);
|
||||
@@ -69,33 +68,28 @@ async fn download<R: Runtime>(
|
||||
|
||||
while let Some(chunk) = stream.try_next().await? {
|
||||
file.write_all(&chunk).await?;
|
||||
let _ = window.emit(
|
||||
"download://progress",
|
||||
ProgressPayload {
|
||||
id,
|
||||
progress: chunk.len() as u64,
|
||||
total,
|
||||
},
|
||||
);
|
||||
let _ = on_progress.send(&ProgressPayload {
|
||||
progress: chunk.len() as u64,
|
||||
total,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(id)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command]
|
||||
async fn upload<R: Runtime>(
|
||||
window: Window<R>,
|
||||
id: u32,
|
||||
url: &str,
|
||||
file_path: &str,
|
||||
headers: HashMap<String, String>,
|
||||
on_progress: Channel<R>,
|
||||
) -> Result<serde_json::Value> {
|
||||
// Read the file
|
||||
let file = File::open(file_path).await?;
|
||||
|
||||
// Create the request and attach the file to the body
|
||||
let client = reqwest::Client::new();
|
||||
let mut request = client.post(url).body(file_to_body(id, window, file));
|
||||
let mut request = client.post(url).body(file_to_body(on_progress, file));
|
||||
|
||||
// Loop trought the headers keys and values
|
||||
// and add them to the request object.
|
||||
@@ -108,20 +102,13 @@ async fn upload<R: Runtime>(
|
||||
response.json().await.map_err(Into::into)
|
||||
}
|
||||
|
||||
fn file_to_body<R: Runtime>(id: u32, window: Window<R>, file: File) -> reqwest::Body {
|
||||
fn file_to_body<R: Runtime>(channel: Channel<R>, file: File) -> reqwest::Body {
|
||||
let stream = FramedRead::new(file, BytesCodec::new()).map_ok(|r| r.freeze());
|
||||
let window = Mutex::new(window);
|
||||
|
||||
reqwest::Body::wrap_stream(ReadProgressStream::new(
|
||||
stream,
|
||||
Box::new(move |progress, total| {
|
||||
let _ = window.lock().unwrap().emit(
|
||||
"upload://progress",
|
||||
ProgressPayload {
|
||||
id,
|
||||
progress,
|
||||
total,
|
||||
},
|
||||
);
|
||||
let _ = channel.send(&ProgressPayload { progress, total });
|
||||
}),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Save window positions and sizes and restore them when the app is reopened.
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
import { invoke } from "@tauri-apps/api/tauri";
|
||||
import { WindowLabel, getCurrent } from "tauri-plugin-window-api";
|
||||
|
||||
interface WindowDef {
|
||||
label: string;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__TAURI_METADATA__: {
|
||||
__windows: WindowDef[];
|
||||
__currentWindow: WindowDef;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export enum StateFlags {
|
||||
SIZE = 1 << 0,
|
||||
@@ -21,7 +33,7 @@ async function saveWindowState(flags: StateFlags) {
|
||||
/**
|
||||
* Restore the state for the specified window from disk.
|
||||
*/
|
||||
async function restoreState(label: WindowLabel, flags: StateFlags) {
|
||||
async function restoreState(label: string, flags: StateFlags) {
|
||||
invoke("plugin:window-state|restore_state", { label, flags });
|
||||
}
|
||||
|
||||
@@ -29,7 +41,7 @@ async function restoreState(label: WindowLabel, flags: StateFlags) {
|
||||
* Restore the state for the current window from disk.
|
||||
*/
|
||||
async function restoreStateCurrent(flags: StateFlags) {
|
||||
restoreState(getCurrent().label, flags);
|
||||
restoreState(window.__TAURI_METADATA__.__currentWindow.label, flags);
|
||||
}
|
||||
|
||||
export { restoreState, restoreStateCurrent, saveWindowState };
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
"tslib": "^2.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0",
|
||||
"tauri-plugin-window-api": "0.0.0"
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ Interact with the Tauri window.
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user