mod drivetemp;
mod hddtemp;
mod hdparm;
mod smartctl;
use std::{
fmt,
net::{Ipv4Addr, SocketAddrV4},
};
use crate::device::Drive;
#[derive(thiserror::Error, Debug)]
pub(crate) enum ProberError {
#[error("Temperature probing method unsupported: {0}")]
Unsupported(String),
#[error(transparent)]
Other(#[from] anyhow::Error),
}
pub(crate) type Temp = f64;
pub(crate) trait DriveTempProbeMethod: fmt::Display {
type Prober: DeviceTempProber;
fn prober(&self, drive: &Drive) -> Result<Self::Prober, ProberError>;
fn supports_probing_sleeping(&self) -> bool;
}
pub(crate) trait DeviceTempProber {
fn probe_temp(&mut self) -> anyhow::Result<Temp>;
}
mod dyn_method {
use std::fmt;
use super::{DeviceTempProber, DriveTempProbeMethod, ProberError};
use crate::Drive;
pub(super) trait DynDriveTempProbeMethod: fmt::Display {
fn prober(&self, drive: &Drive) -> Result<Box<dyn DeviceTempProber>, ProberError>;
fn supports_probing_sleeping(&self) -> bool;
}
impl<T> DynDriveTempProbeMethod for T
where
T: DriveTempProbeMethod,
T::Prober: 'static,
{
fn prober(&self, drive: &Drive) -> Result<Box<dyn DeviceTempProber>, ProberError> {
let prober = Box::new(<T as DriveTempProbeMethod>::prober(self, drive)?);
Ok(prober)
}
fn supports_probing_sleeping(&self) -> bool {
<T as DriveTempProbeMethod>::supports_probing_sleeping(self)
}
}
}
pub(crate) fn prober(
drive: &Drive,
hddtemp_daemon_port: u16,
) -> anyhow::Result<Option<(Box<dyn DeviceTempProber>, bool)>> {
let methods: [Box<dyn dyn_method::DynDriveTempProbeMethod>; 6] = [
Box::new(drivetemp::Method),
Box::new(hdparm::Method),
Box::new(smartctl::SctMethod),
Box::new(hddtemp::DaemonMethod {
addr: SocketAddrV4::new(Ipv4Addr::LOCALHOST, hddtemp_daemon_port),
}),
Box::new(hddtemp::InvocationMethod),
Box::new(smartctl::AttribMethod),
];
for method in methods {
match method.prober(drive) {
Ok(p) => {
log::info!("Using probing method '{method}' for drive '{drive}'");
let sqa = method.supports_probing_sleeping();
return Ok(Some((p, sqa)));
}
Err(ProberError::Unsupported(e)) => {
log::info!("Drive '{drive}' does not support probing method '{method}': {e}");
}
Err(ProberError::Other(e)) => return Err(e),
}
}
Ok(None)
}