mod config; mod xsetroot; use chrono::prelude::*; use log::*; use std::{ fmt, io::{prelude::*, BufReader}, net::Shutdown, os::unix::net::{UnixListener, UnixStream}, sync::{Arc, Mutex}, thread, time, }; use xsetroot::XSetRoot; pub type MTState = Arc>; fn handle_client(stream: UnixStream, st: MTState) { let mut rdr = BufReader::new(&stream); let mut msg = String::new(); let _ = rdr.read_line(&mut msg); let _ = write!(&stream, "OK"); let mut data = st.lock().unwrap(); data.msg = msg.trim().to_string(); info!("new message: {}", data.msg); stream.shutdown(Shutdown::Both).expect("socket to close"); } const UPDATE_FREQUENCY: u64 = 250; fn update_every_so_often(st: MTState) { loop { let so_often = time::Duration::from_millis(UPDATE_FREQUENCY); thread::sleep(so_often); { let data = st.lock().unwrap(); data.show(); } } } const FIVE_MINUTES: u64 = 60 * 5; fn front_update(st: MTState, cfg: config::Config) { loop { match reqwest::blocking::get(&cfg.front_url) { Ok(who) => { let mut data = st.lock().unwrap(); let who = who.text().unwrap().trim().to_string(); if who != data.front { data.front = who; info!("new front: {}", data.front); } } Err(why) => { error!("front error: {:?}", why); } } let dur = time::Duration::new(FIVE_MINUTES, 0); thread::sleep(dur); } } fn main() -> std::io::Result<()> { let st: State = State::init(); st.show(); let mtst = Arc::new(Mutex::new(st)); env_logger::init(); let cfg = config::load()?; info!("{:?}", cfg); // start update thread { let mtst = mtst.clone(); thread::spawn(move || update_every_so_often(mtst)); } // start front thread { let mtst = mtst.clone(); let cfg = cfg.clone(); thread::spawn(move || front_update(mtst, cfg)); } let _ = std::fs::remove_file("/home/cadey/tmp/cabytcini.sock")?; let listener = UnixListener::bind("/home/cadey/tmp/cabytcini.sock")?; for stream in listener.incoming() { match stream { Ok(stream) => { let mtst = mtst.clone(); thread::spawn(move || handle_client(stream, mtst)); } Err(err) => { error!("unix listener error: {:?}", err); break; } } } Ok(()) } pub struct State { msg: String, front: String, } impl fmt::Display for State { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.msg) } } impl State { fn init() -> State { State { msg: "".to_string(), front: "".to_string(), } } fn show(&self) { let now = Local::now().format("%H:%M M%m %-d %a"); let xsr = XSetRoot::init(); let mut msg = String::new(); if self.msg != "" { msg.push_str(format!("{} | ", msg).as_str()); } if self.front != "" { msg.push_str(format!("{} | ", self.front).as_str()); } msg.push_str(format!("{}", now).as_str()); xsr.render(msg); } }