Add tauri_plugin_single_instance

This commit is contained in:
kwaroran
2024-10-09 21:12:06 +09:00
parent 833c2ad39c
commit 19d1c1ef7a
3 changed files with 109 additions and 54 deletions

46
src-tauri/Cargo.lock generated
View File

@@ -127,6 +127,30 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
] ]
[[package]]
name = "async-executor"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec"
dependencies = [
"async-task",
"concurrent-queue",
"fastrand",
"futures-lite",
"slab",
]
[[package]]
name = "async-fs"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a"
dependencies = [
"async-lock",
"blocking",
"futures-lite",
]
[[package]] [[package]]
name = "async-io" name = "async-io"
version = "2.3.4" version = "2.3.4"
@@ -3508,6 +3532,7 @@ dependencies = [
"tauri-plugin-os", "tauri-plugin-os",
"tauri-plugin-process", "tauri-plugin-process",
"tauri-plugin-shell", "tauri-plugin-shell",
"tauri-plugin-single-instance",
"tauri-plugin-updater", "tauri-plugin-updater",
"tiktoken-rs", "tiktoken-rs",
"url", "url",
@@ -4519,6 +4544,21 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "tauri-plugin-single-instance"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a25ac834491d089699a2bc9266a662faf373c9f779f05a2235bc6e4d9e61769a"
dependencies = [
"log",
"serde",
"serde_json",
"tauri",
"thiserror",
"windows-sys 0.59.0",
"zbus",
]
[[package]] [[package]]
name = "tauri-plugin-updater" name = "tauri-plugin-updater"
version = "2.0.2" version = "2.0.2"
@@ -5872,9 +5912,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b8e3d6ae3342792a6cc2340e4394334c7402f3d793b390d2c5494a4032b3030" checksum = "7b8e3d6ae3342792a6cc2340e4394334c7402f3d793b390d2c5494a4032b3030"
dependencies = [ dependencies = [
"async-broadcast", "async-broadcast",
"async-executor",
"async-fs",
"async-io",
"async-lock",
"async-process", "async-process",
"async-recursion", "async-recursion",
"async-task",
"async-trait", "async-trait",
"blocking",
"derivative", "derivative",
"enumflags2", "enumflags2",
"event-listener", "event-listener",

View File

@@ -42,4 +42,5 @@ custom-protocol = ["tauri/custom-protocol"]
# crate-type = ["staticlib", "cdylib", "rlib", "lib"] # crate-type = ["staticlib", "cdylib", "rlib", "lib"]
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
tauri-plugin-single-instance = "2"
tauri-plugin-updater = "2" tauri-plugin-updater = "2"

View File

@@ -10,10 +10,10 @@ use base64::{engine::general_purpose, Engine as _};
use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
use serde_json::json; use serde_json::json;
use serde_json::Value; use serde_json::Value;
use tauri::path::BaseDirectory;
use std::collections::HashMap; use std::collections::HashMap;
use std::io::Write; use std::io::Write;
use std::{path::Path, time::Duration}; use std::{path::Path, time::Duration};
use tauri::path::BaseDirectory;
use tauri::Manager; use tauri::Manager;
use tauri::{AppHandle, Emitter}; use tauri::{AppHandle, Emitter};
@@ -305,7 +305,7 @@ fn run_py_server(handle: tauri::AppHandle, py_path: String) {
let py_exec_path = Path::new(&py_path).join("python").join("python.exe"); let py_exec_path = Path::new(&py_path).join("python").join("python.exe");
let server_path = handle let server_path = handle
.path() .path()
.resolve("src-python/run.py", BaseDirectory::Resource) .resolve("src-python/run.py", BaseDirectory::Resource)
.expect("failed to resolve resource"); .expect("failed to resolve resource");
let mut py_server = Command::new(&py_exec_path); let mut py_server = Command::new(&py_exec_path);
@@ -326,14 +326,13 @@ fn run_py_server(handle: tauri::AppHandle, py_path: String) {
return; return;
} }
#[tauri::command] #[tauri::command]
async fn streamed_fetch( async fn streamed_fetch(
id: String, id: String,
url: String, url: String,
headers: String, headers: String,
body: String, body: String,
app: AppHandle app: AppHandle,
) -> String { ) -> String {
//parse headers //parse headers
let headers_json: Value = match serde_json::from_str(&headers) { let headers_json: Value = match serde_json::from_str(&headers) {
@@ -419,50 +418,60 @@ async fn streamed_fetch(
} }
} }
use std::path::PathBuf; use std::path::PathBuf;
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy // Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
fn handle_file_associations(app: AppHandle, files: Vec<PathBuf>) { fn handle_file_associations(app: AppHandle, files: Vec<PathBuf>) {
// -- Scope handling start -- // -- Scope handling start --
// You can remove this block if you only want to know about the paths, but not actually "use" them in the frontend. // You can remove this block if you only want to know about the paths, but not actually "use" them in the frontend.
// This requires the `fs` tauri plugin and is required to make the plugin's frontend work: // This requires the `fs` tauri plugin and is required to make the plugin's frontend work:
// use tauri_plugin_fs::FsExt; // use tauri_plugin_fs::FsExt;
// let fs_scope = app.fs_scope(); // let fs_scope = app.fs_scope();
// This is for the `asset:` protocol to work: // This is for the `asset:` protocol to work:
let asset_protocol_scope = app.asset_protocol_scope(); let asset_protocol_scope = app.asset_protocol_scope();
for file in &files { for file in &files {
// This requires the `fs` plugin: // This requires the `fs` plugin:
// let _ = fs_scope.allow_file(file); // let _ = fs_scope.allow_file(file);
// This is for the `asset:` protocol: // This is for the `asset:` protocol:
let _ = asset_protocol_scope.allow_file(file); let _ = asset_protocol_scope.allow_file(file);
} }
// -- Scope handling end -- // -- Scope handling end --
let files = files let files = files
.into_iter() .into_iter()
.map(|f| { .map(|f| {
let file = f.to_string_lossy().replace("\\", "\\\\"); // escape backslash let file = f.to_string_lossy().replace("\\", "\\\\"); // escape backslash
format!("\"{file}\"",) // wrap in quotes for JS array format!("\"{file}\"",) // wrap in quotes for JS array
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(","); .join(",");
tauri::WebviewWindowBuilder::new(&app, "main", Default::default()) tauri::WebviewWindowBuilder::new(&app, "main", Default::default())
.initialization_script(&format!("window.tauriOpenedFiles = [{files}]")) .initialization_script(&format!("window.tauriOpenedFiles = [{files}]"))
.build() .build()
.unwrap(); .unwrap();
} }
fn main() { fn main() {
tauri::Builder::default() let mut builder = tauri::Builder::default();
#[cfg(desktop)]
{
builder = builder.plugin(tauri_plugin_single_instance::init(|app, args, cwd| {
let _ = app.get_webview_window("main")
.expect("no main window")
.set_focus();
}));
}
builder
.plugin(tauri_plugin_http::init()) .plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_shell::init()) .plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_process::init()) .plugin(tauri_plugin_process::init())
@@ -474,29 +483,29 @@ fn main() {
#[cfg(any(windows, target_os = "linux"))] #[cfg(any(windows, target_os = "linux"))]
{ {
let mut files = Vec::new(); let mut files = Vec::new();
// NOTICE: `args` may include URL protocol (`your-app-protocol://`) // NOTICE: `args` may include URL protocol (`your-app-protocol://`)
// or arguments (`--`) if your app supports them. // or arguments (`--`) if your app supports them.
// files may aslo be passed as `file://path/to/file` // files may aslo be passed as `file://path/to/file`
for maybe_file in std::env::args().skip(1) { for maybe_file in std::env::args().skip(1) {
// skip flags like -f or --flag // skip flags like -f or --flag
if maybe_file.starts_with("-") { if maybe_file.starts_with("-") {
continue; continue;
} }
// handle `file://` path urls and skip other urls // handle `file://` path urls and skip other urls
if let Ok(url) = url::Url::parse(&maybe_file) { if let Ok(url) = url::Url::parse(&maybe_file) {
if let Ok(path) = url.to_file_path() { if let Ok(path) = url.to_file_path() {
files.push(path); files.push(path);
}
} else {
files.push(PathBuf::from(maybe_file))
} }
} else {
files.push(PathBuf::from(maybe_file))
} }
}
handle_file_associations(app.handle().clone(), files); handle_file_associations(app.handle().clone(), files);
} }
Ok(()) Ok(())
}) })
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
@@ -519,18 +528,17 @@ fn main() {
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#[allow(unused_variables)] #[allow(unused_variables)]
|app, event| { |app, event| {
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios"))]
if let tauri::RunEvent::Opened { urls } = event { if let tauri::RunEvent::Opened { urls } = event {
let files = urls let files = urls
.into_iter() .into_iter()
.filter_map(|url| url.to_file_path().ok()) .filter_map(|url| url.to_file_path().ok())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
handle_file_associations(app.clone(), files); handle_file_associations(app.clone(), files);
} }
}, },
); );
} }
fn header_map_to_json(header_map: &HeaderMap) -> serde_json::Value { fn header_map_to_json(header_map: &HeaderMap) -> serde_json::Value {