From 34725b517b249b3b341fe02459457f77ca24df1d Mon Sep 17 00:00:00 2001
From: GyDi <segydi@foxmail.com>
Date: Thu, 23 Dec 2021 01:35:17 +0800
Subject: [PATCH] feat: implement a simple singleton process

---
 src-tauri/Cargo.lock          | 232 ++++++++++++++++++++++++++++++++++
 src-tauri/Cargo.toml          |   2 +
 src-tauri/src/main.rs         |  14 +-
 src-tauri/src/utils/mod.rs    |   1 +
 src-tauri/src/utils/server.rs |  38 ++++++
 5 files changed, 286 insertions(+), 1 deletion(-)
 create mode 100644 src-tauri/src/utils/server.rs

diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock
index 612eaf9..786edd5 100644
--- a/src-tauri/Cargo.lock
+++ b/src-tauri/Cargo.lock
@@ -46,6 +46,7 @@ dependencies = [
  "dirs 4.0.0",
  "log",
  "log4rs",
+ "port_scanner",
  "reqwest",
  "serde",
  "serde_json",
@@ -53,6 +54,7 @@ dependencies = [
  "tauri",
  "tauri-build",
  "tokio",
+ "warp",
  "winreg 0.10.1",
 ]
 
@@ -200,6 +202,15 @@ version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
 
+[[package]]
+name = "block-buffer"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "bstr"
 version = "0.2.17"
@@ -209,6 +220,16 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "buf_redux"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f"
+dependencies = [
+ "memchr",
+ "safemem",
+]
+
 [[package]]
 name = "bumpalo"
 version = "3.8.0"
@@ -502,6 +523,15 @@ dependencies = [
  "objc",
 ]
 
+[[package]]
+name = "cpufeatures"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "crc32fast"
 version = "1.3.0"
@@ -1304,6 +1334,31 @@ version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
 
+[[package]]
+name = "headers"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4c4eb0471fcb85846d8b0690695ef354f9afb11cb03cac2e1d7c9253351afb0"
+dependencies = [
+ "base64",
+ "bitflags",
+ "bytes",
+ "headers-core",
+ "http",
+ "httpdate",
+ "mime",
+ "sha-1",
+]
+
+[[package]]
+name = "headers-core"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
+dependencies = [
+ "http",
+]
+
 [[package]]
 name = "heck"
 version = "0.3.3"
@@ -1739,6 +1794,16 @@ version = "0.3.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
 
+[[package]]
+name = "mime_guess"
+version = "2.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
 [[package]]
 name = "minisign-verify"
 version = "0.1.8"
@@ -1786,6 +1851,24 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "multipart"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182"
+dependencies = [
+ "buf_redux",
+ "httparse",
+ "log",
+ "mime",
+ "mime_guess",
+ "quick-error",
+ "rand 0.8.4",
+ "safemem",
+ "tempfile",
+ "twoway",
+]
+
 [[package]]
 name = "native-tls"
 version = "0.2.8"
@@ -2005,6 +2088,12 @@ version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
 
+[[package]]
+name = "opaque-debug"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
+
 [[package]]
 name = "open"
 version = "2.0.2"
@@ -2253,6 +2342,26 @@ dependencies = [
  "siphasher",
 ]
 
+[[package]]
+name = "pin-project"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "pin-project-lite"
 version = "0.2.7"
@@ -2308,6 +2417,12 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "port_scanner"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "325a6d2ac5dee293c3b2612d4993b98aec1dff096b0a2dae70ed7d95784a05da"
+
 [[package]]
 name = "ppv-lite86"
 version = "0.2.15"
@@ -2378,6 +2493,12 @@ dependencies = [
  "unicode-xid",
 ]
 
+[[package]]
+name = "quick-error"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
+
 [[package]]
 name = "quote"
 version = "1.0.10"
@@ -2693,6 +2814,12 @@ version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568"
 
+[[package]]
+name = "safemem"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
+
 [[package]]
 name = "same-file"
 version = "1.0.6"
@@ -2889,6 +3016,19 @@ dependencies = [
  "stable_deref_trait",
 ]
 
+[[package]]
+name = "sha-1"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
+dependencies = [
+ "block-buffer",
+ "cfg-if 1.0.0",
+ "cpufeatures",
+ "digest",
+ "opaque-debug",
+]
+
 [[package]]
 name = "sharded-slab"
 version = "0.1.4"
@@ -3472,6 +3612,30 @@ dependencies = [
  "tokio",
 ]
 
+[[package]]
+name = "tokio-stream"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-tungstenite"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "511de3f85caf1c98983545490c3d09685fa8eb634e57eec22bb4db271f46cbd8"
+dependencies = [
+ "futures-util",
+ "log",
+ "pin-project",
+ "tokio",
+ "tungstenite",
+]
+
 [[package]]
 name = "tokio-util"
 version = "0.6.9"
@@ -3508,6 +3672,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
 dependencies = [
  "cfg-if 1.0.0",
+ "log",
  "pin-project-lite",
  "tracing-attributes",
  "tracing-core",
@@ -3574,6 +3739,34 @@ version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
 
+[[package]]
+name = "tungstenite"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0b2d8558abd2e276b0a8df5c05a2ec762609344191e5fd23e292c910e9165b5"
+dependencies = [
+ "base64",
+ "byteorder",
+ "bytes",
+ "http",
+ "httparse",
+ "log",
+ "rand 0.8.4",
+ "sha-1",
+ "thiserror",
+ "url",
+ "utf-8",
+]
+
+[[package]]
+name = "twoway"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "typemap"
 version = "0.3.3"
@@ -3595,6 +3788,15 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 
+[[package]]
+name = "unicase"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
+dependencies = [
+ "version_check",
+]
+
 [[package]]
 name = "unicode-bidi"
 version = "0.3.7"
@@ -3716,6 +3918,36 @@ dependencies = [
  "try-lock",
 ]
 
+[[package]]
+name = "warp"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3cef4e1e9114a4b7f1ac799f16ce71c14de5778500c5450ec6b7b920c55b587e"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "headers",
+ "http",
+ "hyper",
+ "log",
+ "mime",
+ "mime_guess",
+ "multipart",
+ "percent-encoding",
+ "pin-project",
+ "scoped-tls",
+ "serde",
+ "serde_json",
+ "serde_urlencoded 0.7.0",
+ "tokio",
+ "tokio-stream",
+ "tokio-tungstenite",
+ "tokio-util",
+ "tower-service",
+ "tracing",
+]
+
 [[package]]
 name = "wasi"
 version = "0.9.0+wasi-snapshot-preview1"
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index e8f10ef..6b9694b 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -23,6 +23,8 @@ reqwest = { version = "0.11", features = ["json"] }
 tokio = { version = "1", features = ["full"] }
 log = "0.4.14"
 log4rs = "1.0.0"
+warp = "0.3"
+port_scanner = "0.1.5"
 
 [target.'cfg(windows)'.dependencies]
 winreg = { version = "0.10", features = ["transactions"] }
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index 96ee2f6..38f1bae 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -12,7 +12,11 @@ mod utils;
 
 use crate::{
   events::state,
-  utils::{clash::put_clash_profile, config::read_verge},
+  utils::{
+    clash::put_clash_profile,
+    config::read_verge,
+    server::{check_singleton, embed_server},
+  },
 };
 use std::sync::{Arc, Mutex};
 use tauri::{
@@ -21,6 +25,11 @@ use tauri::{
 };
 
 fn main() -> std::io::Result<()> {
+  if check_singleton().is_err() {
+    println!("app exists");
+    return Ok(());
+  }
+
   let sub_menu = SystemTraySubmenu::new(
     "出站规则",
     SystemTrayMenu::new()
@@ -76,6 +85,9 @@ fn main() -> std::io::Result<()> {
     .build(tauri::generate_context!())
     .expect("error while running tauri application");
 
+  // a simple http server
+  embed_server(&app.handle());
+
   // init app config
   utils::init::init_app(app.package_info());
   // run clash sidecar
diff --git a/src-tauri/src/utils/mod.rs b/src-tauri/src/utils/mod.rs
index 0430f37..9794a2c 100644
--- a/src-tauri/src/utils/mod.rs
+++ b/src-tauri/src/utils/mod.rs
@@ -5,4 +5,5 @@ pub mod clash;
 pub mod config;
 pub mod fetch;
 pub mod init;
+pub mod server;
 pub mod sysopt;
diff --git a/src-tauri/src/utils/server.rs b/src-tauri/src/utils/server.rs
new file mode 100644
index 0000000..b860dd4
--- /dev/null
+++ b/src-tauri/src/utils/server.rs
@@ -0,0 +1,38 @@
+extern crate warp;
+
+use port_scanner::local_port_available;
+use tauri::{AppHandle, Manager};
+use warp::Filter;
+
+const SERVER_PORT: u16 = 33333;
+
+/// check whether there is already exists
+pub fn check_singleton() -> Result<(), ()> {
+  if !local_port_available(SERVER_PORT) {
+    tauri::async_runtime::block_on(async {
+      let url = format!("http://127.0.0.1:{}/commands/visible", SERVER_PORT);
+      reqwest::get(url).await.unwrap();
+      Err(())
+    })
+  } else {
+    Ok(())
+  }
+}
+
+/// The embed server only be used to implement singleton process
+/// maybe it can be used as pac server later
+pub fn embed_server(app: &AppHandle) {
+  let window = app.get_window("main").unwrap();
+
+  let commands = warp::path!("commands" / "visible").map(move || {
+    window.show().unwrap();
+    window.set_focus().unwrap();
+    return format!("ok");
+  });
+
+  tauri::async_runtime::spawn(async move {
+    warp::serve(commands)
+      .bind(([127, 0, 0, 1], SERVER_PORT))
+      .await;
+  });
+}
-- 
GitLab