datalogger/src/main.rs

105 lines
2.8 KiB
Rust

#![feature(proc_macro_hygiene, decl_macro)]
#[macro_use]
extern crate rocket;
#[macro_use]
extern crate anyhow;
use rocket::{http::RawStr, State};
use std::{
collections::BTreeMap,
fmt::Display,
sync::{Arc, Mutex},
time::{Duration, SystemTime},
};
#[derive(Default)]
struct LoggedAccesses {
devices: BTreeMap<String, DeviceLog>,
}
#[derive(Default)]
struct DeviceLog {
access_times: Vec<SystemTime>,
}
impl LoggedAccesses {
pub fn log_device_access(&mut self, device_name: &str) {
let device = self.devices.entry(String::from(device_name)).or_default();
let now = SystemTime::now();
device.access_times.push(now)
}
}
impl DeviceLog {
pub fn get_duration(&self) -> Result<(Duration, &SystemTime, &SystemTime), anyhow::Error> {
let start = self.access_times.first().ok_or(anyhow!("No start time"))?;
let end = self.access_times.last().ok_or(anyhow!("No end time"))?;
let duration = end
.duration_since(start.clone())
.map_err(|_| anyhow!("Times could not be diffed"))?;
Ok((duration, &start, &end))
}
}
impl Display for LoggedAccesses {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (device_name, device_log) in &self.devices {
f.write_fmt(format_args!("{}: {}\n", device_name, device_log))?
}
Ok(())
}
}
impl Display for DeviceLog {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.get_duration() {
Ok((duration, start, end)) => f.write_fmt(format_args!(
"{} seconds between first ({:?}) and last ({:?}) call",
duration.as_secs(),
start,
end
)),
Err(e) => f.write_fmt(format_args!("Error getting duration: {}", e)),
}
}
}
#[get("/")]
fn index(state: State<Arc<Mutex<LoggedAccesses>>>) -> Result<String, anyhow::Error> {
match state.clone().lock() {
Ok(logged_accesses) => Ok(format!(
"Devices:\n{}\n\nwhile true; do curl https://pc.vvn.space/log/name; sleep 5; done",
logged_accesses
)),
Err(_) => Err(anyhow!("Couldn't lock state")),
}
}
#[get("/log/<device_name>")]
fn log(
device_name: &RawStr,
state: State<Arc<Mutex<LoggedAccesses>>>,
) -> Result<String, anyhow::Error> {
match &mut state.clone().lock() {
Ok(logged_accesses) => {
logged_accesses.log_device_access(device_name);
Ok(String::from("Logged"))
}
Err(_) => Err(anyhow!("Couldn't lock state")),
}
}
fn main() {
rocket::ignite()
.manage(Arc::<Mutex<LoggedAccesses>>::default())
.mount("/", routes![index, log])
.launch();
println!("after");
}