#![cfg(not(target_arch = "wasm32"))]
use exfiltrate_internal::instances::Instance;
use std::sync::atomic::{AtomicBool, Ordering};
static ADVERTISED: AtomicBool = AtomicBool::new(false);
pub(crate) fn advertise(name: &str, addr: &str) {
for stale in exfiltrate_internal::instances::read_all() {
if stale.addr == addr && stale.pid != std::process::id() {
exfiltrate_internal::instances::remove(stale.pid);
}
}
let instance = Instance {
pid: std::process::id(),
name: name.to_string(),
addr: addr.to_string(),
started_at: now_rfc3339(),
};
match exfiltrate_internal::instances::write(&instance) {
Ok(_) => {
ADVERTISED.store(true, Ordering::Relaxed);
}
Err(error) => crate::diagnostic(&format!(
"exfiltrate: could not advertise this instance in {}: {error}. \
`exfiltrate instances` will not list it; the server itself is unaffected.",
exfiltrate_internal::instances::directory().display()
)),
}
}
pub(crate) fn withdraw() {
if ADVERTISED.swap(false, Ordering::Relaxed) {
exfiltrate_internal::instances::remove(std::process::id());
}
}
fn now_rfc3339() -> String {
let Ok(since_epoch) = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH) else {
return String::new();
};
let seconds = since_epoch.as_secs() as i64;
let days = seconds.div_euclid(86_400);
let time_of_day = seconds.rem_euclid(86_400);
let (year, month, day) = civil_from_days(days);
format!(
"{year:04}-{month:02}-{day:02}T{:02}:{:02}:{:02}Z",
time_of_day / 3600,
(time_of_day % 3600) / 60,
time_of_day % 60
)
}
fn civil_from_days(days: i64) -> (i64, u32, u32) {
let z = days + 719_468;
let era = z.div_euclid(146_097);
let day_of_era = z.rem_euclid(146_097);
let year_of_era =
(day_of_era - day_of_era / 1460 + day_of_era / 36_524 - day_of_era / 146_096) / 365;
let year = year_of_era + era * 400;
let day_of_year = day_of_era - (365 * year_of_era + year_of_era / 4 - year_of_era / 100);
let shifted_month = (5 * day_of_year + 2) / 153;
let day = (day_of_year - (153 * shifted_month + 2) / 5 + 1) as u32;
let month = if shifted_month < 10 {
shifted_month + 3
} else {
shifted_month - 9
} as u32;
(if month <= 2 { year + 1 } else { year }, month, day)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_timestamp_is_rfc_3339_shaped() {
let stamp = now_rfc3339();
assert_eq!(stamp.len(), 20, "{stamp}");
assert!(stamp.ends_with('Z'), "{stamp}");
assert_eq!(&stamp[4..5], "-", "{stamp}");
assert_eq!(&stamp[10..11], "T", "{stamp}");
}
#[test]
fn withdrawing_without_advertising_does_nothing() {
ADVERTISED.store(false, Ordering::Relaxed);
withdraw();
assert!(!ADVERTISED.load(Ordering::Relaxed));
}
}