aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <yvchraiqi@protonmail.com>2022-06-14 13:58:09 +0200
committermetamuffin <yvchraiqi@protonmail.com>2022-06-14 13:58:09 +0200
commit09ee50601311c802e67e1f7b0a5278c334d2e406 (patch)
tree12325eda3288e08c16ffd85cce0aaa3ff4344be9
parenta7abc26af31b69db06a5875fc3fbc756adc838b1 (diff)
downloadkarlender-09ee50601311c802e67e1f7b0a5278c334d2e406.tar
karlender-09ee50601311c802e67e1f7b0a5278c334d2e406.tar.bz2
karlender-09ee50601311c802e67e1f7b0a5278c334d2e406.tar.zst
dynamic scheduling
-rw-r--r--karlc/src/main.rs25
-rw-r--r--karlcommon/src/protocol.rs4
-rw-r--r--karld/src/condition.rs44
-rw-r--r--karld/src/main.rs17
-rw-r--r--karld/src/schedule.rs92
5 files changed, 152 insertions, 30 deletions
diff --git a/karlc/src/main.rs b/karlc/src/main.rs
index 501ef3c..4501c56 100644
--- a/karlc/src/main.rs
+++ b/karlc/src/main.rs
@@ -96,7 +96,30 @@ fn main() {
print!(" \x1b[38;2;100;255;100mSchedule: \x1b[0m");
match t.schedule {
Schedule::Never => println!("\x1b[3m\x1b[2m(never)\x1b[0m"),
- Schedule::Dynamic { .. } => todo!(),
+ Schedule::Dynamic {
+ duration,
+ priority,
+ scheduled,
+ ..
+ } => {
+ // TODO dont ignore condition
+ println!("dynamicly scheduled",);
+ println!(" \x1b[38;2;100;255;100mPriority:\x1b[0m {priority}");
+ println!(
+ " \x1b[38;2;100;255;100mDuration:\x1b[0m {:?}",
+ std::time::Duration::from_secs(duration as u64)
+ );
+ println!(
+ " \x1b[38;2;100;255;100mScheduled for:\x1b[0m {}",
+ scheduled
+ .map(|r| format!(
+ "{} - {}",
+ NaiveDateTime::from_timestamp(r.start, 0),
+ NaiveDateTime::from_timestamp(r.end, 0)
+ ))
+ .unwrap_or("...".to_string())
+ );
+ }
Schedule::Static(t) => {
println!(
"from {} to {}",
diff --git a/karlcommon/src/protocol.rs b/karlcommon/src/protocol.rs
index d0aad41..02a9db1 100644
--- a/karlcommon/src/protocol.rs
+++ b/karlcommon/src/protocol.rs
@@ -51,7 +51,7 @@ pub enum Schedule {
Never,
Dynamic {
priority: f64,
- scheduled: Option<i64>,
+ scheduled: Option<Range<i64>>,
duration: i64,
condition: Condition, // duration, during which the task should be scheduled
},
@@ -91,7 +91,7 @@ pub enum Condition {
},
}
-#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
+#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum Property {
Year,
diff --git a/karld/src/condition.rs b/karld/src/condition.rs
index 1a9abab..643ca5e 100644
--- a/karld/src/condition.rs
+++ b/karld/src/condition.rs
@@ -1,6 +1,9 @@
use chrono::{Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Timelike};
use karlcommon::{Condition, Property};
-use std::cmp::{max, min};
+use std::{
+ cmp::{max, min},
+ ops::Range,
+};
use Direction::*;
use Edge::*;
@@ -40,6 +43,12 @@ pub trait ConditionFind {
(None, None) => None,
}
}
+
+ fn find_instance(&self, dir: Direction, from: NaiveDateTime) -> Range<Option<NaiveDateTime>> {
+ let start = self.find(Edge::Start, dir, from);
+ let end = self.find(Edge::End, dir, start.unwrap_or(from));
+ start..end
+ }
}
impl ConditionFind for Condition {
@@ -240,11 +249,34 @@ impl ConditionFind for Condition {
}
}
Condition::Range {
- prop: _,
- min: _,
- max: _,
- modulus: _,
- } => todo!(),
+ prop,
+ min,
+ max,
+ modulus,
+ } => {
+ // TODO
+ assert_eq!(*modulus, None);
+ assert_eq!(*prop, Property::Unix);
+ assert_eq!(dir, Direction::Forward);
+ let min = NaiveDateTime::from_timestamp(*min, 0);
+ let max = NaiveDateTime::from_timestamp(*max, 0);
+ match edge {
+ Start => {
+ if min < from {
+ None
+ } else {
+ Some(min)
+ }
+ }
+ End => {
+ if max < from {
+ None
+ } else {
+ Some(max)
+ }
+ }
+ }
+ }
}
}
}
diff --git a/karld/src/main.rs b/karld/src/main.rs
index 24f70a3..414b1e6 100644
--- a/karld/src/main.rs
+++ b/karld/src/main.rs
@@ -88,7 +88,7 @@ fn main() {
schedule: Schedule::Dynamic {
scheduled: None,
duration: 15 * 60,
- priority: 1.0,
+ priority: 2.0,
condition: Condition::Equal {
prop: Property::Monthofyear,
value: 6,
@@ -97,6 +97,21 @@ fn main() {
},
},
);
+ TASKS.write().unwrap().insert(
+ 4,
+ Task {
+ id: 4,
+ description: Some("sollte ich wirklich mal machen".to_string()),
+ name: "Geschirrspüler ausräumen".to_string(),
+ tags: vec!["Unwichtig".to_string()],
+ schedule: Schedule::Dynamic {
+ scheduled: None,
+ duration: 15 * 60,
+ priority: 5.0,
+ condition: Condition::Never,
+ },
+ },
+ );
std::thread::spawn(move || {
std::thread::sleep(std::time::Duration::from_secs_f64(0.1));
diff --git a/karld/src/schedule.rs b/karld/src/schedule.rs
index 971c63a..c30fd5c 100644
--- a/karld/src/schedule.rs
+++ b/karld/src/schedule.rs
@@ -1,8 +1,14 @@
+use chrono::Utc;
use karlcommon::{Condition, Schedule};
+use log::{info, warn};
-use crate::TASKS;
+use crate::{
+ condition::{ConditionFind, Direction},
+ TASKS,
+};
pub fn schedule_dynamic() {
+ info!("starting dynamic scheduling");
let mut tasks = TASKS.write().unwrap();
let mut colliders = vec![];
@@ -24,25 +30,71 @@ pub fn schedule_dynamic() {
}
});
- let cond = Condition::Invert(box Condition::Or(
- colliders
- .iter()
- .map(|c| match &c.schedule {
- Schedule::Never => Condition::Never,
- Schedule::Condition(c) => c.clone(),
- Schedule::Static(r) => Condition::Range {
- min: r.start,
- max: r.end,
- modulus: None,
- prop: karlcommon::Property::Unix,
- },
- Schedule::Dynamic { .. } => unreachable!(),
- })
- .collect(),
- ));
- println!("{:?}", cond);
+ let now = Utc::now().naive_local();
+ while let Some(t) = dynamic.pop() {
+ let props = match &t.schedule {
+ Schedule::Dynamic {
+ duration,
+ condition,
+ priority,
+ scheduled,
+ } => (duration, condition, priority, scheduled),
+ _ => unreachable!(),
+ };
- while dynamic.len() != 0 {
- todo!()
+ let duration =
+ chrono::Duration::from_std(std::time::Duration::from_secs(*props.0 as u64)).unwrap();
+
+ let cond = Condition::Invert(box Condition::Or(
+ colliders
+ .iter()
+ .map(|c| match &c.schedule {
+ Schedule::Never => Condition::Never,
+ Schedule::Condition(c) => c.clone(),
+ Schedule::Static(r) => Condition::Range {
+ min: r.start,
+ max: r.end,
+ modulus: None,
+ prop: karlcommon::Property::Unix,
+ },
+ Schedule::Dynamic { scheduled, .. } => match scheduled {
+ Some(r) => Condition::Range {
+ min: r.start,
+ max: r.end,
+ modulus: None,
+ prop: karlcommon::Property::Unix,
+ },
+ None => Condition::Never,
+ },
+ })
+ .collect(),
+ ));
+
+ let mut cursor = now;
+
+ let mut found_spot = false;
+ for _ in 0..256 {
+ // TODO actually respect the condition and repeat
+ let free = cond.find_instance(Direction::Forward, cursor);
+ let p_start = free.start.unwrap_or(now);
+ let p_end = p_start + duration;
+ if free.end.map(|e| e >= p_end).unwrap_or(true) {
+ t.schedule = Schedule::Dynamic {
+ condition: props.1.clone(),
+ duration: *props.0,
+ priority: *props.2,
+ scheduled: Some(p_start.timestamp()..p_end.timestamp()),
+ };
+ colliders.push(t);
+ found_spot = true;
+ break;
+ }
+ cursor = free.end.unwrap()
+ }
+ if !found_spot {
+ warn!("could not find a spot where the task fits in");
+ }
}
+ drop(tasks);
+ info!("done");
}