libfancontrold 0.4.0

Base library for fancontrold.
Documentation
//! Libfancontrold is the base library for fancontrold, a system daemon written in rust that controls your computer's fans depending on various configurable sensor inputs.

mod address;
mod error;

/// Module containing the config structs.
pub mod config;

pub use address::{Address, Addressable, Error as AddressError};
pub use error::Error;

use config::Config;

use libmedium::{
    sensors::{Error as SensorError, SensorSubFunctionType},
    units::Temperature,
};

#[cfg(feature = "async")]
use libmedium::{
    hwmon::async_hwmon::Hwmons, sensors::async_sensors::virt::virtual_sensor_from_path,
};

#[cfg(not(feature = "async"))]
use libmedium::{hwmon::sync_hwmon::Hwmons, sensors::sync_sensors::virt::virtual_sensor_from_path};

use std::convert::TryInto;

/// Checks the given `Config` for errors and incompatibilities with the given `Hwmons`.
pub async fn check_config<T>(config: T, hwmons: &Hwmons) -> Vec<Error>
where
    T: TryInto<Config>,
    Error: From<<T as TryInto<Config>>::Error>,
{
    let config = match config.try_into() {
        Ok(c) => c,
        Err(e) => return vec![e.into()],
    };

    let mut errors = Vec::new();

    for channel_config in config.channel_configs() {
        let channel_address = channel_config.address();

        match hwmons.get_pwm(&channel_address) {
            Ok(pwm_sensor) => {
                if !pwm_sensor
                    .supported_write_sub_functions()
                    .contains(&SensorSubFunctionType::Pwm)
                {
                    errors.push(Error::pwm_not_writable(channel_address.clone()));
                }

                #[cfg(feature = "async")]
                if let Err(e) = pwm_sensor.read_enable().await {
                    match e {
                        SensorError::SubtypeNotSupported { .. } => (),
                        _ => errors.push(Error::pwm_enable(e)),
                    }
                }

                #[cfg(not(feature = "async"))]
                if let Err(e) = pwm_sensor.read_enable() {
                    match e {
                        SensorError::SubtypeNotSupported { .. } => (),
                        _ => errors.push(Error::pwm_enable(e)),
                    }
                }
            }
            Err(e) => errors.push(Error::sensor_not_found(e)),
        }

        for temp_address in &channel_config.temps {
            if let Err(e) = hwmons.get_temp(temp_address) {
                errors.push(Error::sensor_not_found(e));
            }
        }

        for virtual_temp_path in &channel_config.virtual_temps {
            if let Err(e) = virtual_sensor_from_path::<Temperature>(virtual_temp_path) {
                errors.push(Error::virtual_temp_not_found(virtual_temp_path, e));
            }
        }
    }

    errors
}

// #[cfg(test)]
// mod tests {
//     use std::fs;
//     use std::fs::{File, OpenOptions};
//     use std::io::Write;
//     use std::path::{Path, PathBuf};

//     pub struct VirtualHwmonBuilder {
//         path: PathBuf,
//     }

//     impl VirtualHwmonBuilder {
//         pub fn create(
//             path: impl AsRef<Path>,
//             index: u16,
//             name: impl AsRef<[u8]>,
//         ) -> VirtualHwmonBuilder {
//             let path = path.as_ref().join(format!("hwmon{}", index));

//             fs::create_dir_all(&path).unwrap();

//             File::create(path.join("name"))
//                 .unwrap()
//                 .write(name.as_ref())
//                 .unwrap();

//             std::os::unix::fs::symlink(
//                 path.parent().unwrap().canonicalize().unwrap(),
//                 path.join("device"),
//             )
//             .unwrap();

//             VirtualHwmonBuilder { path }
//         }

//         pub fn add_temp(
//             self,
//             index: u16,
//             value: i32,
//             label: impl AsRef<str>,
//         ) -> VirtualHwmonBuilder {
//             OpenOptions::new()
//                 .read(true)
//                 .write(true)
//                 .create(true)
//                 .truncate(true)
//                 .open(self.path().join(format!("temp{}_input", index)))
//                 .unwrap()
//                 .write(value.to_string().as_bytes())
//                 .unwrap();

//             OpenOptions::new()
//                 .read(true)
//                 .write(true)
//                 .create(true)
//                 .truncate(true)
//                 .open(self.path().join(format!("temp{}_label", index)))
//                 .unwrap()
//                 .write(label.as_ref().as_bytes())
//                 .unwrap();

//             self
//         }

//         pub fn add_fan(self, index: u16, value: u32) -> VirtualHwmonBuilder {
//             OpenOptions::new()
//                 .read(true)
//                 .write(true)
//                 .create(true)
//                 .truncate(true)
//                 .open(self.path().join(format!("fan{}_input", index)))
//                 .unwrap()
//                 .write(value.to_string().as_bytes())
//                 .unwrap();

//             self
//         }

//         pub fn add_pwm(
//             self,
//             index: u16,
//             create_enable_file: bool,
//             create_mode_file: bool,
//         ) -> VirtualHwmonBuilder {
//             OpenOptions::new()
//                 .read(true)
//                 .write(true)
//                 .create(true)
//                 .truncate(true)
//                 .open(self.path.join(&format!("pwm{}", index)))
//                 .unwrap()
//                 .write(b"0")
//                 .unwrap();
//             if create_enable_file {
//                 OpenOptions::new()
//                     .read(true)
//                     .write(true)
//                     .create(true)
//                     .truncate(true)
//                     .open(self.path.join(&format!("pwm{}_enable", index)))
//                     .unwrap()
//                     .write(b"2")
//                     .unwrap();
//             }
//             if create_mode_file {
//                 OpenOptions::new()
//                     .read(true)
//                     .write(true)
//                     .create(true)
//                     .truncate(true)
//                     .open(self.path.join(&format!("pwm{}_mode", index)))
//                     .unwrap()
//                     .write(b"1")
//                     .unwrap();
//             }

//             self.add_fan(index, 1000)
//         }

//         pub fn path(&self) -> &Path {
//             self.path.as_path()
//         }
//     }
// }