231 lines
8.2 KiB
Rust
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");
|
|
}
|