use std::sync::atomic::{AtomicU32, Ordering};
use kanade_shared::manifest::Require;
static LATEST_SYSTEM_CPU: AtomicU32 = AtomicU32::new(f32::NAN.to_bits());
pub fn set_system_cpu(pct: Option<f32>) {
let bits = pct.unwrap_or(f32::NAN).to_bits();
LATEST_SYSTEM_CPU.store(bits, Ordering::Relaxed);
}
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
fn system_cpu() -> Option<f64> {
let v = f32::from_bits(LATEST_SYSTEM_CPU.load(Ordering::Relaxed));
if v.is_nan() { None } else { Some(v as f64) }
}
pub fn require_satisfied(req: &Require) -> bool {
if req.is_empty() {
return true; }
#[cfg(target_os = "windows")]
{
use kanade_shared::manifest::require_met;
let (ac_online, idle) = sense_windows();
require_met(req, ac_online, idle, system_cpu())
}
#[cfg(not(target_os = "windows"))]
{
let _ = req;
true
}
}
#[cfg(target_os = "windows")]
fn sense_windows() -> (bool, Option<std::time::Duration>) {
use std::time::Duration;
use windows::Win32::System::Power::{GetSystemPowerStatus, SYSTEM_POWER_STATUS};
use windows::Win32::System::RemoteDesktop::{
WTS_CURRENT_SERVER_HANDLE, WTS_INFO_CLASS, WTSFreeMemory, WTSGetActiveConsoleSessionId,
WTSINFOW, WTSQuerySessionInformationW, WTSSessionInfo,
};
use windows::core::PWSTR;
let ac_online = {
let mut st = SYSTEM_POWER_STATUS::default();
match unsafe { GetSystemPowerStatus(&mut st) } {
Ok(()) => st.ACLineStatus == 1,
Err(_) => false,
}
};
let idle = {
let session = unsafe { WTSGetActiveConsoleSessionId() };
if session == 0xFFFF_FFFF {
Some(Duration::MAX)
} else {
let mut buf = PWSTR::null();
let mut bytes: u32 = 0;
unsafe {
match WTSQuerySessionInformationW(
Some(WTS_CURRENT_SERVER_HANDLE),
session,
WTS_INFO_CLASS(WTSSessionInfo.0),
&mut buf,
&mut bytes,
) {
Ok(())
if (bytes as usize) >= std::mem::size_of::<WTSINFOW>()
&& !buf.is_null() =>
{
let info = &*(buf.0 as *const WTSINFOW);
let delta_100ns = info.CurrentTime.saturating_sub(info.LastInputTime);
let d = if delta_100ns > 0 {
Duration::from_nanos((delta_100ns as u64).saturating_mul(100))
} else {
Duration::ZERO
};
WTSFreeMemory(buf.0 as *mut core::ffi::c_void);
Some(d)
}
Ok(()) => {
if !buf.is_null() {
WTSFreeMemory(buf.0 as *mut core::ffi::c_void);
}
None
}
Err(_) => None,
}
}
}
};
(ac_online, idle)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_require_is_satisfied_without_syscalls() {
assert!(require_satisfied(&Require::default()));
assert!(require_satisfied(&Require {
ac_power: false,
idle: None,
cpu_below: None,
}));
#[cfg(not(target_os = "windows"))]
assert!(require_satisfied(&Require {
ac_power: true,
idle: Some("10m".into()),
cpu_below: Some(20.0),
}));
}
#[test]
fn system_cpu_roundtrips_and_unknown_is_none() {
set_system_cpu(Some(42.5));
assert_eq!(system_cpu(), Some(42.5));
set_system_cpu(None);
assert!(system_cpu().is_none());
}
}