Remake desktop
Optimize change proxy Optimize network check Fix fallback issues Optimize lots of details
This commit is contained in:
1313
services/helper/Cargo.lock
generated
Normal file
1313
services/helper/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
23
services/helper/Cargo.toml
Normal file
23
services/helper/Cargo.toml
Normal file
@@ -0,0 +1,23 @@
|
||||
[package]
|
||||
name = "helper"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "helper"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
windows-service = { version = "0.7.0", optional = true }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
anyhow = "1.0.93"
|
||||
warp = "0.3.7"
|
||||
serde = { version = "1.0.215", features = ["derive"] }
|
||||
once_cell = "1.20.2"
|
||||
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
codegen-units = 1
|
||||
lto = true
|
||||
opt-level = "s"
|
||||
20
services/helper/src/main.rs
Normal file
20
services/helper/src/main.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
#[cfg(not(all(feature = "windows-service", target_os = "windows")))]
|
||||
use tokio::runtime::Runtime;
|
||||
#[cfg(not(all(feature = "windows-service", target_os = "windows")))]
|
||||
use crate::service::hub::run_service;
|
||||
|
||||
mod service;
|
||||
|
||||
#[cfg(all(feature = "windows-service", target_os = "windows"))]
|
||||
pub fn main() -> windows_service::Result<()> {
|
||||
service::windows::main()
|
||||
}
|
||||
|
||||
#[cfg(not(all(feature = "windows-service", target_os = "windows")))]
|
||||
fn main() {
|
||||
if let Ok(rt) = Runtime::new() {
|
||||
rt.block_on(async {
|
||||
let _ = run_service().await;
|
||||
});
|
||||
}
|
||||
}
|
||||
110
services/helper/src/service/hub.rs
Normal file
110
services/helper/src/service/hub.rs
Normal file
@@ -0,0 +1,110 @@
|
||||
use std::collections::VecDeque;
|
||||
use std::{io, thread};
|
||||
use std::io::BufRead;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use warp::{Filter, Reply};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
const LISTEN_PORT: u16 = 47890;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct StartParams {
|
||||
pub path: String,
|
||||
pub arg: String,
|
||||
}
|
||||
|
||||
static LOGS: Lazy<Arc<Mutex<VecDeque<String>>>> = Lazy::new(|| Arc::new(Mutex::new(VecDeque::with_capacity(100))));
|
||||
static PROCESS: Lazy<Arc<Mutex<Option<std::process::Child>>>> = Lazy::new(|| Arc::new(Mutex::new(None)));
|
||||
|
||||
fn start(start_params: StartParams) -> impl Reply {
|
||||
stop();
|
||||
let mut process = PROCESS.lock().unwrap();
|
||||
match Command::new(&start_params.path)
|
||||
.stderr(Stdio::piped())
|
||||
.arg(&start_params.arg)
|
||||
.spawn()
|
||||
{
|
||||
Ok(child) => {
|
||||
*process = Some(child);
|
||||
if let Some(ref mut child) = *process {
|
||||
let stderr = child.stderr.take().unwrap();
|
||||
let reader = io::BufReader::new(stderr);
|
||||
thread::spawn(move || {
|
||||
for line in reader.lines() {
|
||||
match line {
|
||||
Ok(output) => {
|
||||
log_message(output);
|
||||
}
|
||||
Err(_) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
"".to_string()
|
||||
}
|
||||
Err(e) => {
|
||||
log_message(e.to_string());
|
||||
e.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn stop() -> impl Reply {
|
||||
let mut process = PROCESS.lock().unwrap();
|
||||
if let Some(mut child) = process.take() {
|
||||
let _ = child.kill();
|
||||
let _ = child.wait();
|
||||
}
|
||||
*process = None;
|
||||
"".to_string()
|
||||
}
|
||||
|
||||
fn log_message(message: String) {
|
||||
let mut log_buffer = LOGS.lock().unwrap();
|
||||
if log_buffer.len() == 100 {
|
||||
log_buffer.pop_front();
|
||||
}
|
||||
log_buffer.push_back(format!("{}\n", message));
|
||||
}
|
||||
|
||||
fn get_logs() -> impl Reply {
|
||||
let log_buffer = LOGS.lock().unwrap();
|
||||
let value = log_buffer.iter().cloned().collect::<Vec<String>>().join("\n");
|
||||
warp::reply::with_header(value, "Content-Type", "text/plain")
|
||||
}
|
||||
|
||||
pub async fn run_service() -> anyhow::Result<()> {
|
||||
let api_ping = warp::get()
|
||||
.and(warp::path("ping"))
|
||||
.map(|| "2024125");
|
||||
|
||||
let api_start = warp::post()
|
||||
.and(warp::path("start"))
|
||||
.and(warp::body::json())
|
||||
.map(|start_params: StartParams| {
|
||||
start(start_params)
|
||||
});
|
||||
|
||||
let api_stop = warp::post()
|
||||
.and(warp::path("stop"))
|
||||
.map(|| stop());
|
||||
|
||||
let api_logs = warp::get()
|
||||
.and(warp::path("logs"))
|
||||
.map(|| get_logs());
|
||||
|
||||
warp::serve(
|
||||
api_ping
|
||||
.or(api_start)
|
||||
.or(api_stop)
|
||||
.or(api_logs)
|
||||
)
|
||||
.run(([127, 0, 0, 1], LISTEN_PORT))
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
8
services/helper/src/service/mod.rs
Normal file
8
services/helper/src/service/mod.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
pub mod hub;
|
||||
#[cfg(all(feature = "windows-service", target_os = "windows"))]
|
||||
pub mod windows;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
67
services/helper/src/service/windows.rs
Normal file
67
services/helper/src/service/windows.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
use crate::service::hub::run_service;
|
||||
|
||||
use std::ffi::OsString;
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
use windows_service::{
|
||||
define_windows_service,
|
||||
service::{
|
||||
ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus,
|
||||
ServiceType,
|
||||
},
|
||||
service_control_handler::{self, ServiceControlHandlerResult},
|
||||
service_dispatcher, Result,
|
||||
};
|
||||
|
||||
const SERVICE_NAME: &str = "FlClashHelperService";
|
||||
|
||||
const SERVICE_TYPE: ServiceType = ServiceType::OWN_PROCESS;
|
||||
|
||||
pub fn main() -> Result<()> {
|
||||
start_service()
|
||||
}
|
||||
|
||||
pub fn start_service() -> Result<()> {
|
||||
service_dispatcher::start(SERVICE_NAME, serveice)
|
||||
}
|
||||
|
||||
define_windows_service!(serveice, service_main);
|
||||
|
||||
pub fn service_main(_arguments: Vec<OsString>) {
|
||||
if let Ok(rt) = Runtime::new() {
|
||||
rt.block_on(async {
|
||||
let _ = run_windows_service().await;
|
||||
});
|
||||
}
|
||||
}
|
||||
async fn run_windows_service() -> anyhow::Result<()> {
|
||||
let status_handle = service_control_handler::register(
|
||||
SERVICE_NAME,
|
||||
move |event| -> ServiceControlHandlerResult {
|
||||
match event {
|
||||
ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
|
||||
ServiceControl::Stop => std::process::exit(0),
|
||||
_ => ServiceControlHandlerResult::NotImplemented,
|
||||
}
|
||||
},
|
||||
)?;
|
||||
|
||||
status_handle.set_service_status(ServiceStatus {
|
||||
service_type: SERVICE_TYPE,
|
||||
current_state: ServiceState::Running,
|
||||
controls_accepted: ServiceControlAccept::STOP,
|
||||
exit_code: ServiceExitCode::Win32(0),
|
||||
checkpoint: 0,
|
||||
wait_hint: Duration::default(),
|
||||
process_id: None,
|
||||
})?;
|
||||
|
||||
run_service().await
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user