refactor 4
This commit is contained in:
@@ -64,6 +64,18 @@ pub struct ResolvedPostInstall {
|
||||
pub steps: Vec<PostInstallStep>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct TaskEventPayload {
|
||||
pub task_id: String,
|
||||
pub software_id: String,
|
||||
pub task_type: String,
|
||||
pub status: String,
|
||||
pub stage: String,
|
||||
pub progress: f32,
|
||||
pub target_version: Option<String>,
|
||||
pub message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct EssentialsStatusItem {
|
||||
pub id: String,
|
||||
|
||||
@@ -11,17 +11,19 @@ use tokio::sync::mpsc;
|
||||
use winreg::enums::*;
|
||||
use winreg::RegKey;
|
||||
|
||||
use crate::domain::models::{InstallProgress, InstallTask};
|
||||
use crate::domain::models::{InstallProgress, InstallTask, TaskEventPayload};
|
||||
use crate::services::essentials_service;
|
||||
use crate::services::log_service::emit_log;
|
||||
use crate::winget::PostInstallStep;
|
||||
|
||||
pub struct AppState {
|
||||
pub install_tx: mpsc::Sender<InstallTask>,
|
||||
pub app_handle: AppHandle,
|
||||
}
|
||||
|
||||
pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||
let (tx, mut rx) = mpsc::channel::<InstallTask>(100);
|
||||
let runtime_handle = handle.clone();
|
||||
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let perc_re = Regex::new(r"(\d+)\s*%").unwrap();
|
||||
@@ -35,14 +37,16 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||
let enable_post_install_flag = task.enable_post_install;
|
||||
|
||||
let log_id = format!("install-{}", task_id);
|
||||
|
||||
let _ = handle.emit(
|
||||
"install-status",
|
||||
InstallProgress {
|
||||
id: task_id.clone(),
|
||||
status: "installing".to_string(),
|
||||
progress: 0.0,
|
||||
},
|
||||
emit_task_event(
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
&task_id,
|
||||
"install",
|
||||
"running",
|
||||
"installing",
|
||||
0.0,
|
||||
task_version.clone(),
|
||||
None,
|
||||
);
|
||||
|
||||
let mut args = vec!["install".to_string()];
|
||||
@@ -52,8 +56,19 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||
if use_manifest && manifest_url.is_some() {
|
||||
let url = manifest_url.unwrap();
|
||||
display_cmd = format!("Winget Install (Manifest): {} from {}", task_id, url);
|
||||
emit_task_event(
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
&task_id,
|
||||
"install",
|
||||
"running",
|
||||
"downloading_manifest",
|
||||
0.0,
|
||||
task_version.clone(),
|
||||
Some("Downloading remote manifest".to_string()),
|
||||
);
|
||||
emit_log(
|
||||
&handle,
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
&display_cmd,
|
||||
"Downloading remote manifest...",
|
||||
@@ -85,19 +100,22 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||
|
||||
if temp_manifest_path.is_none() {
|
||||
emit_log(
|
||||
&handle,
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
"Error",
|
||||
"Failed to download or save manifest.",
|
||||
"error",
|
||||
);
|
||||
let _ = handle.emit(
|
||||
"install-status",
|
||||
InstallProgress {
|
||||
id: task_id.clone(),
|
||||
status: "error".to_string(),
|
||||
progress: 0.0,
|
||||
},
|
||||
emit_task_event(
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
&task_id,
|
||||
"install",
|
||||
"failed",
|
||||
"manifest_error",
|
||||
0.0,
|
||||
task_version.clone(),
|
||||
Some("Failed to download or save manifest".to_string()),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -128,12 +146,23 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||
|
||||
let full_command = format!("winget {}", args.join(" "));
|
||||
emit_log(
|
||||
&handle,
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
&display_cmd,
|
||||
&format!("Executing: {}\n---", full_command),
|
||||
"info",
|
||||
);
|
||||
emit_task_event(
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
&task_id,
|
||||
"install",
|
||||
"running",
|
||||
"invoking_winget",
|
||||
0.0,
|
||||
task_version.clone(),
|
||||
None,
|
||||
);
|
||||
|
||||
let child = Command::new("winget")
|
||||
.args(&args)
|
||||
@@ -147,7 +176,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||
let stdout_handle = child_proc.stdout.take().map(|stdout| {
|
||||
spawn_install_stream_reader(
|
||||
stdout,
|
||||
handle.clone(),
|
||||
runtime_handle.clone(),
|
||||
log_id.clone(),
|
||||
task_id.clone(),
|
||||
"stdout",
|
||||
@@ -158,7 +187,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||
let stderr_handle = child_proc.stderr.take().map(|stderr| {
|
||||
spawn_install_stream_reader(
|
||||
stderr,
|
||||
handle.clone(),
|
||||
runtime_handle.clone(),
|
||||
log_id.clone(),
|
||||
task_id.clone(),
|
||||
"stderr",
|
||||
@@ -177,7 +206,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||
let status_result = if exit_status { "success" } else { "error" };
|
||||
|
||||
if status_result == "success" && enable_post_install_flag {
|
||||
let software_info = essentials_service::get_essentials(&handle)
|
||||
let software_info = essentials_service::get_essentials(&runtime_handle)
|
||||
.and_then(|repo| repo.essentials.into_iter().find(|s| s.id == task_id));
|
||||
|
||||
if let Some(sw) = software_info {
|
||||
@@ -188,7 +217,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||
}
|
||||
} else if let Some(url) = sw.post_install_url {
|
||||
emit_log(
|
||||
&handle,
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
"Post-Install",
|
||||
"Local config not found, fetching remote config...",
|
||||
@@ -206,7 +235,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||
match serde_json::from_str::<Vec<PostInstallStep>>(&text) {
|
||||
Ok(steps) => {
|
||||
emit_log(
|
||||
&handle,
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
"Post-Install",
|
||||
&format!(
|
||||
@@ -219,7 +248,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||
}
|
||||
Err(e) => {
|
||||
emit_log(
|
||||
&handle,
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
"Post-Install Error",
|
||||
&format!("JSON Parse Error: {}. Raw Content: {}", e, text),
|
||||
@@ -230,7 +259,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||
}
|
||||
} else {
|
||||
emit_log(
|
||||
&handle,
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
"Post-Install Error",
|
||||
&format!("Remote config HTTP Error: {}", resp.status()),
|
||||
@@ -241,26 +270,29 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||
}
|
||||
|
||||
if let Some(steps) = final_steps {
|
||||
let _ = handle.emit(
|
||||
"install-status",
|
||||
InstallProgress {
|
||||
id: task_id.clone(),
|
||||
status: "configuring".to_string(),
|
||||
progress: 1.0,
|
||||
},
|
||||
emit_task_event(
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
&task_id,
|
||||
"install",
|
||||
"running",
|
||||
"configuring",
|
||||
1.0,
|
||||
task_version.clone(),
|
||||
Some("Starting post-installation configuration".to_string()),
|
||||
);
|
||||
emit_log(
|
||||
&handle,
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
"Post-Install",
|
||||
"Starting post-installation configuration...",
|
||||
"info",
|
||||
);
|
||||
if let Err(e) = execute_post_install(&handle, &log_id, steps).await {
|
||||
emit_log(&handle, &log_id, "Post-Install Error", &e, "error");
|
||||
if let Err(e) = execute_post_install(&runtime_handle, &log_id, steps).await {
|
||||
emit_log(&runtime_handle, &log_id, "Post-Install Error", &e, "error");
|
||||
} else {
|
||||
emit_log(
|
||||
&handle,
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
"Post-Install",
|
||||
"Post-installation configuration completed.",
|
||||
@@ -273,21 +305,35 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||
status_result
|
||||
}
|
||||
Err(e) => {
|
||||
emit_log(&handle, &log_id, "Fatal Error", &e.to_string(), "error");
|
||||
emit_log(&runtime_handle, &log_id, "Fatal Error", &e.to_string(), "error");
|
||||
emit_task_event(
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
&task_id,
|
||||
"install",
|
||||
"failed",
|
||||
"spawn_error",
|
||||
0.0,
|
||||
task_version.clone(),
|
||||
Some(e.to_string()),
|
||||
);
|
||||
"error"
|
||||
}
|
||||
};
|
||||
|
||||
let _ = handle.emit(
|
||||
"install-status",
|
||||
InstallProgress {
|
||||
id: task_id.clone(),
|
||||
status: status_result.to_string(),
|
||||
progress: 1.0,
|
||||
},
|
||||
emit_task_event(
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
&task_id,
|
||||
"install",
|
||||
if status_result == "success" { "completed" } else { "failed" },
|
||||
status_result,
|
||||
1.0,
|
||||
task_version.clone(),
|
||||
Some(format!("Execution finished: {}", status_result)),
|
||||
);
|
||||
emit_log(
|
||||
&handle,
|
||||
&runtime_handle,
|
||||
&log_id,
|
||||
"Result",
|
||||
&format!("Execution finished: {}", status_result),
|
||||
@@ -304,7 +350,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||
}
|
||||
});
|
||||
|
||||
AppState { install_tx: tx }
|
||||
AppState { install_tx: tx, app_handle: handle }
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -312,6 +358,18 @@ pub async fn install_software(
|
||||
task: InstallTask,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<(), String> {
|
||||
let log_id = format!("install-{}", task.id);
|
||||
emit_task_event(
|
||||
&state.app_handle,
|
||||
&log_id,
|
||||
&task.id,
|
||||
"install",
|
||||
"queued",
|
||||
"queued",
|
||||
0.0,
|
||||
task.version.clone(),
|
||||
None,
|
||||
);
|
||||
state.install_tx.send(task).await.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
@@ -346,6 +404,19 @@ fn spawn_install_stream_reader<R: Read + Send + 'static>(
|
||||
progress: p_val / 100.0,
|
||||
},
|
||||
);
|
||||
let _ = handle.emit(
|
||||
"task-event",
|
||||
TaskEventPayload {
|
||||
task_id: log_id.clone(),
|
||||
software_id: task_id.clone(),
|
||||
task_type: "install".to_string(),
|
||||
status: "running".to_string(),
|
||||
stage: "installing".to_string(),
|
||||
progress: p_val / 100.0,
|
||||
target_version: None,
|
||||
message: None,
|
||||
},
|
||||
);
|
||||
is_progress = true;
|
||||
}
|
||||
} else if let Some(caps) = size_re.captures(clean_line) {
|
||||
@@ -360,6 +431,19 @@ fn spawn_install_stream_reader<R: Read + Send + 'static>(
|
||||
progress: (current / total).min(1.0),
|
||||
},
|
||||
);
|
||||
let _ = handle.emit(
|
||||
"task-event",
|
||||
TaskEventPayload {
|
||||
task_id: log_id.clone(),
|
||||
software_id: task_id.clone(),
|
||||
task_type: "install".to_string(),
|
||||
status: "running".to_string(),
|
||||
stage: "installing".to_string(),
|
||||
progress: (current / total).min(1.0),
|
||||
target_version: None,
|
||||
message: None,
|
||||
},
|
||||
);
|
||||
is_progress = true;
|
||||
}
|
||||
}
|
||||
@@ -375,6 +459,48 @@ fn spawn_install_stream_reader<R: Read + Send + 'static>(
|
||||
})
|
||||
}
|
||||
|
||||
fn emit_task_event(
|
||||
handle: &AppHandle,
|
||||
task_id: &str,
|
||||
software_id: &str,
|
||||
task_type: &str,
|
||||
status: &str,
|
||||
stage: &str,
|
||||
progress: f32,
|
||||
target_version: Option<String>,
|
||||
message: Option<String>,
|
||||
) {
|
||||
let _ = handle.emit(
|
||||
"task-event",
|
||||
TaskEventPayload {
|
||||
task_id: task_id.to_string(),
|
||||
software_id: software_id.to_string(),
|
||||
task_type: task_type.to_string(),
|
||||
status: status.to_string(),
|
||||
stage: stage.to_string(),
|
||||
progress,
|
||||
target_version: target_version.clone(),
|
||||
message,
|
||||
},
|
||||
);
|
||||
|
||||
let legacy_status = match status {
|
||||
"queued" => "pending".to_string(),
|
||||
"completed" => "success".to_string(),
|
||||
"failed" => "error".to_string(),
|
||||
_ => stage.to_string(),
|
||||
};
|
||||
|
||||
let _ = handle.emit(
|
||||
"install-status",
|
||||
InstallProgress {
|
||||
id: software_id.to_string(),
|
||||
status: legacy_status,
|
||||
progress,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn expand_win_path(path: &str) -> PathBuf {
|
||||
let mut expanded = path.to_string();
|
||||
let env_vars = [
|
||||
|
||||
Reference in New Issue
Block a user