Skip to main content

apollo/channels/
cli.rs

1//! CLI channel — interactive terminal chat.
2
3use async_trait::async_trait;
4use tokio::io::{AsyncBufReadExt, BufReader};
5use tokio::sync::mpsc;
6
7use super::traits::*;
8
9pub struct CliChannel;
10
11impl CliChannel {
12    pub fn new() -> Self {
13        Self
14    }
15}
16
17impl Default for CliChannel {
18    fn default() -> Self {
19        Self::new()
20    }
21}
22
23#[async_trait]
24impl Channel for CliChannel {
25    fn name(&self) -> &str {
26        "cli"
27    }
28
29    async fn start(&mut self) -> anyhow::Result<mpsc::Receiver<IncomingMessage>> {
30        let (tx, rx) = mpsc::channel(32);
31
32        tokio::spawn(async move {
33            let stdin = tokio::io::stdin();
34            let reader = BufReader::new(stdin);
35            let mut lines = reader.lines();
36
37            while let Ok(Some(line_input)) = lines.next_line().await {
38                let line = line_input.trim().to_string();
39                if line.is_empty() {
40                    continue;
41                }
42                if line == "/quit" || line == "/exit" {
43                    break;
44                }
45
46                let msg = IncomingMessage {
47                    id: uuid::Uuid::new_v4().to_string(),
48                    sender_id: "local".to_string(),
49                    sender_name: Some("user".to_string()),
50                    chat_id: "cli".to_string(),
51                    text: line,
52                    is_group: false,
53                    reply_to: None,
54                    timestamp: chrono::Utc::now(),
55                };
56
57                if tx.send(msg).await.is_err() {
58                    break;
59                }
60            }
61        });
62
63        Ok(rx)
64    }
65
66    async fn send(&self, message: OutgoingMessage) -> anyhow::Result<Option<String>> {
67        println!("{}", message.text);
68        Ok(None)
69    }
70
71    async fn stop(&mut self) -> anyhow::Result<()> {
72        Ok(())
73    }
74}