missiond_core/core/
inbox.rs1use crate::db::MissionDB;
6use crate::types::InboxMessage;
7use std::sync::Arc;
8use tracing::{debug, info};
9use uuid::Uuid;
10
11pub struct Inbox {
15 db: Arc<MissionDB>,
16}
17
18impl Inbox {
19 pub fn new(db: Arc<MissionDB>) -> Self {
21 Self { db }
22 }
23
24 pub fn get_messages(&self, unread_only: bool, limit: usize) -> Vec<InboxMessage> {
30 self.db
31 .get_inbox_messages(unread_only, limit as i64)
32 .unwrap_or_default()
33 }
34
35 pub fn mark_read(&self, message_id: &str) {
37 let _ = self.db.mark_inbox_read(message_id);
38 debug!(message_id = %message_id, "Message marked as read");
39 }
40
41 pub fn mark_all_read(&self) {
43 let messages = self
44 .db
45 .get_inbox_messages(true, 10000)
46 .unwrap_or_default();
47 let count = messages.len();
48
49 for msg in messages {
50 let _ = self.db.mark_inbox_read(&msg.id);
51 }
52
53 info!(count = count, "All messages marked as read");
54 }
55
56 pub fn get_unread_count(&self) -> usize {
58 self.db
59 .get_inbox_messages(true, 10000)
60 .map(|v| v.len())
61 .unwrap_or(0)
62 }
63
64 pub fn add_message(&self, task_id: &str, from_role: &str, content: &str) {
66 let msg = InboxMessage {
67 id: Uuid::new_v4().to_string(),
68 task_id: task_id.to_string(),
69 from_role: from_role.to_string(),
70 content: content.to_string(),
71 read: false,
72 created_at: chrono::Utc::now().timestamp_millis(),
73 };
74
75 let _ = self.db.insert_inbox_message(&msg);
76 debug!(message_id = %msg.id, task_id = %task_id, "Message added to inbox");
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use tempfile::tempdir;
84
85 fn create_test_db() -> Arc<MissionDB> {
86 let dir = tempdir().unwrap();
87 let db_path = dir.path().join("test.db");
88 Arc::new(MissionDB::open(db_path).unwrap())
89 }
90
91 #[test]
92 fn test_add_and_get_messages() {
93 let db = create_test_db();
94 let inbox = Inbox::new(db);
95
96 inbox.add_message("task-1", "worker", "Result 1");
98 inbox.add_message("task-2", "specialist", "Result 2");
99
100 let messages = inbox.get_messages(false, 10);
102 assert_eq!(messages.len(), 2);
103
104 let unread = inbox.get_messages(true, 10);
106 assert_eq!(unread.len(), 2);
107
108 assert!(messages.iter().any(|m| m.content == "Result 1"));
110 assert!(messages.iter().any(|m| m.content == "Result 2"));
111 }
112
113 #[test]
114 fn test_mark_read() {
115 let db = create_test_db();
116 let inbox = Inbox::new(db);
117
118 inbox.add_message("task-1", "worker", "Result");
120
121 let messages = inbox.get_messages(true, 10);
123 assert_eq!(messages.len(), 1);
124 let msg_id = &messages[0].id;
125
126 inbox.mark_read(msg_id);
128
129 let unread = inbox.get_messages(true, 10);
131 assert_eq!(unread.len(), 0);
132
133 let all = inbox.get_messages(false, 10);
135 assert_eq!(all.len(), 1);
136 }
137
138 #[test]
139 fn test_mark_all_read() {
140 let db = create_test_db();
141 let inbox = Inbox::new(db);
142
143 inbox.add_message("task-1", "worker", "Result 1");
145 inbox.add_message("task-2", "worker", "Result 2");
146 inbox.add_message("task-3", "worker", "Result 3");
147
148 assert_eq!(inbox.get_unread_count(), 3);
150
151 inbox.mark_all_read();
153
154 assert_eq!(inbox.get_unread_count(), 0);
156 }
157
158 #[test]
159 fn test_get_unread_count() {
160 let db = create_test_db();
161 let inbox = Inbox::new(db);
162
163 assert_eq!(inbox.get_unread_count(), 0);
164
165 inbox.add_message("task-1", "worker", "Result 1");
166 assert_eq!(inbox.get_unread_count(), 1);
167
168 inbox.add_message("task-2", "worker", "Result 2");
169 assert_eq!(inbox.get_unread_count(), 2);
170
171 let messages = inbox.get_messages(true, 1);
173 inbox.mark_read(&messages[0].id);
174
175 assert_eq!(inbox.get_unread_count(), 1);
176 }
177
178 #[test]
179 fn test_limit() {
180 let db = create_test_db();
181 let inbox = Inbox::new(db);
182
183 for i in 0..5 {
185 inbox.add_message(&format!("task-{}", i), "worker", &format!("Result {}", i));
186 }
187
188 let messages = inbox.get_messages(true, 3);
190 assert_eq!(messages.len(), 3);
191 }
192}