1use crate::identity::enhanced::{EnhancedIdentity, OrganizationId};
11use crate::storage::{StorageManager, keys, ttl};
12use crate::quantum_crypto::types::GroupId;
14use serde::{Deserialize, Serialize};
15use std::collections::HashMap;
16use std::time::SystemTime;
17use thiserror::Error;
18use uuid::Uuid;
19
20#[derive(Debug, Error)]
22pub enum ChatError {
23 #[error("Storage error: {0}")]
24 StorageError(#[from] crate::storage::StorageError),
25
26 #[error("Channel not found: {0}")]
27 ChannelNotFound(String),
28
29 #[error("Permission denied: {0}")]
30 PermissionDenied(String),
31
32 #[error("Invalid operation: {0}")]
33 InvalidOperation(String),
34}
35
36type Result<T> = std::result::Result<T, ChatError>;
37
38#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
40pub struct ChannelId(pub String);
41
42impl ChannelId {
43 pub fn new() -> Self {
45 Self(Uuid::new_v4().to_string())
46 }
47}
48
49#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
51pub struct MessageId(pub String);
52
53impl MessageId {
54 pub fn new() -> Self {
56 Self(Uuid::new_v4().to_string())
57 }
58}
59
60#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
62pub struct ThreadId(pub String);
63
64pub type UserId = String;
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
69pub enum ChannelType {
70 Public,
72
73 Private {
75 access_group: GroupId,
76 visibility: ChannelVisibility,
77 },
78
79 Direct {
81 participants: Vec<UserId>,
82 },
83
84 GroupDirect {
86 participants: Vec<UserId>,
87 name: Option<String>,
88 },
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
93pub enum ChannelVisibility {
94 Listed,
96
97 Hidden,
99
100 Secret,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct Channel {
107 pub id: ChannelId,
108 pub name: String,
109 pub description: String,
110 pub channel_type: ChannelType,
111 pub organization_id: Option<OrganizationId>,
112 pub created_by: UserId,
113 pub created_at: SystemTime,
114 pub members: Vec<ChannelMember>,
115 pub settings: ChannelSettings,
116 pub metadata: HashMap<String, String>,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct ChannelMember {
122 pub user_id: UserId,
123 pub role: ChannelRole,
124 pub joined_at: SystemTime,
125 pub last_read: Option<MessageId>,
126 pub notifications: NotificationSettings,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
131pub enum ChannelRole {
132 Owner,
133 Admin,
134 Moderator,
135 Member,
136 Guest,
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct NotificationSettings {
142 pub all_messages: bool,
143 pub mentions_only: bool,
144 pub muted: bool,
145 pub muted_until: Option<SystemTime>,
146}
147
148impl Default for NotificationSettings {
149 fn default() -> Self {
150 Self {
151 all_messages: true,
152 mentions_only: false,
153 muted: false,
154 muted_until: None,
155 }
156 }
157}
158
159#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct ChannelSettings {
162 pub allow_threads: bool,
163 pub allow_reactions: bool,
164 pub allow_files: bool,
165 pub allow_voice_video: bool,
166 pub message_retention_days: Option<u32>,
167 pub max_message_length: usize,
168 pub slow_mode_seconds: Option<u32>,
169}
170
171impl Default for ChannelSettings {
172 fn default() -> Self {
173 Self {
174 allow_threads: true,
175 allow_reactions: true,
176 allow_files: true,
177 allow_voice_video: true,
178 message_retention_days: Some(90),
179 max_message_length: 4000,
180 slow_mode_seconds: None,
181 }
182 }
183}
184
185#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct Message {
188 pub id: MessageId,
189 pub channel_id: ChannelId,
190 pub thread_id: Option<ThreadId>,
191 pub author: UserId,
192 pub content: MessageContent,
193 pub created_at: SystemTime,
194 pub edited_at: Option<SystemTime>,
195 pub deleted_at: Option<SystemTime>,
196 pub reactions: Vec<Reaction>,
197 pub mentions: Vec<Mention>,
198 pub attachments: Vec<Attachment>,
199 pub reply_to: Option<MessageId>,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
204pub enum MessageContent {
205 Text(String),
207
208 RichText {
210 text: String,
211 formatting: Vec<TextFormat>,
212 },
213
214 System(SystemMessage),
216
217 Encrypted {
219 ciphertext: Vec<u8>,
220 algorithm: String,
221 },
222}
223
224#[derive(Debug, Clone, Serialize, Deserialize)]
226pub struct TextFormat {
227 pub start: usize,
228 pub end: usize,
229 pub format_type: FormatType,
230}
231
232#[derive(Debug, Clone, Serialize, Deserialize)]
234pub enum FormatType {
235 Bold,
236 Italic,
237 Code,
238 Strike,
239 Link(String),
240 Mention(UserId),
241 ChannelRef(ChannelId),
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize)]
246pub enum SystemMessage {
247 UserJoined(UserId),
248 UserLeft(UserId),
249 UserInvited { inviter: UserId, invitee: UserId },
250 ChannelRenamed { old_name: String, new_name: String },
251 ChannelDescriptionChanged,
252 CallStarted { call_id: String },
253 CallEnded { call_id: String, duration_seconds: u64 },
254}
255
256#[derive(Debug, Clone, Serialize, Deserialize)]
258pub struct Reaction {
259 pub emoji: String,
260 pub users: Vec<UserId>,
261}
262
263#[derive(Debug, Clone, Serialize, Deserialize)]
265pub enum Mention {
266 User(UserId),
267 Channel,
268 Here,
269 Everyone,
270}
271
272#[derive(Debug, Clone, Serialize, Deserialize)]
274pub struct Attachment {
275 pub id: String,
276 pub name: String,
277 pub mime_type: String,
278 pub size: u64,
279 pub url: String,
280 pub thumbnail_url: Option<String>,
281 pub metadata: AttachmentMetadata,
282}
283
284#[derive(Debug, Clone, Serialize, Deserialize)]
286pub enum AttachmentMetadata {
287 Image { width: u32, height: u32 },
288 Video { duration_seconds: u64, width: u32, height: u32 },
289 Audio { duration_seconds: u64 },
290 Document { page_count: Option<u32> },
291 Other,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize)]
296pub struct Thread {
297 pub id: ThreadId,
298 pub channel_id: ChannelId,
299 pub parent_message_id: MessageId,
300 pub reply_count: u32,
301 pub participant_count: u32,
302 pub last_reply_at: Option<SystemTime>,
303 pub participants: Vec<UserId>,
304}
305
306#[derive(Debug, Clone, Serialize, Deserialize)]
308pub struct Call {
309 pub id: String,
310 pub channel_id: ChannelId,
311 pub call_type: CallType,
312 pub started_by: UserId,
313 pub started_at: SystemTime,
314 pub ended_at: Option<SystemTime>,
315 pub participants: Vec<CallParticipant>,
316 pub recording_url: Option<String>,
317}
318
319#[derive(Debug, Clone, Serialize, Deserialize)]
321pub enum CallType {
322 Voice,
323 Video,
324 ScreenShare,
325}
326
327#[derive(Debug, Clone, Serialize, Deserialize)]
329pub struct CallParticipant {
330 pub user_id: UserId,
331 pub joined_at: SystemTime,
332 pub left_at: Option<SystemTime>,
333 pub is_muted: bool,
334 pub is_video_on: bool,
335 pub is_screen_sharing: bool,
336}
337
338pub struct ChatManager {
340 storage: StorageManager,
341 identity: EnhancedIdentity,
342}
343
344impl ChatManager {
345 pub fn new(storage: StorageManager, identity: EnhancedIdentity) -> Self {
347 Self { storage, identity }
348 }
349
350 pub async fn create_channel(
352 &mut self,
353 name: String,
354 description: String,
355 channel_type: ChannelType,
356 organization_id: Option<OrganizationId>,
357 ) -> Result<Channel> {
358 if let Some(org_id) = &organization_id {
360 }
363
364 let channel = Channel {
365 id: ChannelId::new(),
366 name,
367 description,
368 channel_type,
369 organization_id,
370 created_by: self.identity.base_identity.user_id.clone(),
371 created_at: SystemTime::now(),
372 members: vec![ChannelMember {
373 user_id: self.identity.base_identity.user_id.clone(),
374 role: ChannelRole::Owner,
375 joined_at: SystemTime::now(),
376 last_read: None,
377 notifications: NotificationSettings::default(),
378 }],
379 settings: ChannelSettings::default(),
380 metadata: HashMap::new(),
381 };
382
383 let key = keys::chat_channel(&channel.id.0);
385 self.storage.store_encrypted(
386 &key,
387 &channel,
388 ttl::PROFILE,
389 None,
390 ).await?;
391
392 self.add_user_channel(&channel.id).await?;
394
395 if matches!(channel.channel_type, ChannelType::Public) {
397 self.add_public_channel(&channel.id, &channel.name).await?;
398 }
399
400 Ok(channel)
401 }
402
403 pub async fn send_message(
405 &mut self,
406 channel_id: &ChannelId,
407 content: MessageContent,
408 thread_id: Option<ThreadId>,
409 attachments: Vec<Attachment>,
410 ) -> Result<Message> {
411 let channel = self.get_channel(channel_id).await?;
413 if !channel.members.iter().any(|m| m.user_id == self.identity.base_identity.user_id) {
414 return Err(ChatError::PermissionDenied("Not a member of channel".to_string()));
415 }
416
417 let message = Message {
418 id: MessageId::new(),
419 channel_id: channel_id.clone(),
420 thread_id,
421 author: self.identity.base_identity.user_id.clone(),
422 content,
423 created_at: SystemTime::now(),
424 edited_at: None,
425 deleted_at: None,
426 reactions: vec![],
427 mentions: vec![], attachments,
429 reply_to: None,
430 };
431
432 let msg_key = keys::chat_message(&channel_id.0, &message.id.0);
434 self.storage.store_encrypted(
435 &msg_key,
436 &message,
437 ttl::MESSAGE,
438 None,
439 ).await?;
440
441 let timestamp = message.created_at.duration_since(SystemTime::UNIX_EPOCH)
443 .unwrap().as_secs();
444 let index_key = keys::chat_index(&channel_id.0, timestamp);
445 self.storage.store_encrypted(
446 &index_key,
447 &message.id,
448 ttl::MESSAGE,
449 None,
450 ).await?;
451
452 Ok(message)
453 }
454
455 pub async fn get_channel(&self, channel_id: &ChannelId) -> Result<Channel> {
457 let key = keys::chat_channel(&channel_id.0);
458 self.storage.get_encrypted(&key).await
459 .map_err(|_| ChatError::ChannelNotFound(channel_id.0.clone()))
460 }
461
462 pub async fn get_user_channels(&self) -> Result<Vec<ChannelId>> {
464 let key = keys::user_channels(&self.identity.base_identity.user_id);
465 Ok(self.storage.get_encrypted(&key).await
466 .unwrap_or_else(|_| vec![]))
467 }
468
469 async fn add_user_channel(&mut self, channel_id: &ChannelId) -> Result<()> {
471 let mut channels = self.get_user_channels().await.unwrap_or_default();
472 if !channels.contains(channel_id) {
473 channels.push(channel_id.clone());
474
475 let key = keys::user_channels(&self.identity.base_identity.user_id);
476 self.storage.store_encrypted(
477 &key,
478 &channels,
479 ttl::PROFILE,
480 None,
481 ).await?;
482 }
483 Ok(())
484 }
485
486 async fn add_public_channel(&mut self, channel_id: &ChannelId, name: &str) -> Result<()> {
488 let key = keys::public_channel_list();
489 let mut public_channels: HashMap<String, String> = self.storage
490 .get_public(&key).await
491 .unwrap_or_default();
492
493 public_channels.insert(channel_id.0.clone(), name.to_string());
494
495 self.storage.store_public(
496 &key,
497 &public_channels,
498 ttl::PROFILE,
499 ).await?;
500
501 Ok(())
502 }
503
504 pub async fn create_thread(
506 &mut self,
507 channel_id: &ChannelId,
508 parent_message_id: &MessageId,
509 ) -> Result<Thread> {
510 let thread = Thread {
511 id: ThreadId(Uuid::new_v4().to_string()),
512 channel_id: channel_id.clone(),
513 parent_message_id: parent_message_id.clone(),
514 reply_count: 0,
515 participant_count: 1,
516 last_reply_at: None,
517 participants: vec![self.identity.base_identity.user_id.clone()],
518 };
519
520 Ok(thread)
522 }
523
524 pub async fn add_reaction(
526 &mut self,
527 channel_id: &ChannelId,
528 message_id: &MessageId,
529 emoji: String,
530 ) -> Result<()> {
531 let msg_key = keys::chat_message(&channel_id.0, &message_id.0);
532 let mut message: Message = self.storage.get_encrypted(&msg_key).await?;
533
534 let user_id = &self.identity.base_identity.user_id;
536 if let Some(reaction) = message.reactions.iter_mut().find(|r| r.emoji == emoji) {
537 if !reaction.users.contains(user_id) {
538 reaction.users.push(user_id.clone());
539 }
540 } else {
541 message.reactions.push(Reaction {
542 emoji,
543 users: vec![user_id.clone()],
544 });
545 }
546
547 self.storage.store_encrypted(
549 &msg_key,
550 &message,
551 ttl::MESSAGE,
552 None,
553 ).await?;
554
555 Ok(())
556 }
557}