P1: sidecar lifecycle and HTTP bridge
Backend - sidecar.rs supervises the bundled `mycelium` binary launched via pkexec; locates it in resource_dir or CARGO_MANIFEST_DIR/binaries matching $TAURI_ENV_TARGET_TRIPLE - ephemeral port via portpicker, key + config persisted in app_data_dir, kill_on_drop with explicit start_kill on stop - health-check loop calls /api/v1/admin until 2xx (timeout 20s); emits sidecar://ready and sidecar://exited - 500-line ring buffer of stdout/stderr surfaced via sidecar_logs command for the upcoming Settings page - elevation::is_auth_failure(126|127) maps pkexec cancel to a dedicated AppError variant - AppError uses thiserror, Serialize impl renders messages as plain strings for the JS side Frontend - typed `api` wrapper around invoke() in src/lib/api.ts - node store (Pinia) bootstraps on mount, listens on sidecar://ready and sidecar://exited - StartupOverlay covers the whole window for idle/starting/error phases; sidebar status dot + start/stop button - Status view renders subnet, pubkey, api endpoint and key path with one-click clipboard copy
This commit is contained in:
53
src-tauri/src/commands.rs
Normal file
53
src-tauri/src/commands.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use crate::api::admin::NodeInfo;
|
||||
use crate::error::{AppError, AppResult};
|
||||
use crate::sidecar::SidecarConfig;
|
||||
use crate::state::AppState;
|
||||
use serde::Serialize;
|
||||
use tauri::{AppHandle, State};
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct DaemonStatus {
|
||||
pub running: bool,
|
||||
pub api_url: Option<String>,
|
||||
pub key_path: Option<String>,
|
||||
pub config_path: Option<String>,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn daemon_status(state: State<'_, AppState>) -> DaemonStatus {
|
||||
let sc = &state.sidecar;
|
||||
DaemonStatus {
|
||||
running: sc.is_running(),
|
||||
api_url: sc.client().map(|c| c.base_url().to_string()),
|
||||
key_path: sc.key_path().map(|p| p.display().to_string()),
|
||||
config_path: sc.config_path().map(|p| p.display().to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn start_daemon(
|
||||
app: AppHandle,
|
||||
state: State<'_, AppState>,
|
||||
config: Option<SidecarConfig>,
|
||||
) -> AppResult<DaemonStatus> {
|
||||
let cfg = config.unwrap_or_default();
|
||||
state.sidecar.start(&app, &cfg).await?;
|
||||
Ok(daemon_status(state))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn stop_daemon(state: State<'_, AppState>) -> AppResult<DaemonStatus> {
|
||||
state.sidecar.stop().await;
|
||||
Ok(daemon_status(state))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn node_info(state: State<'_, AppState>) -> AppResult<NodeInfo> {
|
||||
let client = state.sidecar.client().ok_or(AppError::DaemonNotRunning)?;
|
||||
client.node_info().await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn sidecar_logs(state: State<'_, AppState>) -> Vec<String> {
|
||||
state.sidecar.logs_snapshot()
|
||||
}
|
||||
Reference in New Issue
Block a user