Refactor API processing to apply settings from single thread and queue API calls instead of locking

This commit is contained in:
NGnius (Graham) 2022-11-09 22:09:05 -05:00
parent 357a7cfe37
commit 1610f18278
17 changed files with 822 additions and 452 deletions

33
backend/Cargo.lock generated
View file

@ -38,6 +38,28 @@ dependencies = [
"zeroize",
]
[[package]]
name = "async-recursion"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cda8f4bcc10624c4e85bc66b3f452cca98cfa5ca002dc83a16aad2367641bea"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "async-trait"
version = "0.1.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "autocfg"
version = "1.1.0"
@ -567,12 +589,14 @@ dependencies = [
[[package]]
name = "powertools-rs"
version = "1.0.5"
version = "1.1.0"
dependencies = [
"async-trait",
"log",
"serde",
"serde_json",
"simplelog",
"tokio",
"usdpl-back",
]
@ -1053,12 +1077,15 @@ dependencies = [
[[package]]
name = "usdpl-back"
version = "0.6.0"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbbc0781e83ba990f8239142e33173a2d2548701775f3db66702d1af4fd0319a"
checksum = "4ca96dac4ee471e9534940f99cb36f5212cbfaf4e7779eb3ba970d3c511d9583"
dependencies = [
"async-recursion",
"async-trait",
"bytes",
"hex",
"log",
"obfstr",
"tokio",
"usdpl-core",

View file

@ -1,15 +1,19 @@
[package]
name = "powertools-rs"
version = "1.0.5"
version = "1.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
usdpl-back = { version = "0.6.0", features = ["blocking"]}
usdpl-back = { version = "0.7.0", features = ["blocking"]}
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
# async
tokio = { version = "*", features = ["time"] }
async-trait = { version = "0.1" }
# logging
log = "0.4"
simplelog = "0.12"

View file

@ -0,0 +1,65 @@
//use usdpl_back::core::serdes::Primitive;
use usdpl_back::AsyncCallable;
/*pub struct AsyncIsh<T: Send,
TS: (Fn(super::ApiParameterType) -> Result<T, String>) + Send + Sync,
SG: (Fn(T) -> T) + Send + Sync + 'static,
TG: (Fn(T) -> super::ApiParameterType) + Send + Sync> {
pub trans_setter: TS, // assumed to be pretty fast
pub set_get: SG, // probably has locks (i.e. slow)
pub trans_getter: TG, // assumed to be pretty fast
}
#[async_trait::async_trait]
impl <T: Send,
TS: (Fn(super::ApiParameterType) -> Result<T, String>) + Send + Sync,
SG: (Fn(T) -> T) + Send + Sync + 'static,
TG: (Fn(T) -> super::ApiParameterType) + Send + Sync>
AsyncCallable for AsyncIsh<T, TS, SG, TG> {
async fn call(&self, params: super::ApiParameterType) -> super::ApiParameterType {
let t_to_set = match (self.trans_setter)(params) {
Ok(t) => t,
Err(e) => return vec![e.into()]
};
let t_got = match tokio::task::spawn_blocking(|| (self.set_get)(t_to_set)).await {
Ok(t) => t,
Err(e) => return vec![e.to_string().into()],
};
(self.trans_getter)(t_got)
}
}*/
pub struct AsyncIshGetter<T: Send + 'static,
Gen: (Fn() -> G) + Send + Sync,
G: (Fn() -> T) + Send + Sync + 'static,
TG: (Fn(T) -> super::ApiParameterType) + Send + Sync> {
pub set_get: Gen, // probably has locks (i.e. slow)
pub trans_getter: TG, // assumed to be pretty fast
}
#[async_trait::async_trait]
impl <T: Send + 'static,
Gen: (Fn() -> G) + Send + Sync,
G: (Fn() -> T) + Send + Sync + 'static,
TG: (Fn(T) -> super::ApiParameterType) + Send + Sync>
AsyncCallable for AsyncIshGetter<T, Gen, G, TG> {
async fn call(&self, _params: super::ApiParameterType) -> super::ApiParameterType {
let getter = (self.set_get)();
let t_got = match tokio::task::spawn_blocking(move || getter()).await {
Ok(t) => t,
Err(e) => return vec![e.to_string().into()],
};
(self.trans_getter)(t_got)
}
}
pub struct Blocking<F: (Fn(super::ApiParameterType) -> super::ApiParameterType) + Send + Sync> {
pub func: F,
}
#[async_trait::async_trait]
impl <F: (Fn(super::ApiParameterType) -> super::ApiParameterType) + Send + Sync> AsyncCallable for Blocking<F> {
async fn call(&self, params: super::ApiParameterType) -> super::ApiParameterType {
(self.func)(params)
}
}

View file

@ -1,8 +1,8 @@
use std::sync::{mpsc::Sender, Arc, Mutex};
use std::sync::mpsc::{Sender, self};
use std::sync::Mutex;
use usdpl_back::core::serdes::Primitive;
use crate::settings::{Battery, OnSet};
use crate::utility::{unwrap_lock, unwrap_maybe_fatal};
use super::handler::{ApiMessage, BatteryMessage};
/// Current current (ha!) web method
pub fn current_now(_: super::ApiParameterType) -> super::ApiParameterType {
@ -26,22 +26,18 @@ pub fn charge_design(_: super::ApiParameterType) -> super::ApiParameterType {
/// Generate set battery charge rate web method
pub fn set_charge_rate(
settings: Arc<Mutex<Battery>>,
saver: Sender<()>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let saver = Mutex::new(saver); // Sender is not Sync; this is required for safety
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move |rate: f64|
sender.lock()
.unwrap()
.send(ApiMessage::Battery(BatteryMessage::SetChargeRate(Some(rate as u64))))
.expect("set_charge_rate send failed");
move |params_in: super::ApiParameterType| {
if let Some(Primitive::F64(new_val)) = params_in.get(0) {
let mut settings_lock = unwrap_lock(settings.lock(), "battery");
settings_lock.charge_rate = Some(*new_val as _);
unwrap_maybe_fatal(
unwrap_lock(saver.lock(), "save channel").send(()),
"Failed to send on save channel",
);
super::utility::map_empty_result(
settings_lock.on_set(),
settings_lock.charge_rate.unwrap(),
)
if let Some(&Primitive::F64(new_val)) = params_in.get(0) {
setter(new_val);
vec![(new_val).into()]
} else {
vec!["set_charge_rate missing parameter".into()]
}
@ -50,30 +46,28 @@ pub fn set_charge_rate(
/// Generate get battery charge rate web method
pub fn get_charge_rate(
settings: Arc<Mutex<Battery>>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let getter = move || {
let (tx, rx) = mpsc::channel();
let callback = move |rate: Option<u64>| tx.send(rate).expect("get_charge_rate callback send failed");
sender.lock().unwrap().send(ApiMessage::Battery(BatteryMessage::GetChargeRate(Box::new(callback)))).expect("get_charge_rate send failed");
rx.recv().expect("get_charge_rate callback recv failed")
};
move |_: super::ApiParameterType| {
let settings_lock = unwrap_lock(settings.lock(), "battery");
vec![settings_lock
.charge_rate
.map(|x| x.into())
.unwrap_or(Primitive::Empty)]
vec![getter().map(|x| x.into()).unwrap_or(Primitive::Empty)]
}
}
/// Generate unset battery charge rate web method
pub fn unset_charge_rate(
settings: Arc<Mutex<Battery>>,
saver: Sender<()>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let saver = Mutex::new(saver); // Sender is not Sync; this is required for safety
move |_: super::ApiParameterType| {
let mut settings_lock = unwrap_lock(settings.lock(), "battery");
settings_lock.charge_rate = None;
unwrap_maybe_fatal(
unwrap_lock(saver.lock(), "save channel").send(()),
"Failed to send on save channel",
);
super::utility::map_empty_result(settings_lock.on_set(), true)
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move || sender.lock().unwrap().send(ApiMessage::Battery(BatteryMessage::SetChargeRate(None))).expect("unset_charge_rate send failed");
move |_params_in: super::ApiParameterType| {
setter();
vec![true.into()]
}
}

View file

@ -1,8 +1,11 @@
use std::sync::{mpsc::Sender, Arc, Mutex};
use std::sync::mpsc::{Sender, self};
use std::sync::{Arc, Mutex};
use usdpl_back::core::serdes::Primitive;
use usdpl_back::AsyncCallable;
use crate::settings::{Cpu, OnSet, SettingError, SettingVariant, MinMax};
use crate::utility::{unwrap_lock, unwrap_maybe_fatal};
use crate::settings::{Cpu, SettingError, SettingVariant, MinMax};
//use crate::utility::{unwrap_lock, unwrap_maybe_fatal};
use super::handler::{ApiMessage, CpuMessage};
/// Available CPUs web method
pub fn max_cpus(_: super::ApiParameterType) -> super::ApiParameterType {
@ -20,29 +23,21 @@ pub fn max_cpus(_: super::ApiParameterType) -> super::ApiParameterType {
/// Generate set CPU online web method
pub fn set_cpu_online(
settings: Arc<Mutex<Vec<Cpu>>>,
saver: Sender<()>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let saver = Mutex::new(saver); // Sender is not Sync; this is required for safety
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move |index: usize, value: bool|
sender.lock()
.unwrap()
.send(ApiMessage::Cpu(CpuMessage::SetCpuOnline(index, value))).expect("set_cpu_online send failed");
move |params_in: super::ApiParameterType| {
if let Some(Primitive::F64(index)) = params_in.get(0) {
let mut settings_lock = unwrap_lock(settings.lock(), "cpu");
if let Some(cpu) = settings_lock.get_mut(*index as usize) {
if let Some(Primitive::Bool(online)) = params_in.get(1) {
cpu.online = *online;
unwrap_maybe_fatal(
unwrap_lock(saver.lock(), "save channel").send(()),
"Failed to send on save channel",
);
super::utility::map_empty_result(
cpu.on_set(),
cpu.online,
)
} else {
vec!["set_cpu_online missing parameter 1".into()]
}
if let Some(&Primitive::F64(index)) = params_in.get(0) {
//let mut settings_lock = unwrap_lock(settings.lock(), "cpu");
if let Some(&Primitive::Bool(online)) = params_in.get(1) {
setter(index as usize, online);
vec![online.into()]
} else {
vec!["set_cpu_online cpu index out of bounds".into()]
vec!["set_cpu_online missing parameter 1".into()]
}
} else {
vec!["set_cpu_online missing parameter 0".into()]
@ -51,81 +46,94 @@ pub fn set_cpu_online(
}
pub fn set_cpus_online(
settings: Arc<Mutex<Vec<Cpu>>>,
saver: Sender<()>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let saver = Mutex::new(saver); // Sender is not Sync; this is required for safety
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move |values: Vec<bool>|
sender.lock()
.unwrap()
.send(ApiMessage::Cpu(CpuMessage::SetCpusOnline(values))).expect("set_cpus_online send failed");
move |params_in: super::ApiParameterType| {
let mut result = Vec::with_capacity(params_in.len());
let mut settings_lock = unwrap_lock(settings.lock(), "cpu");
let mut values = Vec::with_capacity(params_in.len());
for i in 0..params_in.len() {
if let Primitive::Bool(online) = params_in[i] {
if let Some(cpu) = settings_lock.get_mut(i) {
cpu.online = online;
match cpu.on_set() {
Ok(_) => result.push(cpu.online.into()),
Err(e) => result.push(e.msg.into())
}
}
values.push(online);
result.push(online.into());
} else {
values.push(true);
result.push(format!("Invalid parameter {}", i).into())
}
}
unwrap_maybe_fatal(
unwrap_lock(saver.lock(), "save channel").send(()),
"Failed to send on save channel",
);
setter(values);
result
}
}
pub fn get_cpus_online(
settings: Arc<Mutex<Vec<Cpu>>>,
/*pub fn get_cpus_online(
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let getter = move || {
let (tx, rx) = mpsc::channel();
let callback = move |values: Vec<bool>| tx.send(values).expect("get_cpus_online callback send failed");
sender.lock().unwrap().send(ApiMessage::Cpu(CpuMessage::GetCpusOnline(Box::new(callback)))).expect("get_cpus_online send failed");
rx.recv().expect("get_cpus_online callback recv failed")
};
move |_: super::ApiParameterType| {
let settings_lock = unwrap_lock(settings.lock(), "cpu");
let mut output = Vec::with_capacity(settings_lock.len());
for cpu in settings_lock.as_slice() {
output.push(cpu.online.into());
let result = getter();
let mut output = Vec::with_capacity(result.len());
for &status in result.as_slice() {
output.push(status.into());
}
output
}
}*/
pub fn get_cpus_online(
sender: Sender<ApiMessage>,
) -> impl AsyncCallable {
let sender = Arc::new(Mutex::new(sender)); // Sender is not Sync; this is required for safety
let getter = move || {
let sender2 = sender.clone();
move || {
let (tx, rx) = mpsc::channel();
let callback = move |values: Vec<bool>| tx.send(values).expect("get_cpus_online callback send failed");
sender2.lock().unwrap().send(ApiMessage::Cpu(CpuMessage::GetCpusOnline(Box::new(callback)))).expect("get_cpus_online send failed");
rx.recv().expect("get_cpus_online callback recv failed")
}
};
super::async_utils::AsyncIshGetter {
set_get: getter,
trans_getter: |result| {
let mut output = Vec::with_capacity(result.len());
for &status in result.as_slice() {
output.push(status.into());
}
output
}
}
}
pub fn set_clock_limits(
settings: Arc<Mutex<Vec<Cpu>>>,
saver: Sender<()>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let saver = Mutex::new(saver); // Sender is not Sync; this is required for safety
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move |index: usize, value: MinMax<u64>|
sender.lock()
.unwrap()
.send(ApiMessage::Cpu(CpuMessage::SetClockLimits(index, Some(value)))).expect("set_clock_limits send failed");
move |params_in: super::ApiParameterType| {
if let Some(Primitive::F64(index)) = params_in.get(0) {
let mut settings_lock = unwrap_lock(settings.lock(), "cpu");
if let Some(cpu) = settings_lock.get_mut(*index as usize) {
if let Some(Primitive::F64(min)) = params_in.get(1) {
if let Some(Primitive::F64(max)) = params_in.get(2) {
cpu.clock_limits = Some(MinMax {
min: *min as _,
max: *max as _,
});
unwrap_maybe_fatal(
unwrap_lock(saver.lock(), "save channel").send(()),
"Failed to send on save channel",
);
match cpu.on_set() {
Ok(_) => vec![
cpu.clock_limits.as_ref().unwrap().min.into(),
cpu.clock_limits.as_ref().unwrap().max.into(),
],
Err(e) => vec![e.msg.into()]
}
} else {
vec!["set_clock_limits missing parameter 2".into()]
}
if let Some(&Primitive::F64(index)) = params_in.get(0) {
if let Some(&Primitive::F64(min)) = params_in.get(1) {
if let Some(&Primitive::F64(max)) = params_in.get(2) {
setter(index as usize, MinMax {min: min as u64, max: max as u64});
vec![min.into(), max.into()]
} else {
vec!["set_clock_limits missing parameter 1".into()]
vec!["set_clock_limits missing parameter 2".into()]
}
} else {
vec!["set_clock_limits cpu index out of bounds".into()]
vec!["set_clock_limits missing parameter 1".into()]
}
} else {
vec!["set_clock_limits missing parameter 0".into()]
@ -134,19 +142,21 @@ pub fn set_clock_limits(
}
pub fn get_clock_limits(
settings: Arc<Mutex<Vec<Cpu>>>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let getter = move |index: usize| {
let (tx, rx) = mpsc::channel();
let callback = move |values: Option<MinMax<u64>>| tx.send(values).expect("get_clock_limits callback send failed");
sender.lock().unwrap().send(ApiMessage::Cpu(CpuMessage::GetClockLimits(index, Box::new(callback)))).expect("get_clock_limits send failed");
rx.recv().expect("get_clock_limits callback recv failed")
};
move |params_in: super::ApiParameterType| {
if let Some(Primitive::F64(index)) = params_in.get(0) {
let mut settings_lock = unwrap_lock(settings.lock(), "cpu");
if let Some(cpu) = settings_lock.get_mut(*index as usize) {
if let Some(min_max) = &cpu.clock_limits {
vec![min_max.min.into(), min_max.max.into()]
} else {
vec![Primitive::Empty, Primitive::Empty]
}
if let Some(&Primitive::F64(index)) = params_in.get(0) {
if let Some(min_max) = getter(index as usize) {
vec![min_max.min.into(), min_max.max.into()]
} else {
vec!["get_clock_limits cpu index out of bounds".into()]
vec![Primitive::Empty, Primitive::Empty]
}
} else {
vec!["get_clock_limits missing parameter 0".into()]
@ -155,23 +165,17 @@ pub fn get_clock_limits(
}
pub fn unset_clock_limits(
settings: Arc<Mutex<Vec<Cpu>>>,
saver: Sender<()>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let saver = Mutex::new(saver); // Sender is not Sync; this is required for safety
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move |index: usize|
sender.lock()
.unwrap()
.send(ApiMessage::Cpu(CpuMessage::SetClockLimits(index, None))).expect("unset_clock_limits send failed");
move |params_in: super::ApiParameterType| {
if let Some(Primitive::F64(index)) = params_in.get(0) {
let mut settings_lock = unwrap_lock(settings.lock(), "cpu");
if let Some(cpu) = settings_lock.get_mut(*index as usize) {
cpu.clock_limits = None;
unwrap_maybe_fatal(
unwrap_lock(saver.lock(), "save channel").send(()),
"Failed to send on save channel",
);
super::utility::map_empty_result(cpu.on_set(), true)
} else {
vec!["get_clock_limits cpu index out of bounds".into()]
}
if let Some(&Primitive::F64(index)) = params_in.get(0) {
setter(index as usize);
vec![true.into()]
} else {
vec!["get_clock_limits missing parameter 0".into()]
}
@ -179,29 +183,20 @@ pub fn unset_clock_limits(
}
pub fn set_cpu_governor(
settings: Arc<Mutex<Vec<Cpu>>>,
saver: Sender<()>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let saver = Mutex::new(saver); // Sender is not Sync; this is required for safety
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move |index: usize, governor: String|
sender.lock()
.unwrap()
.send(ApiMessage::Cpu(CpuMessage::SetCpuGovernor(index, governor))).expect("set_cpu_governor send failed");
move |params_in: super::ApiParameterType| {
if let Some(Primitive::F64(index)) = params_in.get(0) {
let mut settings_lock = unwrap_lock(settings.lock(), "cpu");
if let Some(cpu) = settings_lock.get_mut(*index as usize) {
if let Some(Primitive::String(governor)) = params_in.get(1) {
cpu.governor = governor.to_owned();
unwrap_maybe_fatal(
unwrap_lock(saver.lock(), "save channel").send(()),
"Failed to send on save channel",
);
super::utility::map_empty_result(
cpu.on_set(),
&cpu.governor as &str,
)
} else {
vec!["set_cpu_governor missing parameter 1".into()]
}
if let Some(&Primitive::F64(index)) = params_in.get(0) {
if let Some(Primitive::String(governor)) = params_in.get(1) {
setter(index as usize, governor.to_owned());
vec![(governor as &str).into()]
} else {
vec!["set_cpu_governor cpu index out of bounds".into()]
vec!["set_cpu_governor missing parameter 1".into()]
}
} else {
vec!["set_cpu_governor missing parameter 0".into()]
@ -209,14 +204,46 @@ pub fn set_cpu_governor(
}
}
pub fn get_cpu_governors(
settings: Arc<Mutex<Vec<Cpu>>>,
pub fn set_cpus_governors(
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move |governors: Vec<String>|
sender.lock()
.unwrap()
.send(ApiMessage::Cpu(CpuMessage::SetCpusGovernor(governors))).expect("set_cpus_governor send failed");
move |params_in: super::ApiParameterType| {
let mut result = Vec::with_capacity(params_in.len());
let mut values = Vec::with_capacity(params_in.len());
for i in 0..params_in.len() {
if let Primitive::String(gov) = &params_in[i] {
values.push(gov.to_owned());
result.push((gov as &str).into());
} else {
//values.push(true);
result.push(format!("Invalid parameter {}", i).into())
}
}
setter(values);
result
}
}
pub fn get_cpu_governors(
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let getter = move || {
let (tx, rx) = mpsc::channel();
let callback = move |values: Vec<String>| tx.send(values).expect("get_cpu_governors callback send failed");
sender.lock().unwrap().send(ApiMessage::Cpu(CpuMessage::GetCpusGovernor(Box::new(callback)))).expect("get_cpu_governors send failed");
rx.recv().expect("get_cpu_governors callback recv failed")
};
move |_: super::ApiParameterType| {
let settings_lock = unwrap_lock(settings.lock(), "cpu");
let mut output = Vec::with_capacity(settings_lock.len());
for cpu in settings_lock.as_slice() {
output.push(cpu.governor.clone().into());
let result = getter();
let mut output = Vec::with_capacity(result.len());
for cpu in result.as_slice() {
output.push(cpu.clone().into());
}
output
}

View file

@ -1,29 +1,25 @@
use std::sync::{mpsc::Sender, Arc, Mutex};
use std::sync::mpsc::{Sender, self};
use std::sync::{Arc, Mutex};
use usdpl_back::core::serdes::Primitive;
use usdpl_back::AsyncCallable;
use crate::settings::{General, Settings, OnSet};
use crate::utility::{unwrap_lock, unwrap_maybe_fatal};
//use crate::utility::{unwrap_lock, unwrap_maybe_fatal};
use super::handler::{ApiMessage, GeneralMessage};
/// Generate set persistent web method
pub fn set_persistent(
settings: Arc<Mutex<General>>,
saver: Sender<()>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let saver = Mutex::new(saver); // Sender is not Sync; this is required for safety
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move |pers: bool|
sender.lock()
.unwrap()
.send(ApiMessage::General(GeneralMessage::SetPersistent(pers))).expect("set_persistent send failed");
move |params_in: super::ApiParameterType| {
if let Some(Primitive::Bool(new_val)) = params_in.get(0) {
let mut settings_lock = unwrap_lock(settings.lock(), "general");
settings_lock.persistent = *new_val;
unwrap_maybe_fatal(
unwrap_lock(saver.lock(), "save channel").send(()),
"Failed to send on save channel",
);
let result = super::utility::map_empty_result(
settings_lock.on_set(),
settings_lock.persistent,
);
log::debug!("Persistent is now {}", settings_lock.persistent);
result
if let Some(&Primitive::Bool(new_val)) = params_in.get(0) {
setter(new_val);
//log::debug!("Persistent is now {}", settings_lock.persistent);
vec![new_val.into()]
} else {
vec!["set_persistent missing parameter".into()]
}
@ -32,30 +28,34 @@ pub fn set_persistent(
/// Generate get persistent save mode web method
pub fn get_persistent(
settings: Arc<Mutex<General>>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let getter = move || {
let (tx, rx) = mpsc::channel();
let callback = move |value: bool| tx.send(value).expect("get_persistent callback send failed");
sender.lock().unwrap().send(ApiMessage::General(GeneralMessage::GetPersistent(Box::new(callback)))).expect("get_persistent send failed");
rx.recv().expect("get_persistent callback recv failed")
};
move |_: super::ApiParameterType| {
let settings_lock = unwrap_lock(settings.lock(), "general");
vec![settings_lock
.persistent.into()]
vec![getter().into()]
}
}
/// Generate load app settings from file web method
pub fn load_settings(
settings: Settings,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move |path: String, name: String|
sender.lock()
.unwrap()
.send(ApiMessage::LoadSettings(path, name)).expect("load_settings send failed");
move |params_in: super::ApiParameterType| {
if let Some(Primitive::String(path)) = params_in.get(0) {
if let Some(Primitive::String(name)) = params_in.get(1) {
match settings.load_file(path.into(), name.to_owned(), false) {
Err(e) => vec![e.msg.into()],
Ok(success) =>
super::utility::map_empty_result(
settings.clone().on_set(),
success
)
}
setter(path.to_owned(), name.to_owned());
vec![true.into()]
} else {
vec!["load_settings missing name parameter".into()]
}
@ -68,10 +68,17 @@ pub fn load_settings(
/// Generate load default settings from file web method
pub fn load_default_settings(
settings: Settings,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move ||
sender.lock()
.unwrap()
.send(ApiMessage::LoadMainSettings).expect("load_default_settings send failed");
move |_: super::ApiParameterType| {
match settings.load_file(
setter();
vec![true.into()]
/*match settings.load_file(
crate::consts::DEFAULT_SETTINGS_FILE.into(),
crate::consts::DEFAULT_SETTINGS_NAME.to_owned(),
true
@ -81,32 +88,76 @@ pub fn load_default_settings(
settings.clone().on_set(),
success
)
}
}*/
}
}
/// Generate load system default settings from file web method
pub fn load_system_settings(
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move ||
sender.lock()
.unwrap()
.send(ApiMessage::LoadSystemSettings).expect("load_default_settings send failed");
move |_: super::ApiParameterType| {
setter();
vec![true.into()]
/*match settings.load_file(
crate::consts::DEFAULT_SETTINGS_FILE.into(),
crate::consts::DEFAULT_SETTINGS_NAME.to_owned(),
true
) {
Err(e) => vec![e.msg.into()],
Ok(success) => super::utility::map_empty_result(
settings.clone().on_set(),
success
)
}*/
}
}
/// Generate get current settings name
pub fn get_name(
settings: Arc<Mutex<General>>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
move |_: super::ApiParameterType| {
let settings_lock = unwrap_lock(settings.lock(), "general");
vec![settings_lock
.name
.clone()
.into()]
sender: Sender<ApiMessage>,
) -> impl AsyncCallable {
let sender = Arc::new(Mutex::new(sender)); // Sender is not Sync; this is required for safety
let getter = move || {
let sender2 = sender.clone();
move || {
let (tx, rx) = mpsc::channel();
let callback = move |name: String| tx.send(name).expect("get_name callback send failed");
sender2.lock().unwrap().send(ApiMessage::General(GeneralMessage::GetCurrentProfileName(Box::new(callback)))).expect("get_name send failed");
rx.recv().expect("get_name callback recv failed")
}
};
super::async_utils::AsyncIshGetter {
set_get: getter,
trans_getter: |result| {
vec![result.into()]
}
}
}
/// Generate wait for all locks to be available web method
pub fn lock_unlock_all(
settings: Settings,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
move |_: super::ApiParameterType| {
let _lock = unwrap_lock(settings.general.lock(), "general");
let _lock = unwrap_lock(settings.cpus.lock(), "cpus");
let _lock = unwrap_lock(settings.gpu.lock(), "gpu");
let _lock = unwrap_lock(settings.battery.lock(), "battery");
vec![true.into()]
sender: Sender<ApiMessage>,
) -> impl AsyncCallable {
let sender = Arc::new(Mutex::new(sender)); // Sender is not Sync; this is required for safety
let getter = move || {
let sender2 = sender.clone();
move || {
let (tx, rx) = mpsc::channel();
let callback = move |x| tx.send(x).expect("lock_unlock_all callback send failed");
sender2.lock().unwrap().send(ApiMessage::WaitForEmptyQueue(Box::new(callback))).expect("lock_unlock_all send failed");
rx.recv().expect("lock_unlock_all callback recv failed")
}
};
super::async_utils::AsyncIshGetter {
set_get: getter,
trans_getter: |_| {
vec![true.into()]
}
}
}

View file

@ -1,31 +1,25 @@
use std::sync::{mpsc::Sender, Arc, Mutex};
use std::sync::mpsc::{Sender, self};
use std::sync::{Mutex, Arc};
use usdpl_back::core::serdes::Primitive;
use usdpl_back::AsyncCallable;
use crate::settings::{Gpu, OnSet, MinMax};
use crate::utility::{unwrap_lock, unwrap_maybe_fatal};
use crate::settings::MinMax;
//use crate::utility::{unwrap_lock, unwrap_maybe_fatal};
use super::handler::{ApiMessage, GpuMessage};
pub fn set_ppt(
settings: Arc<Mutex<Gpu>>,
saver: Sender<()>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let saver = Mutex::new(saver); // Sender is not Sync; this is required for safety
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move |fast: u64, slow: u64|
sender.lock()
.unwrap()
.send(ApiMessage::Gpu(GpuMessage::SetPpt(Some(fast), Some(slow)))).expect("set_ppt send failed");
move |params_in: super::ApiParameterType| {
if let Some(Primitive::F64(fast_ppt)) = params_in.get(0) {
if let Some(Primitive::F64(slow_ppt)) = params_in.get(1) {
let mut settings_lock = unwrap_lock(settings.lock(), "gpu");
settings_lock.fast_ppt = Some(*fast_ppt as u64);
settings_lock.slow_ppt = Some(*slow_ppt as u64);
unwrap_maybe_fatal(
unwrap_lock(saver.lock(), "save channel").send(()),
"Failed to send on save channel",
);
match settings_lock.on_set() {
Ok(_) => vec![
settings_lock.fast_ppt.unwrap().into(),
settings_lock.slow_ppt.unwrap().into()
],
Err(e) => vec![e.msg.into()],
}
if let Some(&Primitive::F64(fast_ppt)) = params_in.get(0) {
if let Some(&Primitive::F64(slow_ppt)) = params_in.get(1) {
setter(fast_ppt as u64, slow_ppt as u64);
vec![(fast_ppt as u64).into(), (slow_ppt as u64).into()]
} else {
vec!["set_ppt missing parameter 1".into()]
}
@ -36,60 +30,59 @@ pub fn set_ppt(
}
pub fn get_ppt(
settings: Arc<Mutex<Gpu>>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
move |_: super::ApiParameterType| {
let settings_lock = unwrap_lock(settings.lock(), "gpu");
let fast_ppt = settings_lock.fast_ppt.map(|x| x.into()).unwrap_or(Primitive::Empty);
let slow_ppt = settings_lock.slow_ppt.map(|x| x.into()).unwrap_or(Primitive::Empty);
vec![fast_ppt, slow_ppt]
sender: Sender<ApiMessage>,
) -> impl AsyncCallable {
let sender = Arc::new(Mutex::new(sender)); // Sender is not Sync; this is required for safety
let getter = move || {
let sender2 = sender.clone();
move || {
let (tx, rx) = mpsc::channel();
let callback = move |ppt: (Option<u64>, Option<u64>)| tx.send(ppt).expect("get_ppt callback send failed");
sender2.lock().unwrap().send(ApiMessage::Gpu(GpuMessage::GetPpt(Box::new(callback)))).expect("get_ppt send failed");
rx.recv().expect("get_ppt callback recv failed")
}
};
super::async_utils::AsyncIshGetter {
set_get: getter,
trans_getter: |(fast, slow): (Option<u64>, Option<u64>)| {
vec![
fast.map(|x| x.into()).unwrap_or(Primitive::Empty),
slow.map(|x| x.into()).unwrap_or(Primitive::Empty),
]
}
}
}
pub fn unset_ppt(
settings: Arc<Mutex<Gpu>>,
saver: Sender<()>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let saver = Mutex::new(saver); // Sender is not Sync; this is required for safety
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move ||
sender.lock()
.unwrap()
.send(ApiMessage::Gpu(GpuMessage::SetPpt(None, None))).expect("set_ppt send failed");
move |_: super::ApiParameterType| {
let mut settings_lock = unwrap_lock(settings.lock(), "gpu");
settings_lock.fast_ppt = None;
settings_lock.slow_ppt = None;
unwrap_maybe_fatal(
unwrap_lock(saver.lock(), "save channel").send(()),
"Failed to send on save channel",
);
super::utility::map_empty_result(
settings_lock.on_set(),
Primitive::Empty,
)
setter();
vec![true.into()]
}
}
pub fn set_clock_limits(
settings: Arc<Mutex<Gpu>>,
saver: Sender<()>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let saver = Mutex::new(saver); // Sender is not Sync; this is required for safety
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move |value: MinMax<u64>|
sender.lock()
.unwrap()
.send(ApiMessage::Gpu(GpuMessage::SetClockLimits(Some(value)))).expect("set_clock_limits send failed");
move |params_in: super::ApiParameterType| {
if let Some(Primitive::F64(min)) = params_in.get(0) {
if let Some(Primitive::F64(max)) = params_in.get(1) {
let mut settings_lock = unwrap_lock(settings.lock(), "gpu");
settings_lock.clock_limits = Some(MinMax {
min: *min as _,
max: *max as _,
if let Some(&Primitive::F64(min)) = params_in.get(0) {
if let Some(&Primitive::F64(max)) = params_in.get(1) {
setter(MinMax {
min: min as _,
max: max as _,
});
unwrap_maybe_fatal(
unwrap_lock(saver.lock(), "save channel").send(()),
"Failed to send on save channel",
);
match settings_lock.on_set() {
Ok(_) => vec![
settings_lock.clock_limits.as_ref().unwrap().min.into(),
settings_lock.clock_limits.as_ref().unwrap().max.into(),
],
Err(e) => vec![e.msg.into()]
}
vec![(min as u64).into(), (max as u64).into()]
} else {
vec!["set_clock_limits missing parameter 1".into()]
}
@ -100,51 +93,54 @@ pub fn set_clock_limits(
}
pub fn get_clock_limits(
settings: Arc<Mutex<Gpu>>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
move |_: super::ApiParameterType| {
let settings_lock = unwrap_lock(settings.lock(), "gpu");
if let Some(min_max) = &settings_lock.clock_limits {
vec![min_max.min.into(), min_max.max.into()]
} else {
vec![Primitive::Empty, Primitive::Empty]
sender: Sender<ApiMessage>,
) -> impl AsyncCallable {
let sender = Arc::new(Mutex::new(sender)); // Sender is not Sync; this is required for safety
let getter = move|| {
let sender2 = sender.clone();
move || {
let (tx, rx) = mpsc::channel();
let callback = move |clocks: Option<MinMax<u64>>| tx.send(clocks).expect("get_clock_limits callback send failed");
sender2.lock().unwrap().send(ApiMessage::Gpu(GpuMessage::GetClockLimits(Box::new(callback)))).expect("get_clock_limits send failed");
rx.recv().expect("get_clock_limits callback recv failed")
}
};
super::async_utils::AsyncIshGetter {
set_get: getter,
trans_getter: |clocks: Option<MinMax<u64>>| {
clocks.map(|x| vec![
x.min.into(), x.max.into()
]).unwrap_or_else(|| vec![Primitive::Empty, Primitive::Empty])
}
}
}
pub fn unset_clock_limits(
settings: Arc<Mutex<Gpu>>,
saver: Sender<()>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let saver = Mutex::new(saver); // Sender is not Sync; this is required for safety
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move ||
sender.lock()
.unwrap()
.send(ApiMessage::Gpu(GpuMessage::SetClockLimits(None))).expect("unset_clock_limits send failed");
move |_: super::ApiParameterType| {
let mut settings_lock = unwrap_lock(settings.lock(), "gpu");
settings_lock.clock_limits = None;
unwrap_maybe_fatal(
unwrap_lock(saver.lock(), "save channel").send(()),
"Failed to send on save channel",
);
super::utility::map_empty_result(settings_lock.on_set(), true)
setter();
vec![true.into()]
}
}
pub fn set_slow_memory(
settings: Arc<Mutex<Gpu>>,
saver: Sender<()>,
sender: Sender<ApiMessage>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
let saver = Mutex::new(saver); // Sender is not Sync; this is required for safety
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
let setter = move |value: bool|
sender.lock()
.unwrap()
.send(ApiMessage::Gpu(GpuMessage::SetSlowMemory(value))).expect("unset_clock_limits send failed");
move |params_in: super::ApiParameterType| {
if let Some(Primitive::Bool(memory_is_slow)) = params_in.get(0) {
let mut settings_lock = unwrap_lock(settings.lock(), "gpu");
settings_lock.slow_memory = *memory_is_slow;
unwrap_maybe_fatal(
unwrap_lock(saver.lock(), "save channel").send(()),
"Failed to send on save channel",
);
super::utility::map_empty_result(
settings_lock.on_set(),
settings_lock.slow_memory,
)
if let Some(&Primitive::Bool(memory_is_slow)) = params_in.get(0) {
setter(memory_is_slow);
vec![memory_is_slow.into()]
} else {
vec!["set_slow_memory missing parameter 0".into()]
}
@ -152,10 +148,22 @@ pub fn set_slow_memory(
}
pub fn get_slow_memory(
settings: Arc<Mutex<Gpu>>,
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
move |_: super::ApiParameterType| {
let settings_lock = unwrap_lock(settings.lock(), "cpu");
vec![settings_lock.slow_memory.into()]
sender: Sender<ApiMessage>,
) -> impl AsyncCallable {
let sender = Arc::new(Mutex::new(sender)); // Sender is not Sync; this is required for safety
let getter = move || {
let sender2 = sender.clone();
move || {
let (tx, rx) = mpsc::channel();
let callback = move |value: bool| tx.send(value).expect("get_slow_memory callback send failed");
sender2.lock().unwrap().send(ApiMessage::Gpu(GpuMessage::GetSlowMemory(Box::new(callback)))).expect("get_slow_memory send failed");
rx.recv().expect("get_slow_memory callback recv failed")
}
};
super::async_utils::AsyncIshGetter {
set_get: getter,
trans_getter: |value: bool| {
vec![value.into()]
}
}
}

199
backend/src/api/handler.rs Normal file
View file

@ -0,0 +1,199 @@
use std::sync::mpsc::{self, Receiver, Sender};
use crate::settings::{Settings, Cpu, Gpu, Battery, General, OnSet, OnResume, MinMax};
use crate::persist::SettingsJson;
use crate::utility::unwrap_maybe_fatal;
type Callback<T> = Box<dyn FnOnce(T) + Send>;
pub enum ApiMessage {
Battery(BatteryMessage),
Cpu(CpuMessage),
Gpu(GpuMessage),
General(GeneralMessage),
OnResume,
WaitForEmptyQueue(Callback<()>),
LoadSettings(String, String), // (path, name)
LoadMainSettings,
LoadSystemSettings,
}
pub enum BatteryMessage {
SetChargeRate(Option<u64>),
GetChargeRate(Callback<Option<u64>>),
}
impl BatteryMessage {
fn process(self, settings: &mut Battery) {
match self {
Self::SetChargeRate(rate) => settings.charge_rate = rate,
Self::GetChargeRate(cb) => cb(settings.charge_rate),
}
}
}
pub enum CpuMessage {
SetCpuOnline(usize, bool),
SetCpusOnline(Vec<bool>),
GetCpusOnline(Callback<Vec<bool>>),
SetClockLimits(usize, Option<MinMax<u64>>),
GetClockLimits(usize, Callback<Option<MinMax<u64>>>),
SetCpuGovernor(usize, String),
SetCpusGovernor(Vec<String>),
GetCpusGovernor(Callback<Vec<String>>),
}
impl CpuMessage {
fn process(self, settings: &mut Vec<Cpu>) {
match self {
Self::SetCpuOnline(index, status) => {settings.get_mut(index).map(|c| c.online = status);},
Self::SetCpusOnline(cpus) => {
for i in 0..cpus.len() {
settings.get_mut(i).map(|c| c.online = cpus[i]);
}
},
Self::GetCpusOnline(cb) => {
let mut result = Vec::with_capacity(settings.len());
for cpu in settings {
result.push(cpu.online);
}
cb(result);
},
Self::SetClockLimits(index, clocks) => {settings.get_mut(index).map(|c| c.clock_limits = clocks);},
Self::GetClockLimits(index, cb) => {settings.get(index).map(|c| cb(c.clock_limits.clone()));},
Self::SetCpuGovernor(index, gov) => {settings.get_mut(index).map(|c| c.governor = gov);},
Self::SetCpusGovernor(govs) => {
for i in 0..govs.len() {
settings.get_mut(i).map(|c| c.governor = govs[i].clone());
}
},
Self::GetCpusGovernor(cb) => {
let mut result = Vec::with_capacity(settings.len());
for cpu in settings {
result.push(cpu.governor.clone());
}
cb(result);
}
}
}
}
pub enum GpuMessage {
SetPpt(Option<u64>, Option<u64>), // (fast, slow)
GetPpt(Callback<(Option<u64>, Option<u64>)>),
SetClockLimits(Option<MinMax<u64>>),
GetClockLimits(Callback<Option<MinMax<u64>>>),
SetSlowMemory(bool),
GetSlowMemory(Callback<bool>),
}
impl GpuMessage {
fn process(self, settings: &mut Gpu) {
match self {
Self::SetPpt(fast, slow) => {
settings.fast_ppt = fast;
settings.slow_ppt = slow;
},
Self::GetPpt(cb) => cb((settings.fast_ppt, settings.slow_ppt)),
Self::SetClockLimits(clocks) => settings.clock_limits = clocks,
Self::GetClockLimits(cb) => cb(settings.clock_limits.clone()),
Self::SetSlowMemory(val) => settings.slow_memory = val,
Self::GetSlowMemory(cb) => cb(settings.slow_memory),
}
}
}
pub enum GeneralMessage {
SetPersistent(bool),
GetPersistent(Callback<bool>),
GetCurrentProfileName(Callback<String>),
}
impl GeneralMessage {
fn process(self, settings: &mut General) {
match self {
Self::SetPersistent(val) => settings.persistent = val,
Self::GetPersistent(cb) => cb(settings.persistent),
Self::GetCurrentProfileName(cb) => cb(settings.name.clone()),
}
}
}
pub struct ApiMessageHandler {
intake: Receiver<ApiMessage>,
on_empty: Vec<Callback<()>>,
}
impl ApiMessageHandler {
pub fn process_forever(&mut self, settings: &mut Settings) {
while let Ok(msg) = self.intake.recv() {
self.process(settings, msg);
while let Ok(msg) = self.intake.try_recv() {
self.process(settings, msg);
}
// run on_set
if let Err(e) = settings.on_set() {
log::error!("Settings on_set() err: {}", e);
}
// do callbacks
for func in self.on_empty.drain(..) {
func(());
}
// save
log::debug!("api_worker is saving...");
let is_persistent = settings.general.persistent;
if is_persistent {
let save_path = crate::utility::settings_dir()
.join(settings.general.path.clone());
let settings_clone = settings.clone();
let save_json: SettingsJson = settings_clone.into();
unwrap_maybe_fatal(save_json.save(&save_path), "Failed to save settings");
log::debug!("Saved settings to {}", save_path.display());
} else {
log::debug!("Ignored save request for non-persistent settings");
}
}
}
pub fn process(&mut self, settings: &mut Settings, message: ApiMessage) {
match message {
ApiMessage::Battery(x) => x.process(&mut settings.battery),
ApiMessage::Cpu(x) => x.process(&mut settings.cpus),
ApiMessage::Gpu(x) => x.process(&mut settings.gpu),
ApiMessage::General(x) => x.process(&mut settings.general),
ApiMessage::OnResume => {
if let Err(e) = settings.on_resume() {
log::error!("Settings on_resume() err: {}", e);
}
}
ApiMessage::WaitForEmptyQueue(callback) => self.on_empty.push(callback),
ApiMessage::LoadSettings(path, name) => {
match settings.load_file(path.into(), name, false) {
Ok(success) => log::info!("Loaded settings file? {}", success),
Err(e) => log::warn!("Load file err: {}", e),
}
}
ApiMessage::LoadMainSettings => {
match settings.load_file(
crate::consts::DEFAULT_SETTINGS_FILE.into(),
crate::consts::DEFAULT_SETTINGS_NAME.to_owned(),
true
) {
Ok(success) => log::info!("Loaded main settings file? {}", success),
Err(e) => log::warn!("Load file err: {}", e),
}
}
ApiMessage::LoadSystemSettings => {
settings.load_system_default();
}
}
}
pub fn new() -> (Self, Sender<ApiMessage>) {
let (tx, rx) = mpsc::channel();
(Self {
intake: rx,
on_empty: Vec::with_capacity(4),
}, tx)
}
}

View file

@ -2,6 +2,8 @@ pub mod battery;
pub mod cpu;
pub mod general;
pub mod gpu;
pub mod handler;
mod async_utils;
mod utility;
pub(super) type ApiParameterType = Vec<usdpl_back::core::serdes::Primitive>;

View file

@ -14,7 +14,7 @@ pub fn map_result<T: Into<Primitive>>(result: Result<T, SettingError>) -> super:
}
}
#[inline]
/*#[inline]
pub fn map_empty_result<T: Into<Primitive>>(
result: Result<(), SettingError>,
success: T,
@ -26,4 +26,4 @@ pub fn map_empty_result<T: Into<Primitive>>(
vec![e.msg.into()]
},
}
}
}*/

13
backend/src/api_worker.rs Normal file
View file

@ -0,0 +1,13 @@
use std::thread::{self, JoinHandle};
use crate::settings::Settings;
//use crate::utility::{unwrap_lock, unwrap_maybe_fatal};
use crate::api::handler::ApiMessageHandler;
pub fn spawn(mut settings: Settings, mut handler: ApiMessageHandler) -> JoinHandle<()> {
thread::spawn(move || {
log::info!("api_worker starting...");
handler.process_forever(&mut settings);
log::warn!("api_worker completed!");
})
}

View file

@ -4,4 +4,4 @@ pub const PACKAGE_NAME: &'static str = env!("CARGO_PKG_NAME");
pub const PACKAGE_VERSION: &'static str = env!("CARGO_PKG_VERSION");
pub const DEFAULT_SETTINGS_FILE: &str = "default_settings.json";
pub const DEFAULT_SETTINGS_NAME: &str = "Default";
pub const DEFAULT_SETTINGS_NAME: &str = "Main";

View file

@ -6,7 +6,8 @@ mod state;
mod consts;
use consts::*;
mod resume_worker;
mod save_worker;
//mod save_worker;
mod api_worker;
mod utility;
use settings::OnSet;
@ -49,14 +50,16 @@ fn main() -> Result<(), ()> {
log::debug!("Settings: {:?}", loaded_settings);
let (_save_handle, save_sender) = save_worker::spawn(loaded_settings.clone());
let _resume_handle = resume_worker::spawn(loaded_settings.clone());
let (api_handler, api_sender) = crate::api::handler::ApiMessageHandler::new();
//let (_save_handle, save_sender) = save_worker::spawn(loaded_settings.clone());
let _resume_handle = resume_worker::spawn(api_sender.clone());
if let Err(e) = loaded_settings.on_set() {
log::error!("Startup Settings.on_set() error: {}", e);
}
Instance::new(PORT)
let instance = Instance::new(PORT)
.register("V_INFO", |_: Vec<Primitive>| {
vec![format!("{} v{}", PACKAGE_NAME, PACKAGE_VERSION).into()]
})
@ -67,107 +70,119 @@ fn main() -> Result<(), ()> {
.register("BATTERY_charge_design", api::battery::charge_design)
.register(
"BATTERY_set_charge_rate",
api::battery::set_charge_rate(loaded_settings.battery.clone(), save_sender.clone()),
api::battery::set_charge_rate(api_sender.clone()),
)
.register(
"BATTERY_get_charge_rate",
api::battery::get_charge_rate(loaded_settings.battery.clone()),
api::battery::get_charge_rate(api_sender.clone()),
)
.register(
"BATTERY_unset_charge_rate",
api::battery::unset_charge_rate(loaded_settings.battery.clone(), save_sender.clone()),
api::battery::unset_charge_rate(api_sender.clone()),
)
// cpu API functions
.register("CPU_count", api::cpu::max_cpus)
.register(
"CPU_set_online",
api::cpu::set_cpu_online(loaded_settings.cpus.clone(), save_sender.clone())
api::cpu::set_cpu_online(api_sender.clone())
)
.register(
"CPU_set_onlines",
api::cpu::set_cpus_online(loaded_settings.cpus.clone(), save_sender.clone())
api::cpu::set_cpus_online(api_sender.clone())
)
.register(
.register_async(
"CPU_get_onlines",
api::cpu::get_cpus_online(loaded_settings.cpus.clone())
api::cpu::get_cpus_online(api_sender.clone())
)
.register(
"CPU_set_clock_limits",
api::cpu::set_clock_limits(loaded_settings.cpus.clone(), save_sender.clone())
api::cpu::set_clock_limits(api_sender.clone())
)
.register(
"CPU_get_clock_limits",
api::cpu::get_clock_limits(loaded_settings.cpus.clone())
api::cpu::get_clock_limits(api_sender.clone())
)
.register(
"CPU_unset_clock_limits",
api::cpu::unset_clock_limits(loaded_settings.cpus.clone(), save_sender.clone())
api::cpu::unset_clock_limits(api_sender.clone())
)
.register(
"CPU_set_governor",
api::cpu::set_cpu_governor(loaded_settings.cpus.clone(), save_sender.clone())
api::cpu::set_cpu_governor(api_sender.clone())
)
.register(
"CPU_set_governors",
api::cpu::set_cpus_governors(api_sender.clone())
)
.register(
"CPU_get_governors",
api::cpu::get_cpu_governors(loaded_settings.cpus.clone())
api::cpu::get_cpu_governors(api_sender.clone())
)
// gpu API functions
.register(
"GPU_set_ppt",
api::gpu::set_ppt(loaded_settings.gpu.clone(), save_sender.clone())
api::gpu::set_ppt(api_sender.clone())
)
.register(
.register_async(
"GPU_get_ppt",
api::gpu::get_ppt(loaded_settings.gpu.clone())
api::gpu::get_ppt(api_sender.clone())
)
.register(
"GPU_unset_ppt",
api::gpu::unset_ppt(loaded_settings.gpu.clone(), save_sender.clone())
api::gpu::unset_ppt(api_sender.clone())
)
.register(
"GPU_set_clock_limits",
api::gpu::set_clock_limits(loaded_settings.gpu.clone(), save_sender.clone())
api::gpu::set_clock_limits(api_sender.clone())
)
.register(
.register_async(
"GPU_get_clock_limits",
api::gpu::get_clock_limits(loaded_settings.gpu.clone())
api::gpu::get_clock_limits(api_sender.clone())
)
.register(
"GPU_unset_clock_limits",
api::gpu::unset_clock_limits(loaded_settings.gpu.clone(), save_sender.clone())
api::gpu::unset_clock_limits(api_sender.clone())
)
.register(
"GPU_set_slow_memory",
api::gpu::set_slow_memory(loaded_settings.gpu.clone(), save_sender.clone())
api::gpu::set_slow_memory(api_sender.clone())
)
.register(
.register_async(
"GPU_get_slow_memory",
api::gpu::get_slow_memory(loaded_settings.gpu.clone())
api::gpu::get_slow_memory(api_sender.clone())
)
// general API functions
.register(
"GENERAL_set_persistent",
api::general::set_persistent(loaded_settings.general.clone(), save_sender.clone())
api::general::set_persistent(api_sender.clone())
)
.register(
"GENERAL_get_persistent",
api::general::get_persistent(loaded_settings.general.clone())
api::general::get_persistent(api_sender.clone())
)
.register(
"GENERAL_load_settings",
api::general::load_settings(loaded_settings.clone())
api::general::load_settings(api_sender.clone())
)
.register(
"GENERAL_load_default_settings",
api::general::load_default_settings(loaded_settings.clone())
api::general::load_default_settings(api_sender.clone())
)
.register(
"GENERAL_load_system_settings",
api::general::load_system_settings(api_sender.clone())
)
.register_async(
"GENERAL_get_name",
api::general::get_name(loaded_settings.general.clone())
api::general::get_name(api_sender.clone())
)
.register(
.register_async(
"GENERAL_wait_for_unlocks",
api::general::lock_unlock_all(loaded_settings.clone())
)
api::general::lock_unlock_all(api_sender.clone())
);
api_worker::spawn(loaded_settings, api_handler);
instance
.run_blocking()
}

View file

@ -1,12 +1,13 @@
use std::thread::{self, JoinHandle};
use std::time::{Duration, Instant};
use std::sync::mpsc::Sender;
use crate::settings::{OnResume, Settings};
use crate::utility::unwrap_maybe_fatal;
use crate::api::handler::ApiMessage;
//use crate::utility::unwrap_maybe_fatal;
const ALLOWED_ERROR: f64 = 100.0; // period of 10ms with 100x means sleep has to be >= 1s to be detected
pub fn spawn(settings: Settings) -> JoinHandle<()> {
pub fn spawn(sender: Sender<ApiMessage>) -> JoinHandle<()> {
thread::spawn(move || {
log::info!("resume_worker starting...");
let duration = Duration::from_millis(10); // very low so it detects before Steam client does
@ -18,7 +19,7 @@ pub fn spawn(settings: Settings) -> JoinHandle<()> {
if old_start.as_secs_f64() > duration.as_secs_f64() * (1.0 + ALLOWED_ERROR) {
// has just resumed from sleep
log::info!("Resume detected");
unwrap_maybe_fatal(settings.on_resume(), "On resume failure");
sender.send(ApiMessage::OnResume).expect("resume_worker send failed");
log::debug!(
"OnResume completed after sleeping for {}s",
old_start.as_secs_f32()

View file

@ -1,11 +1,11 @@
use std::convert::Into;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
//use std::sync::{Arc, Mutex};
use super::{Battery, Cpu, Gpu};
use super::{OnResume, OnSet, SettingError};
use crate::persist::{CpuJson, SettingsJson};
use crate::utility::unwrap_lock;
//use crate::utility::unwrap_lock;
const LATEST_VERSION: u64 = 0;
@ -43,24 +43,20 @@ impl OnSet for General {
#[derive(Debug, Clone)]
pub struct Settings {
pub general: Arc<Mutex<General>>,
pub cpus: Arc<Mutex<Vec<Cpu>>>,
pub gpu: Arc<Mutex<Gpu>>,
pub battery: Arc<Mutex<Battery>>,
pub general: General,
pub cpus: Vec<Cpu>,
pub gpu: Gpu,
pub battery: Battery,
}
impl OnSet for Settings {
fn on_set(&mut self) -> Result<(), SettingError> {
unwrap_lock(self.battery.lock(), "battery").on_set()?;
{
// cpu lock scope
let mut cpu_lock = unwrap_lock(self.cpus.lock(), "cpu");
for cpu in cpu_lock.iter_mut() {
cpu.on_set()?;
}
self.battery.on_set()?;
for cpu in self.cpus.iter_mut() {
cpu.on_set()?;
}
unwrap_lock(self.gpu.lock(), "gpu").on_set()?;
unwrap_lock(self.general.lock(), "general").on_set()?;
self.gpu.on_set()?;
self.general.on_set()?;
Ok(())
}
}
@ -70,24 +66,24 @@ impl Settings {
pub fn from_json(other: SettingsJson, json_path: PathBuf) -> Self {
match other.version {
0 => Self {
general: Arc::new(Mutex::new(General {
general: General {
persistent: other.persistent,
path: json_path,
name: other.name,
})),
cpus: Arc::new(Mutex::new(Self::convert_cpus(other.cpus, other.version))),
gpu: Arc::new(Mutex::new(Gpu::from_json(other.gpu, other.version))),
battery: Arc::new(Mutex::new(Battery::from_json(other.battery, other.version))),
},
cpus: Self::convert_cpus(other.cpus, other.version),
gpu: Gpu::from_json(other.gpu, other.version),
battery: Battery::from_json(other.battery, other.version),
},
_ => Self {
general: Arc::new(Mutex::new(General {
general: General {
persistent: other.persistent,
path: json_path,
name: other.name,
})),
cpus: Arc::new(Mutex::new(Self::convert_cpus(other.cpus, other.version))),
gpu: Arc::new(Mutex::new(Gpu::from_json(other.gpu, other.version))),
battery: Arc::new(Mutex::new(Battery::from_json(other.battery, other.version))),
},
cpus: Self::convert_cpus(other.cpus, other.version),
gpu: Gpu::from_json(other.gpu, other.version),
battery: Battery::from_json(other.battery, other.version),
},
}
}
@ -117,35 +113,26 @@ impl Settings {
pub fn system_default(json_path: PathBuf) -> Self {
Self {
general: Arc::new(Mutex::new(General {
general: General {
persistent: false,
path: json_path,
name: crate::consts::DEFAULT_SETTINGS_NAME.to_owned(),
})),
cpus: Arc::new(Mutex::new(Cpu::system_default())),
gpu: Arc::new(Mutex::new(Gpu::system_default())),
battery: Arc::new(Mutex::new(Battery::system_default())),
},
cpus: Cpu::system_default(),
gpu: Gpu::system_default(),
battery: Battery::system_default(),
}
}
fn load_system_default(&self) {
{
let mut cpu_lock = unwrap_lock(self.cpus.lock(), "cpu");
*cpu_lock = Cpu::system_default();
}
{
let mut gpu_lock = unwrap_lock(self.gpu.lock(), "gpu");
*gpu_lock = Gpu::system_default();
}
{
let mut battery_lock = unwrap_lock(self.battery.lock(), "battery");
*battery_lock = Battery::system_default();
}
pub fn load_system_default(&mut self) {
self.cpus = Cpu::system_default();
self.gpu = Gpu::system_default();
self.battery = Battery::system_default();
}
pub fn load_file(&self, filename: PathBuf, name: String, system_defaults: bool) -> Result<bool, SettingError> {
pub fn load_file(&mut self, filename: PathBuf, name: String, system_defaults: bool) -> Result<bool, SettingError> {
let json_path = crate::utility::settings_dir().join(filename);
let mut general_lock = unwrap_lock(self.general.lock(), "general");
//let mut general_lock = unwrap_lock(self.general.lock(), "general");
if json_path.exists() {
let settings_json = SettingsJson::open(&json_path).map_err(|e| SettingError {
msg: e.to_string(),
@ -153,53 +140,38 @@ impl Settings {
})?;
if !settings_json.persistent {
log::warn!("Loaded persistent config `{}` ({}) with persistent=false", &settings_json.name, json_path.display());
general_lock.persistent = false;
general_lock.name = name;
self.general.persistent = false;
self.general.name = name;
} else {
let new_cpus = Self::convert_cpus(settings_json.cpus, settings_json.version);
let new_gpu = Gpu::from_json(settings_json.gpu, settings_json.version);
let new_battery = Battery::from_json(settings_json.battery, settings_json.version);
{
let mut cpu_lock = unwrap_lock(self.cpus.lock(), "cpu");
*cpu_lock = new_cpus;
}
{
let mut gpu_lock = unwrap_lock(self.gpu.lock(), "gpu");
*gpu_lock = new_gpu;
}
{
let mut battery_lock = unwrap_lock(self.battery.lock(), "battery");
*battery_lock = new_battery;
}
general_lock.persistent = true;
general_lock.name = settings_json.name;
self.cpus = Self::convert_cpus(settings_json.cpus, settings_json.version);
self.gpu = Gpu::from_json(settings_json.gpu, settings_json.version);
self.battery = Battery::from_json(settings_json.battery, settings_json.version);
self.general.persistent = true;
self.general.name = settings_json.name;
}
} else {
if system_defaults {
self.load_system_default();
}
general_lock.persistent = false;
general_lock.name = name;
self.general.persistent = false;
self.general.name = name;
}
general_lock.path = json_path;
Ok(general_lock.persistent)
self.general.path = json_path;
Ok(self.general.persistent)
}
}
impl OnResume for Settings {
fn on_resume(&self) -> Result<(), SettingError> {
log::debug!("Locking settings for on_resume");
unwrap_lock(self.battery.lock(), "battery").on_resume()?;
log::debug!("Got battery lock");
{
let cpu_lock = unwrap_lock(self.cpus.lock(), "cpu");
log::debug!("Got cpus lock");
for cpu in cpu_lock.iter() {
cpu.on_resume()?;
}
log::debug!("Applying settings for on_resume");
self.battery.on_resume()?;
log::debug!("Resumed battery");
for cpu in self.cpus.iter() {
cpu.on_resume()?;
}
unwrap_lock(self.gpu.lock(), "gpu").on_resume()?;
log::debug!("Got gpu lock");
log::debug!("Resumed CPUs");
self.gpu.on_resume()?;
log::debug!("Resumed GPU");
Ok(())
}
}
@ -207,26 +179,18 @@ impl OnResume for Settings {
impl Into<SettingsJson> for Settings {
#[inline]
fn into(self) -> SettingsJson {
log::debug!("Locking settings to convert into json");
let gen_lock = unwrap_lock(self.general.lock(), "general");
log::debug!("Got general lock");
let cpu_lock = unwrap_lock(self.cpus.lock(), "cpu");
log::debug!("Got cpus lock");
let gpu_lock = unwrap_lock(self.gpu.lock(), "gpu");
log::debug!("Got gpu lock");
let batt_lock = unwrap_lock(self.battery.lock(), "battery");
log::debug!("Got battery lock");
log::debug!("Converting into json");
SettingsJson {
version: LATEST_VERSION,
name: gen_lock.name.clone(),
persistent: gen_lock.persistent,
cpus: cpu_lock
name: self.general.name.clone(),
persistent: self.general.persistent,
cpus: self.cpus
.clone()
.drain(..)
.map(|cpu| cpu.into())
.collect(),
gpu: gpu_lock.clone().into(),
battery: batt_lock.clone().into(),
gpu: self.gpu.clone().into(),
battery: self.battery.clone().into(),
}
}
}

View file

@ -1,5 +1,5 @@
use std::fmt::Display;
use std::sync::{LockResult, MutexGuard};
//use std::sync::{LockResult, MutexGuard};
pub fn unwrap_maybe_fatal<T: Sized, E: Display>(result: Result<T, E>, message: &str) -> T {
match result {
@ -11,7 +11,7 @@ pub fn unwrap_maybe_fatal<T: Sized, E: Display>(result: Result<T, E>, message: &
}
}
pub fn unwrap_lock<'a, T: Sized>(
/*pub fn unwrap_lock<'a, T: Sized>(
result: LockResult<MutexGuard<'a, T>>,
lock_name: &str,
) -> MutexGuard<'a, T> {
@ -22,7 +22,7 @@ pub fn unwrap_lock<'a, T: Sized>(
panic!("Failed to acquire {} lock: {}", lock_name, e);
}
}
}
}*/
pub fn settings_dir() -> std::path::PathBuf {
usdpl_back::api::dirs::home()

View file

@ -1,6 +1,6 @@
{
"name": "PowerTools",
"version": "1.0.5",
"version": "1.1.0",
"description": "Power tweaks for power users",
"scripts": {
"build": "shx rm -rf dist && rollup -c",