use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Session {
pub target: String,
pub app_id: String,
pub profile: String,
pub engine_port: u16,
pub engine_token: String,
pub started_at: u64,
}
fn file(root: &Path) -> PathBuf {
root.join("build/day/sessions.json")
}
pub fn list(root: &Path) -> Vec<Session> {
std::fs::read_to_string(file(root))
.ok()
.and_then(|s| serde_json::from_str(&s).ok())
.unwrap_or_default()
}
fn write(root: &Path, sessions: &[Session]) {
let path = file(root);
if let Some(dir) = path.parent() {
let _ = std::fs::create_dir_all(dir);
}
if let Ok(json) = serde_json::to_string_pretty(sessions) {
let _ = std::fs::write(path, json);
}
}
pub fn record(root: &Path, session: Session) {
let mut all = list(root);
all.retain(|s| s.target != session.target);
all.push(session);
write(root, &all);
}
pub fn remove(root: &Path, target: &str) {
let mut all = list(root);
all.retain(|s| s.target != target);
write(root, &all);
}
pub fn find(root: &Path, target: &str) -> Option<Session> {
list(root).into_iter().find(|s| s.target == target)
}
pub fn reachable(session: &Session, direct: bool) -> Option<bool> {
if !direct {
return None;
}
Some(
std::net::TcpStream::connect_timeout(
&std::net::SocketAddr::from(([127, 0, 0, 1], session.engine_port)),
std::time::Duration::from_millis(300),
)
.is_ok(),
)
}
pub fn now_millis() -> u64 {
std::time::UNIX_EPOCH
.elapsed()
.map(|d| d.as_millis() as u64)
.unwrap_or(0)
}