use std::io; use std::io::{BufRead, BufReader, ErrorKind, Write}; use std::os::unix::net::{UnixListener, UnixStream}; use std::thread; use super::protocol::{ClientboundPacket, ServerboundPacket}; use crossbeam_channel::Sender; use log::{debug, error, info, warn}; pub fn network_loop(s: Sender<(u32, ServerboundPacket, Sender)>) { let listener = UnixListener::bind("/run/user/1000/calendar").unwrap(); let mut id_counter = 0; loop { let (stream, addr) = listener.accept().unwrap(); let s = s.clone(); 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(), s.clone()) { warn!("client dropped: {:?} ({})", addr, err); } else { info!("client dropped: {:?}", addr); } }); } } fn handle_connection( id: u32, mut stream: UnixStream, s: Sender<(u32, ServerboundPacket, Sender)>, ) -> io::Result<()> { let mut reader = BufReader::new(stream.try_clone()?); let (responder, responses) = crossbeam_channel::unbounded(); 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::(buf.as_str()) { Ok(packet) => { debug!("{id} <- {packet:?}"); s.send((id, packet, responder.clone())) .map_err(|_| io::Error::from(ErrorKind::InvalidInput))?; } Err(err) => responder .send(ClientboundPacket::Error(format!("{}", &err))) .map_err(|_| io::Error::from(ErrorKind::InvalidInput))?, } buf.clear(); } }