diff options
Diffstat (limited to 'src/interface.rs')
-rw-r--r-- | src/interface.rs | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/src/interface.rs b/src/interface.rs new file mode 100644 index 0000000..568c450 --- /dev/null +++ b/src/interface.rs @@ -0,0 +1,68 @@ +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<ClientboundPacket>)>) { + 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<ClientboundPacket>)>, +) -> 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::<ServerboundPacket>(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(); + } +} |