use crate::engine::vault::Vault;
use crate::utils;
use std::io::{BufRead, BufReader};
#[derive(std::fmt::Debug)]
pub struct ArgApp {
pub nap: f64,
pub join_gap: f64,
pub round_req: usize,
pub round_req_min: usize,
pub round_req_max: usize,
pub buf_task: usize,
pub spawn_task_max: usize,
pub round_task: usize,
pub round_task_min: usize,
pub round_res: usize,
pub round_errs: usize,
pub round_entity: usize,
pub skip: bool,
pub(crate) rate: Vault<ArgRate>,
pub arg_affix: Option<ArgAffix>,
pub data_dir: String,
}
impl ArgApp {
pub fn new() -> Self {
let mut arg = ArgApp {
nap: 17.0,
join_gap: 7.0,
round_req: 10,
round_req_min: 3,
round_req_max: 70,
buf_task: 1000,
spawn_task_max: 100,
round_task: 10,
round_task_min: 7,
round_res: 10,
round_errs: 10,
round_entity: 10,
skip: true,
rate: Vault::new(ArgRate::new()),
arg_affix: None,
data_dir: "data/".into(),
};
arg.parse_config(None, false);
arg
}
pub fn affix_on(&self) -> bool {
if let Some(ArgAffix { is_on: true, .. }) = self.arg_affix {
return true;
}
false
}
fn set(&mut self, key: &str, value: &str, fail_safe: bool) {
match key {
"nap" => {
if let Ok(v) = value.parse::<f64>() {
self.nap = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for nap: {}", value);
} else {
panic!("Update Failed, invalid value for nap: {}", value);
}
}
"join_gap" => {
if let Ok(v) = value.parse::<f64>() {
self.join_gap = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for join_gap: {}", value);
} else {
}
}
"round_req" => {
if let Ok(v) = value.parse::<usize>() {
self.round_req = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for round_req: {}", value);
} else {
panic!("Update Failed, invalid value for round_req: {}", value);
}
}
"round_req_min" => {
if let Ok(v) = value.parse::<usize>() {
self.round_req_min = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for round_req_min: {}", value);
} else {
panic!("Update Failed, invalid value for round_req_min: {}", value);
}
}
"round_req_max" => {
if let Ok(v) = value.parse::<usize>() {
self.round_req_max = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for round_req_max: {}", value);
} else {
panic!("Update Failed, invalid value for round_req_max: {}", value);
}
}
"buf_task" => {
if let Ok(v) = value.parse::<usize>() {
self.buf_task = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for buf_task: {}", value);
} else {
panic!("Update Failed, invalid value for buf_task: {}", value);
}
}
"spawn_task_max" => {
if let Ok(v) = value.parse::<usize>() {
self.spawn_task_max = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for spawn_task_max: {}", value);
} else {
panic!("Update Failed, invalid value for spawn_task_max: {}", value);
}
}
"round_task" => {
if let Ok(v) = value.parse::<usize>() {
self.round_task = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for round_task: {}", value);
} else {
panic!("Update Failed, invalid value for round_task: {}", value);
}
}
"round_task_min" => {
if let Ok(v) = value.parse::<usize>() {
self.round_task_min = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for round_task_min: {}", value);
} else {
panic!("Update Failed, invalid value for round_task_min: {}", value);
}
}
"round_res" => {
if let Ok(v) = value.parse::<usize>() {
self.round_res = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for round_res: {}", value);
} else {
panic!("Update Failed, invalid value for round_res: {}", value);
}
}
"round_errs" => {
if let Ok(v) = value.parse::<usize>() {
self.round_errs = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for round_errs: {}", value);
} else {
panic!("Update Failed, invalid value for round_errs: {}", value);
}
}
"round_entity" => {
if let Ok(v) = value.parse::<usize>() {
self.round_entity = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for round_entity: {}", value);
} else {
panic!("Update Failed, invalid value for round_entity: {}", value);
}
}
"skip" => {
if let Ok(v) = value.parse::<bool>() {
self.skip = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for skip: {}", value);
} else {
panic!("Update Failed, invalid value for skip: {}", value);
}
}
"data_dir" => {
if let Ok(v) = value.parse::<String>() {
self.data_dir = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for data_dir: {}", value);
} else {
panic!("Update Failed, invalid value for data_dir: {}", value);
}
}
"rate.cycle" => {
if let Ok(v) = value.parse::<f64>() {
self.rate.as_mut().cycle = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for rate.cycle: {}", value);
} else {
panic!("Update Failed, invalid value for rate.cycle: {}", value);
}
}
"rate.interval" => {
if let Ok(v) = value.parse::<f64>() {
self.rate.as_mut().interval = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for rate.interval: {}", value);
} else {
panic!("Update Failed, invalid value for rate.interval: {}", value);
}
}
"rate.load" => {
if let Ok(v) = value.parse::<f64>() {
self.rate.as_mut().load = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for rate.load: {}", value);
} else {
panic!("Update Failed, invalid value for rate.load: {}", value);
}
}
"rate.remains" => {
if let Ok(v) = value.parse::<usize>() {
self.rate.as_mut().remains = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for rate.remains: {}", value);
} else {
panic!("Update Failed, invalid value for rate.remains: {}", value);
}
}
"rate.rate_low" => {
if let Ok(v) = value.parse::<f64>() {
self.rate.as_mut().rate_low = v;
} else if fail_safe {
log::error!("Update Failed, invalid value for rate.rate_low: {}", value);
} else {
panic!("Update Failed, invalid value for rate.rate_low: {}", value);
}
}
"arg_affix.is_on" => {
if self.arg_affix.is_some() {
if let Ok(v) = value.parse::<bool>() {
self.arg_affix.as_mut().unwrap().is_on = v;
} else if fail_safe {
log::error!(
"Update Failed, invalid value for arg_affix.is_on: {}",
value
);
} else {
panic!(
"Update Failed, invalid value for arg_affix.is_on: {}",
value
);
}
} else {
let mut arg = ArgAffix::new();
if let Ok(v) = value.parse::<bool>() {
arg.is_on = v;
} else if fail_safe {
log::error!(
"Update Failed, invalid value for arg_affix.is_on: {}",
value
);
} else {
panic!(
"Update Failed, invalid value for arg_affix.is_on: {}",
value
);
}
self.arg_affix = Some(arg);
}
}
"arg_affix.affix_min" => {
if self.arg_affix.is_some() {
if let Ok(v) = value.parse::<usize>() {
self.arg_affix.as_mut().unwrap().affix_min = v;
} else if fail_safe {
log::error!(
"Update Failed, invalid value for arg_affix.affix_min: {}",
value
);
} else {
panic!(
"Update Failed, invalid value for arg_affix.affix_in: {}",
value
);
}
} else {
let mut arg = ArgAffix::new();
if let Ok(v) = value.parse::<usize>() {
arg.affix_min = v;
} else if fail_safe {
log::error!(
"Update Failed, invalid value for arg_affix.affix_min: {}",
value
);
} else {
panic!(
"Update Failed, invalid value for arg_affix.affix_in: {}",
value
);
}
self.arg_affix = Some(arg);
}
}
"arg_affix.affix_max" => {
if self.arg_affix.is_some() {
if let Ok(v) = value.parse::<usize>() {
self.arg_affix.as_mut().unwrap().affix_max = v;
} else if fail_safe {
log::error!(
"Update Failed, invalid value for arg_affix.affix_max : {}",
value
);
} else {
panic!(
"Update Failed, invalid value for arg_affix.affix_max: {}",
value
);
}
} else {
let mut arg = ArgAffix::new();
if let Ok(v) = value.parse::<usize>() {
arg.affix_max = v;
} else if fail_safe {
log::error!(
"Update Failed, invalid value for arg_affix.affix_max : {}",
value
);
} else {
panic!(
"Update Failed, invalid value for arg_affix.affix_max: {}",
value
);
}
self.arg_affix = Some(arg);
}
}
_ => {
eprintln!("Unrecognizable or unnecessary variable: {}", key);
}
}
}
pub fn parse_config(&mut self, _path: Option<&str>, fail_safe: bool) {
let fields = [
"arg_affix.is_on",
"arg_affix.affix_min",
"arg_affix.affix_max",
"rate.cycle",
"rate.interval",
"rate.load",
"rate.remains",
"rate.rate_low",
"data_dir",
"skip",
"nap",
"join_gap",
"round_req",
"round_req_min",
"round_req_max",
"buf_task",
"spawn_task_max",
"round_task",
"round_task_min",
"round_res",
"round_errs",
"round_entity",
];
let file = std::fs::File::open("dyer.cfg").unwrap();
let reader = BufReader::new(file);
reader.lines().filter(|line| line.is_ok()).for_each(|line| {
let pairs = line
.unwrap()
.split(":")
.map(|ele| ele.to_string())
.collect::<Vec<String>>();
if pairs.len() == 2 {
let key = pairs[0].trim();
if fields.contains(&key) {
let value = pairs[1].trim().trim_end_matches(|c| c == ',');
self.set(key, value, fail_safe);
}
}
});
self.init();
}
fn init(&mut self) {
if self.arg_affix.is_some() {
if self.arg_affix.as_ref().unwrap().affix_min
>= self.arg_affix.as_ref().unwrap().affix_max
{
self.arg_affix.as_mut().unwrap().affix_max =
self.arg_affix.as_ref().unwrap().affix_min * 3 + 1;
}
}
if self.round_req_min >= self.round_req_max {
self.round_req_max = self.round_req_min * 3 + 1;
}
}
}
#[derive(std::fmt::Debug)]
pub struct ArgAffix {
pub is_on: bool,
pub affix_min: usize,
pub affix_max: usize,
}
impl ArgAffix {
pub fn new() -> Self {
ArgAffix {
is_on: false,
affix_min: 0,
affix_max: 0,
}
}
}
#[derive(std::fmt::Debug)]
pub struct ArgRate {
pub uptime: f64,
pub cycle: f64,
pub cycle_usage: f64,
pub interval: f64,
pub load: f64,
pub err: usize,
pub remains: usize,
pub rate_low: f64,
pub anchor_low: f64,
pub anchor: f64,
pub stamps: Vec<f64>,
}
impl ArgRate {
pub fn new() -> Self {
let now = utils::now();
ArgRate {
uptime: 0.0,
cycle: 600.0,
cycle_usage: 0.0,
load: 99.0,
remains: 110,
rate_low: 0.333,
anchor_low: 0.0,
err: 0,
anchor: now + 30.0,
interval: 30.0,
stamps: Vec::new(),
}
}
pub fn update(&mut self) -> bool {
let now = utils::now();
if now > self.anchor {
self.cycle_usage += self.interval;
self.anchor += self.interval;
self.uptime += self.interval;
if self.err > 0 {
self.anchor_low = now + self.err as f64 * 0.333;
}
if now >= self.anchor_low {
log::debug!("active period");
self.stamps.clear();
self.remains = self.load as usize;
}
log::debug!("arg rate updated: {:?}", self);
return true;
}
false
}
pub fn backup(&mut self) -> bool {
if self.cycle_usage >= self.cycle {
self.cycle_usage = self.cycle_usage.rem_euclid(self.cycle);
return true;
}
false
}
pub fn get_len(&mut self, tm: Option<f64>) -> usize {
let now = match tm {
Some(now) => now,
None => utils::now(),
};
let delta = self.load * (self.anchor - now) / self.interval;
let len = if self.remains as f64 >= delta + 0.5 && delta >= 0.0 {
self.remains as f64 - delta
} else if (self.remains as f64) < delta + 0.5 && delta >= 0.0 {
self.remains = delta as usize;
0.0
} else {
self.remains as f64
};
log::trace!("Remains:{}, Delta: {}, Len: {}", self.remains, delta, len);
self.remains = self.remains - (len as usize) + 1;
if len > 0.0 {
log::trace!("Only {} tasks are valid by rate control.", len);
}
if self.anchor_low <= now {
len.ceil() as usize
} else {
(self.rate_low * len).ceil() as usize
}
}
}