pub mod httpconnector; use std::net::IpAddr; use crate::{client::Client, executor::Executor}; use remote_control_rs::tasks::{IntoTask, NETWORK_T}; pub type Result = std::result::Result; pub trait Connection { type Ok: std::fmt::Display + IntoTask + AsRef = String; type Err: std::fmt::Debug; // should use channel to notify update fn update(&self) -> Result; // None if no update(content is same) // TODO: queue failed ntfy // TODO: impl type of data fn ntfy(&self, data: String) -> std::result::Result<(), Self::Err>; fn is_prev(&mut self, str: &Self::Ok) -> bool; fn get_ip(&self) -> Option; fn force_network(&mut self) { _ = Executor::new(&NETWORK_T, ["on".to_string()]); } fn init(&self, c: &Client) -> std::result::Result<(), Self::Err> where Self: std::marker::Sized, { self.ntfy(format!( r#"New client: {c} "#, )) } fn reinit(&mut self) { self.force_network(); } fn tick(&mut self) { // tradeoff: if I put this at the ened of the loop, then the continue would just skip it, and continue doing update() until with no waiting, this wastes lot of cpu/IO // however, of course we can add a manual sleep before it continue and put this in the end, but that's code duplication // the cons of the current approch is that the first time we've entered, it would start sleeping self.reinit(); match self.update() { Result::Ok(s) => { if self.is_prev(&s) { return; } let mut it = s.as_ref().split_whitespace(); let task = match it.next() { Some(t) => t, None => return, }; // FIXME: handle the errors... peak prod code self.ntfy( Executor::new(task, it.map(str::to_string)) .unwrap() .run() .unwrap() .clone() .unwrap(), ) .unwrap(); } Result::Err(e) => { #[cfg(debug_assertions)] std::eprintln!( "[{}:{}:{}] {} = {:#?}", std::file!(), std::line!(), std::column!(), std::stringify!(e), &&e as &dyn std::fmt::Debug, ); } } } }