Files
JE-Skin/src-tauri/src/lib.rs
2026-05-11 22:30:45 +08:00

231 lines
8.2 KiB
Rust

mod commands;
mod lan_game;
pub mod log;
pub mod serial_core;
#[cfg(feature = "devkit")]
pub mod devkit;
use commands::serial::SerialConnectionState;
#[cfg(feature = "devkit")]
use tauri::Manager;
#[cfg(target_os = "android")]
fn usb_serial_plugin<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> {
tauri::plugin::Builder::new("usb-serial")
.setup(|_app, api| {
api.register_android_plugin("com.lenn.tauri_serial", "UsbSerialPlugin")?;
Ok(())
})
.build()
}
#[cfg(feature = "devkit")]
fn start_server_exe(exe_path: &std::path::Path) {
let mut command = std::process::Command::new(exe_path);
command.arg("--port").arg("50051");
#[cfg(target_os = "windows")]
{
use std::os::windows::process::CommandExt;
command.creation_flags(0x08000000);
}
match command.spawn() {
Ok(_) => ::log::info!("DevKit Python server launched: {}", exe_path.display()),
Err(error) => ::log::warn!("Failed to start DevKit Python server: {error}"),
}
}
#[cfg(feature = "devkit")]
fn is_local_port_open(port: u16) -> bool {
use std::net::{SocketAddr, TcpStream};
use std::time::Duration;
let addr = SocketAddr::from(([127, 0, 0, 1], port));
TcpStream::connect_timeout(&addr, Duration::from_millis(250)).is_ok()
}
#[cfg(feature = "devkit")]
fn find_server_exe(
resource_dir: &std::path::Path,
exe_name: &str,
) -> Option<std::path::PathBuf> {
let mut candidates = Vec::new();
candidates.push(resource_dir.join(exe_name));
if let Ok(current_exe) = std::env::current_exe() {
if let Some(parent) = current_exe.parent() {
candidates.push(parent.join(exe_name));
}
}
if let Ok(current_dir) = std::env::current_dir() {
candidates.push(current_dir.join("src-tauri").join("resources").join(exe_name));
candidates.push(current_dir.join("devkit").join("dist").join(exe_name));
candidates.push(current_dir.join("resources").join(exe_name));
}
candidates.into_iter().find(|path| path.exists())
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
let builder = tauri::Builder::default()
.plugin(tauri_plugin_process::init())
.manage(SerialConnectionState::default())
.plugin(tauri_plugin_opener::init());
#[cfg(target_os = "android")]
let builder = builder.plugin(usb_serial_plugin());
#[cfg(not(any(target_os = "android", target_os = "ios")))]
let builder = builder.plugin(tauri_plugin_updater::Builder::new().build());
#[cfg(any(target_os = "android", target_os = "ios"))]
let builder = builder;
#[cfg(feature = "devkit")]
let builder = {
let devkit_state = devkit::DevKitState::default();
let devkit_state_clone = devkit_state.clone();
builder.manage(devkit_state).setup(move |app| {
tauri::async_runtime::spawn(async {
if let Err(error) = lan_game::serve().await {
::log::error!("LAN game server failed: {error:?}");
}
});
let resource_dir = app
.path()
.resource_dir()
.unwrap_or_else(|_| std::path::PathBuf::from("./resources"));
let app_handle = app.handle().clone();
tauri::async_runtime::spawn(async move {
let devkit_port = 50051u16;
#[cfg(target_os = "windows")]
let exe_name = "je-skin-devkit-server.exe";
#[cfg(not(target_os = "windows"))]
let exe_name = "je-skin-devkit-server";
if is_local_port_open(devkit_port) {
::log::info!(
"DevKit port {} already in use, skipping Python server auto-start",
devkit_port
);
} else {
let server_exe = find_server_exe(&resource_dir, exe_name);
if let Some(exe_path) = server_exe {
start_server_exe(&exe_path);
tokio::time::sleep(std::time::Duration::from_millis(1200)).await;
} else {
::log::info!("DevKit Python server not found, skipping auto-start");
}
}
if let Err(error) = devkit_state_clone.start(app_handle, devkit_port).await {
::log::warn!("DevKit auto-start failed: {error}");
} else {
::log::info!("DevKit gRPC client initialized for 127.0.0.1:{devkit_port}");
}
});
Ok(())
})
};
#[cfg(not(feature = "devkit"))]
let builder = builder.setup(|_app| {
tauri::async_runtime::spawn(async {
if let Err(error) = lan_game::serve().await {
::log::error!("LAN game server failed: {error:?}");
}
});
Ok(())
});
#[cfg(all(feature = "devkit", not(target_os = "android")))]
let builder = builder.invoke_handler(tauri::generate_handler![
commands::file_explorer::file_explorer_list,
commands::serial::serial_enum,
commands::serial::serial_connect,
commands::serial::serial_disconnect,
commands::serial::serial_export_csv,
commands::serial::serial_has_record_data,
commands::serial::serial_export_csv_to_path,
commands::serial::serial_import_csv,
commands::serial::serial_import_csv_from_path,
commands::window::win_minimize,
commands::window::win_toggle_maximize,
commands::window::win_close,
commands::devkit::devkit_status,
commands::devkit::devkit_start,
commands::devkit::devkit_stop,
commands::devkit::devkit_get_config,
commands::devkit::devkit_set_config,
commands::devkit::devkit_process_export
]);
#[cfg(all(not(feature = "devkit"), not(target_os = "android")))]
let builder = builder.invoke_handler(tauri::generate_handler![
commands::file_explorer::file_explorer_list,
commands::serial::serial_enum,
commands::serial::serial_connect,
commands::serial::serial_disconnect,
commands::serial::serial_export_csv,
commands::serial::serial_has_record_data,
commands::serial::serial_export_csv_to_path,
commands::serial::serial_import_csv,
commands::serial::serial_import_csv_from_path,
commands::window::win_minimize,
commands::window::win_toggle_maximize,
commands::window::win_close
]);
#[cfg(all(feature = "devkit", target_os = "android"))]
let builder = builder.invoke_handler(tauri::generate_handler![
commands::file_explorer::file_explorer_list,
commands::serial::serial_enum,
commands::serial::serial_connect_fd,
commands::serial::serial_disconnect,
commands::serial::serial_export_csv,
commands::serial::serial_has_record_data,
commands::serial::serial_export_csv_to_path,
commands::serial::serial_import_csv,
commands::serial::serial_import_csv_from_path,
commands::window::win_minimize,
commands::window::win_toggle_maximize,
commands::window::win_close,
commands::devkit::devkit_status,
commands::devkit::devkit_start,
commands::devkit::devkit_stop,
commands::devkit::devkit_get_config,
commands::devkit::devkit_set_config,
commands::devkit::devkit_process_export
]);
#[cfg(all(not(feature = "devkit"), target_os = "android"))]
let builder = builder.invoke_handler(tauri::generate_handler![
commands::file_explorer::file_explorer_list,
commands::serial::serial_enum,
commands::serial::serial_connect_fd,
commands::serial::serial_disconnect,
commands::serial::serial_export_csv,
commands::serial::serial_has_record_data,
commands::serial::serial_export_csv_to_path,
commands::serial::serial_import_csv,
commands::serial::serial_import_csv_from_path,
commands::window::win_minimize,
commands::window::win_toggle_maximize,
commands::window::win_close
]);
builder
.run(tauri::generate_context!())
.expect("error while running tauri application");
}