aboutsummaryrefslogtreecommitdiff
path: root/src/interface.rs
blob: fcdb470150b83ac4ed7767c112cacc1e11f8a7bd (plain)
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
use super::protocol::{ClientboundPacket, ServerboundPacket};
use crate::handle_packet;
use log::{debug, error, info, warn};
use std::io;
use std::io::{BufRead, BufReader, ErrorKind, Write};
use std::os::unix::net::{UnixListener, UnixStream};
use std::thread;

pub fn network_loop() {
    let listener = UnixListener::bind("/run/user/1000/calendar").unwrap();
    let mut id_counter = 0;

    loop {
        let (stream, addr) = listener.accept().unwrap();
        let id = id_counter;
        id_counter += 1;
        thread::spawn(move || {
            info!("client connected: {:?}", addr);
            if let Err(err) = handle_connection(id, stream.try_clone().unwrap()) {
                warn!("client dropped: {:?} ({})", addr, err);
            } else {
                info!("client dropped: {:?}", addr);
            }
        });
    }
}

fn handle_connection(id: u32, mut stream: UnixStream) -> io::Result<()> {
    let mut reader = BufReader::new(stream.try_clone()?);
    let (responder, responses) = crossbeam_channel::unbounded();
    responder
        .send(ClientboundPacket::Handshake {
            version: env!("CARGO_PKG_VERSION").to_string(),
        })
        .unwrap();
    thread::spawn(move || {
        for m in responses {
            debug!("{id} -> {m:?}");
            match stream
                .write_fmt(format_args!("{}\n", serde_json::to_string(&m).unwrap()))
                .map_err(|e| e.kind())
            {
                Ok(_) => (),
                Err(ErrorKind::BrokenPipe) => break,
                Err(e) => error!("network error: {:?}", e),
            }
        }
    });
    {
        let mut buf = String::new();
        loop {
            if reader.read_line(&mut buf)? == 0 {
                break Ok(());
            };
            match serde_json::from_str::<ServerboundPacket>(buf.as_str()) {
                Ok(packet) => {
                    debug!("{id} <- {packet:?}");
                    handle_packet(id, packet, responder.clone());
                }
                Err(err) => responder
                    .send(ClientboundPacket::Error(format!("{}", &err)))
                    .map_err(|_| io::Error::from(ErrorKind::InvalidInput))?,
            }

            buf.clear();
        }
    }
}