aboutsummaryrefslogtreecommitdiff
path: root/src/output_protocol/tcp.rs
blob: f8e7787f13dd28f9f3a9e0eb64ca5fb3b0373738 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use crate::OutputProtocol;
use crate::debug_log;
use std::sync::Arc;
use tokio::io::AsyncWriteExt;
use tokio::net::TcpListener;
use tokio::sync::Mutex;

#[derive(Debug)]
pub struct TCPOutputProtocol {
    port: u16,
    clients: Arc<Mutex<Vec<tokio::net::tcp::OwnedWriteHalf>>>,
}

impl TCPOutputProtocol {
    pub fn new(port: u16) -> Self {
        Self {
            port,
            clients: Arc::new(Mutex::new(Vec::new())),
        }
    }
}

impl OutputProtocol for TCPOutputProtocol {
    async fn init(&self) {
        let port = self.port;
        let clients = self.clients.clone();

        tokio::spawn(async move {
            let addr = format!("0.0.0.0:{}", port);
            let listener = match TcpListener::bind(&addr).await {
                Ok(l) => l,
                Err(e) => {
                    eprintln!("[TCP] Failed to bind to {}: {}", addr, e);
                    return;
                }
            };

            debug_log!("[TCP] Listening on {}", addr);

            loop {
                match listener.accept().await {
                    Ok((stream, peer)) => {
                        debug_log!("[TCP] Client connected: {}", peer);
                        let (_, write_half) = stream.into_split();
                        clients.lock().await.push(write_half);
                    }
                    Err(e) => {
                        debug_log!("[TCP] Accept error: {}", e);
                    }
                }
            }
        });
    }

    async fn send(self: Arc<Self>, message: &str) {
        let mut clients = self.clients.lock().await;
        let mut i = 0;
        while i < clients.len() {
            let mut write_half = clients.remove(i);
            let bytes = format!("{}\n", message);
            match write_half.write_all(bytes.as_bytes()).await {
                Ok(_) => {
                    // Re-insert at the end if successful
                    clients.insert(i, write_half);
                    i += 1;
                }
                Err(_) => {
                    // Client disconnected, drop it
                    debug_log!("[TCP] Client disconnected, removing");
                }
            }
        }
    }
}