tsk/commands/
run.rs

1use super::Command;
2use crate::context::AppContext;
3use crate::server::TskServer;
4use crate::task::{Task, TaskStatus};
5use crate::task_manager::TaskManager;
6use crate::task_storage::get_task_storage;
7use async_trait::async_trait;
8use std::error::Error;
9use std::sync::Arc;
10
11pub struct RunCommand {
12    pub server: bool,
13}
14
15#[async_trait]
16impl Command for RunCommand {
17    async fn execute(&self, ctx: &AppContext) -> Result<(), Box<dyn Error>> {
18        if self.server {
19            // Run in server mode
20            println!("Starting TSK server...");
21            let server = TskServer::new(Arc::new(ctx.clone()));
22
23            // Setup signal handlers for graceful shutdown
24            let shutdown_signal = Arc::new(tokio::sync::Notify::new());
25            let shutdown_signal_clone = shutdown_signal.clone();
26
27            tokio::spawn(async move {
28                tokio::signal::ctrl_c()
29                    .await
30                    .expect("Failed to listen for Ctrl+C");
31                println!("\nReceived shutdown signal...");
32                shutdown_signal_clone.notify_one();
33            });
34
35            // Run server until shutdown
36            tokio::select! {
37                result = server.run() => {
38                    match result {
39                        Ok(_) => {},
40                        Err(e) => {
41                            let error_msg = e.to_string();
42                            eprintln!("Server error: {error_msg}");
43                            return Err(Box::new(std::io::Error::other(error_msg)));
44                        }
45                    }
46                }
47                _ = shutdown_signal.notified() => {
48                    server.shutdown().await;
49                }
50            }
51
52            println!("Server stopped");
53            return Ok(());
54        }
55
56        // Run in client mode (execute current tasks and exit)
57        let storage = get_task_storage(ctx.xdg_directories(), ctx.file_system());
58        let tasks = storage
59            .list_tasks()
60            .await
61            .map_err(|e| e as Box<dyn Error>)?;
62
63        let queued_tasks: Vec<Task> = tasks
64            .into_iter()
65            .filter(|t| t.status == TaskStatus::Queued)
66            .collect();
67
68        if queued_tasks.is_empty() {
69            println!("No queued tasks to run");
70            return Ok(());
71        }
72
73        println!("Found {} queued task(s) to run", queued_tasks.len());
74
75        let task_manager = TaskManager::with_storage(ctx)?;
76        let total_tasks = queued_tasks.len();
77        let mut succeeded = 0;
78        let mut failed = 0;
79
80        for task in queued_tasks {
81            println!("\n{}", "=".repeat(60));
82            println!("Running task: {} ({})", task.name, task.id);
83            println!("Type: {}", task.task_type);
84            println!("{}", "=".repeat(60));
85
86            // Update terminal title for current task
87            ctx.terminal_operations()
88                .set_title(&format!("TSK: {}", task.name));
89
90            // Execute the task with automatic status updates
91            match task_manager.execute_queued_task(&task).await {
92                Ok(_result) => {
93                    println!("\nTask completed successfully");
94                    succeeded += 1;
95                }
96                Err(e) => {
97                    eprintln!("Task failed: {}", e.message);
98                    failed += 1;
99                }
100            }
101        }
102
103        // Restore terminal title after all tasks complete
104        ctx.terminal_operations().restore_title();
105
106        println!("\n{}", "=".repeat(60));
107        println!("All tasks processed!");
108        println!("Use 'tsk list' to see the final status of all tasks");
109
110        // Send summary notification
111        ctx.notification_client()
112            .notify_all_tasks_complete(total_tasks, succeeded, failed);
113
114        Ok(())
115    }
116}