wip: working on cron
This commit is contained in:
parent
6e60f58145
commit
5a0c901281
65
Cargo.lock
generated
65
Cargo.lock
generated
@ -86,6 +86,15 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "deranged"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3"
|
||||||
|
dependencies = [
|
||||||
|
"powerfmt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.29"
|
version = "0.3.29"
|
||||||
@ -179,6 +188,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_threads"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.32.1"
|
version = "0.32.1"
|
||||||
@ -217,6 +235,12 @@ version = "0.2.13"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "powerfmt"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.69"
|
version = "1.0.69"
|
||||||
@ -285,6 +309,26 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.193"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.193"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
@ -341,6 +385,26 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5"
|
||||||
|
dependencies = [
|
||||||
|
"deranged",
|
||||||
|
"libc",
|
||||||
|
"num_threads",
|
||||||
|
"powerfmt",
|
||||||
|
"serde",
|
||||||
|
"time-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-core"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.34.0"
|
version = "1.34.0"
|
||||||
@ -471,6 +535,7 @@ dependencies = [
|
|||||||
"nix",
|
"nix",
|
||||||
"regex",
|
"regex",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -11,5 +11,6 @@ lazy_static = "1.4.0"
|
|||||||
nix = {version = "0.27.1", features = ["process", "signal", "fs"]}
|
nix = {version = "0.27.1", features = ["process", "signal", "fs"]}
|
||||||
regex = "1.10.2"
|
regex = "1.10.2"
|
||||||
thiserror = "1.0.50"
|
thiserror = "1.0.50"
|
||||||
|
time = { version = "0.3.30", features = ["local-offset"]}
|
||||||
tokio = { version = "1.34.0", features = ["full"] }
|
tokio = { version = "1.34.0", features = ["full"] }
|
||||||
tokio-util = "0.7.10"
|
tokio-util = "0.7.10"
|
||||||
|
|||||||
@ -266,6 +266,10 @@ impl Config {
|
|||||||
self.services.iter()
|
self.services.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_cron_iter(&self) -> std::slice::Iter<Crontab> {
|
||||||
|
self.cron.iter()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_shell(&self) -> Option<String> {
|
pub fn get_shell(&self) -> Option<String> {
|
||||||
if let Some(shell) = &self.shell_path {
|
if let Some(shell) = &self.shell_path {
|
||||||
return Some(shell.clone());
|
return Some(shell.clone());
|
||||||
@ -282,3 +286,84 @@ impl Clone for Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Clone for Crontab {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
minute: self.minute.clone(),
|
||||||
|
hour: self.hour.clone(),
|
||||||
|
day_of_month: self.day_of_month.clone(),
|
||||||
|
month: self.month.clone(),
|
||||||
|
day_of_week: self.day_of_week.clone(),
|
||||||
|
command: self.command.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for CronTimeFieldSpec {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
CronTimeFieldSpec::Any => CronTimeFieldSpec::Any,
|
||||||
|
CronTimeFieldSpec::Every(x) => CronTimeFieldSpec::Every(*x),
|
||||||
|
CronTimeFieldSpec::Exact(x) => CronTimeFieldSpec::Exact(*x),
|
||||||
|
CronTimeFieldSpec::MultiOccurrence(x) => {
|
||||||
|
CronTimeFieldSpec::MultiOccurrence(x.clone())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct CronFieldCmpHelper<'a>(u8, u8, Option<&'a Vec<u8>>);
|
||||||
|
impl PartialEq for CronTimeFieldSpec {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
let lhs: CronFieldCmpHelper;
|
||||||
|
let rhs: CronFieldCmpHelper;
|
||||||
|
match self {
|
||||||
|
CronTimeFieldSpec::Any => { lhs = CronFieldCmpHelper(0, 0, None); }
|
||||||
|
CronTimeFieldSpec::Every(x) => { lhs = CronFieldCmpHelper(1, *x, None); }
|
||||||
|
CronTimeFieldSpec::Exact(x) => { lhs = CronFieldCmpHelper(2, *x, None); }
|
||||||
|
CronTimeFieldSpec::MultiOccurrence(v) => { lhs = CronFieldCmpHelper(3, 0, Some(v)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
match other {
|
||||||
|
CronTimeFieldSpec::Any => { rhs = CronFieldCmpHelper(0, 0, None); }
|
||||||
|
CronTimeFieldSpec::Every(x) => { rhs = CronFieldCmpHelper(1, *x, None); }
|
||||||
|
CronTimeFieldSpec::Exact(x) => { rhs = CronFieldCmpHelper(2, *x, None); }
|
||||||
|
CronTimeFieldSpec::MultiOccurrence(v) => { rhs = CronFieldCmpHelper(3, 0, Some(v)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
if lhs.0 == rhs.0 {
|
||||||
|
if lhs.0 == 3u8 {
|
||||||
|
if let Some(lv) = lhs.2 {
|
||||||
|
if let Some(rv) = rhs.2 {
|
||||||
|
if lv.len() != rv.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut l_iter = lv.iter();
|
||||||
|
let mut r_iter = rv.iter();
|
||||||
|
'item: loop {
|
||||||
|
if let Some(liv) = l_iter.next() {
|
||||||
|
if let Some(riv) = r_iter.next() {
|
||||||
|
if *liv != *riv {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break 'item;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break 'item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return lhs.1 == rhs.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,15 +18,16 @@ pub async fn start(cfg: config::Config) -> Result<(), WingmateInitError> {
|
|||||||
let waiter_cancel_sighandler = sighandler_cancel.clone();
|
let waiter_cancel_sighandler = sighandler_cancel.clone();
|
||||||
|
|
||||||
let cancel = CancellationToken::new();
|
let cancel = CancellationToken::new();
|
||||||
let starter_cancel = cancel.clone();
|
let starter_service_cancel = cancel.clone();
|
||||||
|
let starter_cron_cancel = cancel.clone();
|
||||||
|
|
||||||
let mut set: JoinSet<Result<(), wmerr::WingmateInitError>> = JoinSet::new();
|
let mut set: JoinSet<Result<(), wmerr::WingmateInitError>> = JoinSet::new();
|
||||||
set.spawn(async move {
|
set.spawn(async move {
|
||||||
sighandler::sighandler(sig_sync_flag, cancel, sighandler_cancel).await
|
sighandler::sighandler(sig_sync_flag, cancel, sighandler_cancel).await
|
||||||
});
|
});
|
||||||
|
|
||||||
//TODO: start the process starter
|
starter::start_services(&mut set, &cfg, starter_service_cancel)?;
|
||||||
starter::start_services(&mut set, &cfg, starter_cancel)?;
|
starter::start_cron(&mut set, &cfg, starter_cron_cancel)?;
|
||||||
|
|
||||||
//TODO: spawn_blocking for waiter
|
//TODO: spawn_blocking for waiter
|
||||||
set.spawn_blocking(move || {
|
set.spawn_blocking(move || {
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
mod time_calc;
|
||||||
|
|
||||||
use tokio::task::JoinSet;
|
use tokio::task::JoinSet;
|
||||||
use tokio::process::{Command, Child};
|
use tokio::process::{Command, Child};
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
@ -10,8 +12,9 @@ use nix::sys::signal::{kill, Signal};
|
|||||||
use nix::errno::Errno;
|
use nix::errno::Errno;
|
||||||
use nix::unistd::Pid;
|
use nix::unistd::Pid;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use crate::init::config;
|
use time::OffsetDateTime;
|
||||||
use crate::init::error::WingmateInitError;
|
use crate::init::config::{self, CronTimeFieldSpec};
|
||||||
|
use crate::init::error::{WingmateInitError, CronConfigError};
|
||||||
|
|
||||||
|
|
||||||
pub fn start_services(ts: &mut JoinSet<Result<(), WingmateInitError>>, cfg: &config::Config, cancel: CancellationToken)
|
pub fn start_services(ts: &mut JoinSet<Result<(), WingmateInitError>>, cfg: &config::Config, cancel: CancellationToken)
|
||||||
@ -102,7 +105,37 @@ fn result_match(result: tokio_result<ExitStatus>) -> Result<(), anyhow::Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg!("starter: sleep exited");
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_cron(ts: &mut JoinSet<Result<(), WingmateInitError>>, cfg: &config::Config, cancel: CancellationToken)
|
||||||
|
-> Result<(), WingmateInitError> {
|
||||||
|
|
||||||
|
for c_ in cfg.get_cron_iter() {
|
||||||
|
let shell = cfg.get_shell().ok_or::<WingmateInitError>(WingmateInitError::NoShellAvailable)?;
|
||||||
|
let cron = c_.clone();
|
||||||
|
let cancel = cancel.clone();
|
||||||
|
|
||||||
|
ts.spawn(async move {
|
||||||
|
if cron.day_of_month != config::CronTimeFieldSpec::Any
|
||||||
|
&& cron.day_of_week != config::CronTimeFieldSpec::Any {
|
||||||
|
return Err(WingmateInitError::CronConfig { source: CronConfigError::ClashingConfig });
|
||||||
|
}
|
||||||
|
|
||||||
|
// let cron = cron.clone();
|
||||||
|
let mut last_running: Option<OffsetDateTime> = None;
|
||||||
|
'continuous: loop {
|
||||||
|
let cron = cron.clone();
|
||||||
|
|
||||||
|
time_calc::wait_calc(cron.clone(), &last_running);
|
||||||
|
select! {
|
||||||
|
_ = cancel.cancelled() => {
|
||||||
|
break 'continuous;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
77
src/init/daemon/starter/time_calc.rs
Normal file
77
src/init/daemon/starter/time_calc.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
use anyhow::Context;
|
||||||
|
use time::OffsetDateTime;
|
||||||
|
use crate::init::config::{Crontab,CronTimeFieldSpec};
|
||||||
|
use crate::init::error;
|
||||||
|
|
||||||
|
const MINUTE: i8 = 0;
|
||||||
|
const HOUR: i8 = 1;
|
||||||
|
const DAY_OF_MONTH: i8 = 2;
|
||||||
|
const MONTH: i8 = 3;
|
||||||
|
const DAY_OF_WEEK: i8 = 4;
|
||||||
|
|
||||||
|
struct CronField {
|
||||||
|
spec: CronTimeFieldSpec,
|
||||||
|
tag: i8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_cron_spec_to_vec(cron: Crontab) -> Vec<CronField> {
|
||||||
|
let mut res: Vec<CronField> = Vec::with_capacity(5);
|
||||||
|
|
||||||
|
res.push(CronField { spec: cron.minute, tag: MINUTE });
|
||||||
|
res.push(CronField { spec: cron.hour, tag: HOUR });
|
||||||
|
res.push(CronField { spec: cron.day_of_month, tag: DAY_OF_MONTH });
|
||||||
|
res.push(CronField { spec: cron.month, tag: MONTH });
|
||||||
|
res.push(CronField { spec: cron.day_of_week, tag: DAY_OF_WEEK });
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wait_calc(cron: Crontab, last_running: &Option<OffsetDateTime>) -> Result<Duration, error::CronConfigError> {
|
||||||
|
let local_clock = OffsetDateTime::now_local()
|
||||||
|
.context("getting current time in local timezone")
|
||||||
|
.map_err(|e| { error::CronConfigError::Other { source: e } })?;
|
||||||
|
|
||||||
|
match last_running {
|
||||||
|
Some(t) => {
|
||||||
|
let vec_cron = convert_cron_spec_to_vec(cron);
|
||||||
|
for vc in vec_cron {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// match cron.minute {
|
||||||
|
// CronTimeFieldSpec::Any => {},
|
||||||
|
// CronTimeFieldSpec::Every(x) => {},
|
||||||
|
// CronTimeFieldSpec::Exact(x) => {},
|
||||||
|
// CronTimeFieldSpec::MultiOccurrence(v) => {}
|
||||||
|
// }
|
||||||
|
// match cron.hour {
|
||||||
|
// CronTimeFieldSpec::Any => {},
|
||||||
|
// CronTimeFieldSpec::Every(x) => {},
|
||||||
|
// CronTimeFieldSpec::Exact(x) => {},
|
||||||
|
// CronTimeFieldSpec::MultiOccurrence(v) => {}
|
||||||
|
// }
|
||||||
|
// match cron.day_of_month {
|
||||||
|
// CronTimeFieldSpec::Any => {},
|
||||||
|
// CronTimeFieldSpec::Every(x) => {},
|
||||||
|
// CronTimeFieldSpec::Exact(x) => {},
|
||||||
|
// CronTimeFieldSpec::MultiOccurrence(v) => {}
|
||||||
|
// }
|
||||||
|
// match cron.month {
|
||||||
|
// CronTimeFieldSpec::Any => {},
|
||||||
|
// CronTimeFieldSpec::Every(x) => {},
|
||||||
|
// CronTimeFieldSpec::Exact(x) => {},
|
||||||
|
// CronTimeFieldSpec::MultiOccurrence(v) => {}
|
||||||
|
// }
|
||||||
|
// match cron.day_of_week {
|
||||||
|
// CronTimeFieldSpec::Any => {},
|
||||||
|
// CronTimeFieldSpec::Every(x) => {},
|
||||||
|
// CronTimeFieldSpec::Exact(x) => {},
|
||||||
|
// CronTimeFieldSpec::MultiOccurrence(v) => {}
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Duration::from_secs(1)) //PLACEHOLDER
|
||||||
|
}
|
||||||
@ -51,6 +51,12 @@ pub enum WingmateInitError {
|
|||||||
source: tokio::task::JoinError,
|
source: tokio::task::JoinError,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#[error("cron config")]
|
||||||
|
CronConfig {
|
||||||
|
#[source]
|
||||||
|
source: CronConfigError,
|
||||||
|
},
|
||||||
|
|
||||||
#[error("tripped over")]
|
#[error("tripped over")]
|
||||||
Other {
|
Other {
|
||||||
#[source]
|
#[source]
|
||||||
@ -58,6 +64,21 @@ pub enum WingmateInitError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Error,Debug)]
|
||||||
|
pub enum CronConfigError {
|
||||||
|
#[error("setting day of week and day of month at the same time will lead to unexpected behavior")]
|
||||||
|
ClashingConfig,
|
||||||
|
|
||||||
|
#[error("when setting time for higher order, the smallest (minute) muste be set")]
|
||||||
|
MissingMinute,
|
||||||
|
|
||||||
|
#[error("something went wrong")]
|
||||||
|
Other {
|
||||||
|
#[source]
|
||||||
|
source: anyhow::Error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Error,Debug)]
|
#[derive(Error,Debug)]
|
||||||
pub enum CronParseError {
|
pub enum CronParseError {
|
||||||
#[error("invalid cron syntax: {}", .0)]
|
#[error("invalid cron syntax: {}", .0)]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user