claude_rust_tools/infrastructure/
task_manager.rs1use std::sync::Arc;
2use std::sync::atomic::{AtomicU64, Ordering};
3
4use claude_rust_errors::{AppError, AppResult};
5use serde_json::Value;
6
7#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
8pub struct TaskInfo {
9 pub id: String,
10 pub subject: String,
11 pub description: String,
12 pub status: TaskStatus,
13 pub owner: Option<String>,
14 pub blocked_by: Vec<String>,
15 pub metadata: Value,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
19#[serde(rename_all = "snake_case")]
20pub enum TaskStatus {
21 Pending,
22 InProgress,
23 Completed,
24 Deleted,
25}
26
27impl std::fmt::Display for TaskStatus {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 match self {
30 Self::Pending => write!(f, "pending"),
31 Self::InProgress => write!(f, "in_progress"),
32 Self::Completed => write!(f, "completed"),
33 Self::Deleted => write!(f, "deleted"),
34 }
35 }
36}
37
38#[async_trait::async_trait]
39pub trait TaskManager: Send + Sync {
40 async fn create(&self, subject: &str, description: &str) -> AppResult<TaskInfo>;
41 async fn get(&self, task_id: &str) -> AppResult<TaskInfo>;
42 async fn list(&self) -> AppResult<Vec<TaskInfo>>;
43 async fn update(&self, task_id: &str, updates: Value) -> AppResult<TaskInfo>;
44 async fn stop(&self, task_id: &str) -> AppResult<()>;
45 async fn output(&self, task_id: &str) -> AppResult<String>;
46}
47
48pub struct InMemoryTaskManager {
49 tasks: tokio::sync::RwLock<Vec<TaskInfo>>,
50 next_id: AtomicU64,
51}
52
53impl InMemoryTaskManager {
54 pub fn new() -> Arc<Self> {
55 Arc::new(Self {
56 tasks: tokio::sync::RwLock::new(Vec::new()),
57 next_id: AtomicU64::new(1),
58 })
59 }
60}
61
62#[async_trait::async_trait]
63impl TaskManager for InMemoryTaskManager {
64 async fn create(&self, subject: &str, description: &str) -> AppResult<TaskInfo> {
65 let id = self.next_id.fetch_add(1, Ordering::SeqCst);
66 let task = TaskInfo {
67 id: id.to_string(),
68 subject: subject.to_string(),
69 description: description.to_string(),
70 status: TaskStatus::Pending,
71 owner: None,
72 blocked_by: Vec::new(),
73 metadata: Value::Null,
74 };
75 self.tasks.write().await.push(task.clone());
76 Ok(task)
77 }
78
79 async fn get(&self, task_id: &str) -> AppResult<TaskInfo> {
80 self.tasks
81 .read()
82 .await
83 .iter()
84 .find(|t| t.id == task_id)
85 .cloned()
86 .ok_or_else(|| AppError::Tool(format!("task not found: {task_id}")))
87 }
88
89 async fn list(&self) -> AppResult<Vec<TaskInfo>> {
90 let tasks = self.tasks.read().await;
91 Ok(tasks
92 .iter()
93 .filter(|t| t.status != TaskStatus::Deleted)
94 .cloned()
95 .collect())
96 }
97
98 async fn update(&self, task_id: &str, updates: Value) -> AppResult<TaskInfo> {
99 let mut tasks = self.tasks.write().await;
100 let task = tasks
101 .iter_mut()
102 .find(|t| t.id == task_id)
103 .ok_or_else(|| AppError::Tool(format!("task not found: {task_id}")))?;
104
105 if let Some(s) = updates.get("status").and_then(|v| v.as_str()) {
106 task.status = match s {
107 "pending" => TaskStatus::Pending,
108 "in_progress" => TaskStatus::InProgress,
109 "completed" => TaskStatus::Completed,
110 "deleted" => TaskStatus::Deleted,
111 other => return Err(AppError::Tool(format!("invalid status: {other}"))),
112 };
113 }
114 if let Some(s) = updates.get("subject").and_then(|v| v.as_str()) {
115 task.subject = s.to_string();
116 }
117 if let Some(s) = updates.get("description").and_then(|v| v.as_str()) {
118 task.description = s.to_string();
119 }
120 if let Some(s) = updates.get("owner").and_then(|v| v.as_str()) {
121 task.owner = Some(s.to_string());
122 }
123 if let Some(m) = updates.get("metadata") {
124 task.metadata = m.clone();
125 }
126
127 Ok(task.clone())
128 }
129
130 async fn stop(&self, task_id: &str) -> AppResult<()> {
131 let mut tasks = self.tasks.write().await;
132 let task = tasks
133 .iter_mut()
134 .find(|t| t.id == task_id)
135 .ok_or_else(|| AppError::Tool(format!("task not found: {task_id}")))?;
136 task.status = TaskStatus::Deleted;
137 Ok(())
138 }
139
140 async fn output(&self, task_id: &str) -> AppResult<String> {
141 self.tasks
143 .read()
144 .await
145 .iter()
146 .find(|t| t.id == task_id)
147 .ok_or_else(|| AppError::Tool(format!("task not found: {task_id}")))?;
148 Ok(String::new())
150 }
151}