use crate::error::{ErrorDomain, ErrorLevel, Result, XmlError};
use chrono::{DateTime, TimeZone, Utc};
use std::sync::OnceLock;
use supso_project::{Enforcement, Status, Supso};
const PROJECT_SLUG: &str = "sup-xml";
static VERDICT: OnceLock<std::result::Result<(), String>> = OnceLock::new();
fn now() -> DateTime<Utc> {
let dur = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default();
DateTime::<Utc>::from_timestamp(dur.as_secs() as i64, dur.subsec_nanos())
.unwrap_or_else(|| Utc.timestamp_opt(0, 0).unwrap())
}
fn verdict() -> &'static std::result::Result<(), String> {
VERDICT.get_or_init(|| {
let at = now();
let status = Supso::project(PROJECT_SLUG)
.enforcement(Enforcement::Silent)
.check_at(at);
match status {
Status::Valid(_) => Ok(()),
Status::Grace { .. } => {
if let Some(notice) = status.grace_message(at) {
log::error!("{notice}");
}
Ok(())
}
Status::Unlicensed(e) => Err(e.to_string()),
}
})
}
pub fn verify_license() -> Result<()> {
ensure_licensed()
}
pub(crate) fn ensure_licensed() -> Result<()> {
match verdict() {
Ok(()) => Ok(()),
Err(reason) => Err(XmlError::new(
ErrorDomain::None,
ErrorLevel::Fatal,
format!(
"sup-xml: a valid license is required to parse documents — {reason}. \
Get a certificate (free for individuals and 30-day evaluation) at \
https://supso.org/projects/sup-xml"
),
)),
}
}