1
Fork 0
mirror of https://github.com/RGBCube/superfreq synced 2025-07-27 17:07:44 +00:00

config: modularize; add config watcher and move error variants

This commit is contained in:
NotAShelf 2025-05-14 01:17:42 +03:00
parent dde938b638
commit 9f7d86ff01
No known key found for this signature in database
GPG key ID: 29D95B64378DB4BF
10 changed files with 349 additions and 126 deletions

173
Cargo.lock generated
View file

@ -38,7 +38,7 @@ version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [ dependencies = [
"windows-sys", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -49,9 +49,15 @@ checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"once_cell", "once_cell",
"windows-sys", "windows-sys 0.59.0",
] ]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.9.0" version = "2.9.0"
@ -123,7 +129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73"
dependencies = [ dependencies = [
"nix", "nix",
"windows-sys", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -144,7 +150,7 @@ dependencies = [
"libc", "libc",
"option-ext", "option-ext",
"redox_users", "redox_users",
"windows-sys", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -153,6 +159,27 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "filetime"
version = "0.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
dependencies = [
"cfg-if",
"libc",
"libredox",
"windows-sys 0.59.0",
]
[[package]]
name = "fsevent-sys"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.16" version = "0.2.16"
@ -192,12 +219,52 @@ dependencies = [
"hashbrown", "hashbrown",
] ]
[[package]]
name = "inotify"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
dependencies = [
"bitflags 2.9.0",
"inotify-sys",
"libc",
]
[[package]]
name = "inotify-sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "is_terminal_polyfill" name = "is_terminal_polyfill"
version = "1.70.1" version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "kqueue"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a"
dependencies = [
"kqueue-sys",
"libc",
]
[[package]]
name = "kqueue-sys"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b"
dependencies = [
"bitflags 1.3.2",
"libc",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.172" version = "0.2.172"
@ -210,28 +277,75 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.9.0",
"libc", "libc",
"redox_syscall",
] ]
[[package]]
name = "log"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.4" version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "mio"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.30.1" version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.9.0",
"cfg-if", "cfg-if",
"cfg_aliases", "cfg_aliases",
"libc", "libc",
] ]
[[package]]
name = "notify"
version = "8.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943"
dependencies = [
"bitflags 2.9.0",
"filetime",
"fsevent-sys",
"inotify",
"kqueue",
"libc",
"log",
"mio",
"notify-types",
"walkdir",
"windows-sys 0.59.0",
]
[[package]]
name = "notify-types"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.16.0" version = "1.16.0"
@ -272,6 +386,15 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "redox_syscall"
version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
dependencies = [
"bitflags 2.9.0",
]
[[package]] [[package]]
name = "redox_users" name = "redox_users"
version = "0.5.0" version = "0.5.0"
@ -283,6 +406,15 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.219" version = "1.0.219"
@ -325,6 +457,7 @@ dependencies = [
"clap", "clap",
"ctrlc", "ctrlc",
"dirs", "dirs",
"notify",
"num_cpus", "num_cpus",
"serde", "serde",
"toml", "toml",
@ -414,12 +547,40 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.59.0" version = "0.59.0"

View file

@ -10,3 +10,4 @@ dirs = "6.0"
clap = { version = "4.0", features = ["derive"] } clap = { version = "4.0", features = ["derive"] }
num_cpus = "1.16" num_cpus = "1.16"
ctrlc = "3.4" ctrlc = "3.4"
notify = { version = "8.0.0", features = ["serde"] }

76
src/config/load.rs Normal file
View file

@ -0,0 +1,76 @@
// Configuration loading functionality
use std::fs;
use std::path::PathBuf;
use crate::config::types::{AppConfig, AppConfigToml, ConfigError, DaemonConfig, ProfileConfig};
// The primary function to load application configuration.
// It tries user-specific and then system-wide TOML files.
// Falls back to default settings if no file is found or if parsing fails.
pub fn load_config() -> Result<AppConfig, ConfigError> {
let mut config_paths: Vec<PathBuf> = Vec::new();
// User-specific path
if let Some(home_dir) = dirs::home_dir() {
let user_config_path = home_dir.join(".config/auto_cpufreq_rs/config.toml");
config_paths.push(user_config_path);
} else {
eprintln!(
"Warning: Could not determine home directory. User-specific config will not be loaded."
);
}
// System-wide path
let system_config_path = PathBuf::from("/etc/auto_cpufreq_rs/config.toml");
config_paths.push(system_config_path);
for path in config_paths {
if path.exists() {
println!("Attempting to load config from: {}", path.display());
match fs::read_to_string(&path) {
Ok(contents) => {
match toml::from_str::<AppConfigToml>(&contents) {
Ok(toml_app_config) => {
// Convert AppConfigToml to AppConfig
let app_config = AppConfig {
charger: ProfileConfig::from(toml_app_config.charger),
battery: ProfileConfig::from(toml_app_config.battery),
battery_charge_thresholds: toml_app_config.battery_charge_thresholds,
ignored_power_supplies: toml_app_config.ignored_power_supplies,
poll_interval_sec: toml_app_config.poll_interval_sec,
daemon: DaemonConfig {
poll_interval_sec: toml_app_config.daemon.poll_interval_sec,
adaptive_interval: toml_app_config.daemon.adaptive_interval,
min_poll_interval_sec: toml_app_config.daemon.min_poll_interval_sec,
max_poll_interval_sec: toml_app_config.daemon.max_poll_interval_sec,
throttle_on_battery: toml_app_config.daemon.throttle_on_battery,
log_level: toml_app_config.daemon.log_level,
stats_file_path: toml_app_config.daemon.stats_file_path,
},
};
return Ok(app_config);
}
Err(e) => {
eprintln!("Error parsing config file {}: {}", path.display(), e);
}
}
}
Err(e) => {
eprintln!("Error reading config file {}: {}", path.display(), e);
}
}
}
}
println!("No configuration file found or all failed to parse. Using default configuration.");
// Construct default AppConfig by converting default AppConfigToml
let default_toml_config = AppConfigToml::default();
Ok(AppConfig {
charger: ProfileConfig::from(default_toml_config.charger),
battery: ProfileConfig::from(default_toml_config.battery),
battery_charge_thresholds: default_toml_config.battery_charge_thresholds,
ignored_power_supplies: default_toml_config.ignored_power_supplies,
poll_interval_sec: default_toml_config.poll_interval_sec,
daemon: DaemonConfig::default(),
})
}

9
src/config/mod.rs Normal file
View file

@ -0,0 +1,9 @@
pub mod watcher;
// Re-export all configuration types and functions
pub use self::types::*;
pub use self::load::*;
// Internal organization of config submodules
mod types;
mod load;

View file

@ -1,7 +1,6 @@
// Configuration types and structures for superfreq
use crate::core::TurboSetting; use crate::core::TurboSetting;
use serde::Deserialize; use serde::Deserialize;
use std::fs;
use std::path::PathBuf;
// Structs for configuration using serde::Deserialize // Structs for configuration using serde::Deserialize
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
@ -83,82 +82,6 @@ impl std::fmt::Display for ConfigError {
impl std::error::Error for ConfigError {} impl std::error::Error for ConfigError {}
// The primary function to load application configuration.
// It tries user-specific and then system-wide TOML files.
// Falls back to default settings if no file is found or if parsing fails.
pub fn load_config() -> Result<AppConfig, ConfigError> {
let mut config_paths: Vec<PathBuf> = Vec::new();
// User-specific path
if let Some(home_dir) = dirs::home_dir() {
let user_config_path = home_dir.join(".config/auto_cpufreq_rs/config.toml");
config_paths.push(user_config_path);
} else {
eprintln!(
"Warning: Could not determine home directory. User-specific config will not be loaded."
);
}
// System-wide path
let system_config_path = PathBuf::from("/etc/auto_cpufreq_rs/config.toml");
config_paths.push(system_config_path);
for path in config_paths {
if path.exists() {
println!("Attempting to load config from: {}", path.display());
match fs::read_to_string(&path) {
Ok(contents) => {
match toml::from_str::<AppConfigToml>(&contents) {
Ok(toml_app_config) => {
// Convert AppConfigToml to AppConfig
let app_config = AppConfig {
charger: ProfileConfig::from(toml_app_config.charger),
battery: ProfileConfig::from(toml_app_config.battery),
battery_charge_thresholds: toml_app_config
.battery_charge_thresholds,
ignored_power_supplies: toml_app_config.ignored_power_supplies,
poll_interval_sec: toml_app_config.poll_interval_sec,
daemon: DaemonConfig {
poll_interval_sec: toml_app_config.daemon.poll_interval_sec,
adaptive_interval: toml_app_config.daemon.adaptive_interval,
min_poll_interval_sec: toml_app_config
.daemon
.min_poll_interval_sec,
max_poll_interval_sec: toml_app_config
.daemon
.max_poll_interval_sec,
throttle_on_battery: toml_app_config.daemon.throttle_on_battery,
log_level: toml_app_config.daemon.log_level,
stats_file_path: toml_app_config.daemon.stats_file_path,
},
};
return Ok(app_config);
}
Err(e) => {
eprintln!("Error parsing config file {}: {}", path.display(), e);
}
}
}
Err(e) => {
eprintln!("Error reading config file {}: {}", path.display(), e);
}
}
}
}
println!("No configuration file found or all failed to parse. Using default configuration.");
// Construct default AppConfig by converting default AppConfigToml
let default_toml_config = AppConfigToml::default();
Ok(AppConfig {
charger: ProfileConfig::from(default_toml_config.charger),
battery: ProfileConfig::from(default_toml_config.battery),
battery_charge_thresholds: default_toml_config.battery_charge_thresholds,
ignored_power_supplies: default_toml_config.ignored_power_supplies,
poll_interval_sec: default_toml_config.poll_interval_sec,
daemon: DaemonConfig::default(),
})
}
// Intermediate structs for TOML parsing // Intermediate structs for TOML parsing
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
pub struct ProfileConfigToml { pub struct ProfileConfigToml {

View file

@ -3,8 +3,6 @@ use crate::util::error::ControlError;
use core::str; use core::str;
use std::{fs, io, path::Path, string::ToString}; use std::{fs, io, path::Path, string::ToString};
impl std::error::Error for ControlError {}
pub type Result<T, E = ControlError> = std::result::Result<T, E>; pub type Result<T, E = ControlError> = std::result::Result<T, E>;
// Write a value to a sysfs file // Write a value to a sysfs file

View file

@ -1,4 +1,5 @@
use crate::config::{AppConfig, LogLevel}; use crate::config::{AppConfig, LogLevel};
use crate::config::watcher::ConfigWatcher;
use crate::conflict; use crate::conflict;
use crate::core::SystemReport; use crate::core::SystemReport;
use crate::engine; use crate::engine;
@ -10,7 +11,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
/// Run the daemon /// Run the daemon
pub fn run_daemon(config: AppConfig, verbose: bool) -> Result<(), Box<dyn std::error::Error>> { pub fn run_daemon(mut config: AppConfig, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
// Set effective log level based on config and verbose flag // Set effective log level based on config and verbose flag
let effective_log_level = if verbose { let effective_log_level = if verbose {
LogLevel::Debug LogLevel::Debug
@ -63,6 +64,34 @@ pub fn run_daemon(config: AppConfig, verbose: bool) -> Result<(), Box<dyn std::e
); );
} }
// Initialize config file watcher if a path is available
let config_file_path = if let Ok(path) = std::env::var("SUPERFREQ_CONFIG") { Some(path) } else {
let default_paths = [
"/etc/superfreq/config.toml",
"/etc/superfreq.toml",
];
default_paths.iter()
.find(|&path| std::path::Path::new(path).exists())
.map(|path| (*path).to_string())
};
let config_watcher: Option<ConfigWatcher> = match config_file_path {
Some(path) => {
match ConfigWatcher::new(&path) {
Ok(watcher) => {
println!("Watching config file: {path}");
Some(watcher)
},
Err(e) => {
eprintln!("Failed to initialize config file watcher: {e}");
None
}
}
},
None => None,
};
// Variables for adaptive polling // Variables for adaptive polling
let mut current_poll_interval = config.daemon.poll_interval_sec; let mut current_poll_interval = config.daemon.poll_interval_sec;
let mut last_settings_change = Instant::now(); let mut last_settings_change = Instant::now();
@ -72,6 +101,24 @@ pub fn run_daemon(config: AppConfig, verbose: bool) -> Result<(), Box<dyn std::e
while running.load(Ordering::SeqCst) { while running.load(Ordering::SeqCst) {
let start_time = Instant::now(); let start_time = Instant::now();
// Check for configuration changes
if let Some(watcher) = &config_watcher {
if let Some(config_result) = watcher.check_for_changes() {
match config_result {
Ok(new_config) => {
if verbose {
println!("Config file changed, updating configuration");
}
config = new_config;
},
Err(e) => {
eprintln!("Error loading new configuration: {e}");
// Continue with existing config
}
}
}
}
match monitor::collect_system_report(&config) { match monitor::collect_system_report(&config) {
Ok(report) => { Ok(report) => {
log_message( log_message(

View file

@ -1,37 +1,7 @@
use crate::config::{AppConfig, ProfileConfig}; use crate::config::{AppConfig, ProfileConfig};
use crate::core::{OperationalMode, SystemReport, TurboSetting}; use crate::core::{OperationalMode, SystemReport, TurboSetting};
use crate::cpu::{self}; use crate::cpu::{self};
use crate::util::error::ControlError; use crate::util::error::EngineError;
#[derive(Debug)]
pub enum EngineError {
ControlError(ControlError),
ConfigurationError(String),
}
impl From<ControlError> for EngineError {
fn from(err: ControlError) -> Self {
Self::ControlError(err)
}
}
impl std::fmt::Display for EngineError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::ControlError(e) => write!(f, "CPU control error: {e}"),
Self::ConfigurationError(s) => write!(f, "Configuration error: {s}"),
}
}
}
impl std::error::Error for EngineError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::ControlError(e) => Some(e),
Self::ConfigurationError(_) => None,
}
}
}
/// Determines the appropriate CPU profile based on power status or forced mode, /// Determines the appropriate CPU profile based on power status or forced mode,
/// and applies the settings using functions from the `cpu` module. /// and applies the settings using functions from the `cpu` module.
@ -158,6 +128,13 @@ fn manage_auto_turbo(report: &SystemReport, config: &ProfileConfig) -> Result<()
} }
}; };
// Validate the configuration to ensure it's usable
if turbo_settings.load_threshold_high <= turbo_settings.load_threshold_low {
return Err(EngineError::ConfigurationError(
"Invalid turbo auto settings: high threshold must be greater than low threshold".to_string()
));
}
// Decision logic for enabling/disabling turbo // Decision logic for enabling/disabling turbo
let enable_turbo = match (cpu_temp, avg_cpu_usage) { let enable_turbo = match (cpu_temp, avg_cpu_usage) {
// If temperature is too high, disable turbo regardless of load // If temperature is too high, disable turbo regardless of load

View file

@ -1,11 +1,10 @@
use crate::config::AppConfig; use crate::config::AppConfig;
use crate::core::{BatteryInfo, CpuCoreInfo, CpuGlobalInfo, SystemInfo, SystemLoad, SystemReport}; use crate::core::{BatteryInfo, CpuCoreInfo, CpuGlobalInfo, SystemInfo, SystemLoad, SystemReport};
use crate::cpu::{get_logical_core_count, get_platform_profiles}; use crate::cpu::get_logical_core_count;
use crate::util::error::ControlError;
use crate::util::error::SysMonitorError; use crate::util::error::SysMonitorError;
use std::{ use std::{
collections::HashMap, collections::HashMap,
fs, io, fs,
path::{Path, PathBuf}, path::{Path, PathBuf},
str::FromStr, str::FromStr,
thread, thread,
@ -13,8 +12,6 @@ use std::{
time::SystemTime, time::SystemTime,
}; };
impl std::error::Error for SysMonitorError {}
pub type Result<T, E = SysMonitorError> = std::result::Result<T, E>; pub type Result<T, E = SysMonitorError> = std::result::Result<T, E>;
// Read a sysfs file to a string, trimming whitespace // Read a sysfs file to a string, trimming whitespace
@ -417,8 +414,8 @@ pub fn get_cpu_global_info(cpu_cores: &[CpuCoreInfo]) -> CpuGlobalInfo {
None None
}; };
let available_governors = if cpufreq_base.join("scaling_available_governors").exists() { let available_governors = if cpufreq_base_path.join("scaling_available_governors").exists() {
read_sysfs_file_trimmed(cpufreq_base.join("scaling_available_governors")).map_or_else( read_sysfs_file_trimmed(cpufreq_base_path.join("scaling_available_governors")).map_or_else(
|_| vec![], |_| vec![],
|s| s.split_whitespace().map(String::from).collect(), |s| s.split_whitespace().map(String::from).collect(),
) )

View file

@ -39,6 +39,8 @@ impl std::fmt::Display for ControlError {
} }
} }
impl std::error::Error for ControlError {}
#[derive(Debug)] #[derive(Debug)]
pub enum SysMonitorError { pub enum SysMonitorError {
Io(io::Error), Io(io::Error),
@ -67,3 +69,35 @@ impl std::fmt::Display for SysMonitorError {
} }
} }
} }
impl std::error::Error for SysMonitorError {}
#[derive(Debug)]
pub enum EngineError {
ControlError(ControlError),
ConfigurationError(String),
}
impl From<ControlError> for EngineError {
fn from(err: ControlError) -> Self {
Self::ControlError(err)
}
}
impl std::fmt::Display for EngineError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::ControlError(e) => write!(f, "CPU control error: {e}"),
Self::ConfigurationError(s) => write!(f, "Configuration error: {s}"),
}
}
}
impl std::error::Error for EngineError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::ControlError(e) => Some(e),
Self::ConfigurationError(_) => None,
}
}
}