//! System Service Integration (Agent Integrator) //! //! This module translates the mathematical optimums defined by the Analyst //! into actionable, real-world Linux/OS service configurations. //! It generates templates for fan daemons (i8kmon, thinkfan) and handles //! resolution strategies for overlapping daemons. use anyhow::Result; use std::path::Path; use std::fs; use crate::agent_analyst::OptimizationMatrix; pub struct ServiceIntegrator; impl ServiceIntegrator { /// Generates and saves an i8kmon configuration based on the balanced profile. pub fn generate_i8kmon_config(matrix: &OptimizationMatrix, output_path: &Path) -> Result<()> { let profile = &matrix.balanced; let mut conf = String::new(); conf.push_str("# Auto-generated by ember-tune Integrator "); conf.push_str(&format!("# Profile: {} ", profile.name)); for (i, p) in profile.fan_curve.iter().enumerate() { // i8kmon syntax: set config(state) {left_fan right_fan temp_on temp_off} // State 0, 1, 2, 3 correspond to BIOS fan states (off, low, high) let state = match p.pwm_percent { 0..=20 => 0, 21..=50 => 1, 51..=100 => 2, _ => 2, }; let off = if i == 0 { "-".to_string() } else { format!("{}", p.temp_off) }; conf.push_str(&format!("set config({}) {{{} {} {} {}}} ", i, state, state, p.temp_on, off)); } fs::write(output_path, conf)?; Ok(()) } /// Generates a thinkfan configuration. pub fn generate_thinkfan_config(matrix: &OptimizationMatrix, output_path: &Path) -> Result<()> { let profile = &matrix.balanced; let mut conf = String::new(); conf.push_str("# Auto-generated by ember-tune Integrator "); conf.push_str("sensors: - hwmon: /sys/class/hwmon/hwmon0/temp1_input "); conf.push_str("levels: "); for (i, p) in profile.fan_curve.iter().enumerate() { // thinkfan syntax: - [level, temp_down, temp_up] let level = match p.pwm_percent { 0..=20 => 0, 21..=40 => 1, 41..=60 => 3, 61..=80 => 5, _ => 7, }; let down = if i == 0 { 0.0 } else { p.temp_off }; conf.push_str(&format!(" - [{}, {}, {}] ", level, down, p.temp_on)); } fs::write(output_path, conf)?; Ok(()) } /// Generates a resolution checklist/script for daemons. pub fn generate_conflict_resolution_script(output_path: &Path) -> Result<()> { let script = r#"#!/bin/bash # ember-tune Daemon Neutralization Script # 1. Mask power-profiles-daemon (Prevent ACPI overrides) systemctl mask power-profiles-daemon # 2. Filter TLP (Prevent CPU governor fights while keeping PCIe saving) sed -i 's/^CPU_SCALING_GOVERNOR_ON_AC=.*/CPU_SCALING_GOVERNOR_ON_AC=""/' /etc/tlp.conf sed -i 's/^CPU_BOOST_ON_AC=.*/CPU_BOOST_ON_AC=""/' /etc/tlp.conf systemctl restart tlp # 3. Thermald Delegate (We provide the trips, it handles the rest) # (Ensure your custom thermal-conf.xml is in /etc/thermald/) systemctl restart thermald "#; fs::write(output_path, script)?; Ok(()) } /// Generates a thermald configuration XML. pub fn generate_thermald_config(matrix: &OptimizationMatrix, output_path: &Path) -> Result<()> { let profile = &matrix.balanced; let mut xml = String::new(); xml.push_str("\n\n \n ember-tune Balanced\n Generic\n balanced\n \n \n cpu\n \n"); for (i, p) in profile.fan_curve.iter().enumerate() { xml.push_str(&format!(" \n cpu\n {}\n Passive\n {}\n \n", p.temp_on * 1000.0, i)); } xml.push_str(" \n \n \n \n\n"); fs::write(output_path, xml)?; Ok(()) } }