diff options
author | metamuffin <yvchraiqi@protonmail.com> | 2022-06-11 14:32:45 +0200 |
---|---|---|
committer | metamuffin <yvchraiqi@protonmail.com> | 2022-06-11 14:32:45 +0200 |
commit | c2699d114c921ab2ceb1f467b32a26257dddcf3d (patch) | |
tree | 0e886d333d944094c8c66905cac36a21cd010405 | |
parent | 9769c17c0b4c271c1cfbe726b19a6d3f9250c7c8 (diff) | |
download | karlender-c2699d114c921ab2ceb1f467b32a26257dddcf3d.tar karlender-c2699d114c921ab2ceb1f467b32a26257dddcf3d.tar.bz2 karlender-c2699d114c921ab2ceb1f467b32a26257dddcf3d.tar.zst |
changing the protocol again
-rw-r--r-- | Cargo.lock | 6 | ||||
-rw-r--r-- | karlc/Cargo.toml | 2 | ||||
-rw-r--r-- | karlc/src/main.rs | 82 | ||||
-rw-r--r-- | karlc/src/pretty.rs | 24 | ||||
-rw-r--r-- | karlcommon/Cargo.toml | 2 | ||||
-rw-r--r-- | karlcommon/src/protocol.rs | 20 | ||||
-rw-r--r-- | karld/Cargo.toml | 2 | ||||
-rw-r--r-- | karld/protocol.d.ts | 2 | ||||
-rw-r--r-- | karld/src/condition.rs | 9 | ||||
-rw-r--r-- | karld/src/helper.rs | 98 | ||||
-rw-r--r-- | karld/src/main.rs | 91 | ||||
-rw-r--r-- | karld/src/schedule.rs | 5 |
12 files changed, 253 insertions, 90 deletions
@@ -188,7 +188,7 @@ checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" [[package]] name = "karlc" -version = "0.1.0" +version = "0.1.1" dependencies = [ "chrono", "clap", @@ -203,14 +203,14 @@ dependencies = [ [[package]] name = "karlcommon" -version = "0.1.0" +version = "0.1.2" dependencies = [ "serde", ] [[package]] name = "karld" -version = "0.1.1" +version = "0.1.5" dependencies = [ "anyhow", "chrono", diff --git a/karlc/Cargo.toml b/karlc/Cargo.toml index 653933a..3bad351 100644 --- a/karlc/Cargo.toml +++ b/karlc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "karlc" -version = "0.1.0" +version = "0.1.1" edition = "2021" [dependencies] diff --git a/karlc/src/main.rs b/karlc/src/main.rs index e95b5b7..55bb974 100644 --- a/karlc/src/main.rs +++ b/karlc/src/main.rs @@ -4,7 +4,9 @@ pub mod pretty; use chrono::{NaiveDateTime, Utc}; use clap::{Args, Parser, Subcommand}; use client::Client; -use karlcommon::{socket_path, version, ClientboundPacket, ServerboundPacket, Task}; +use karlcommon::{ + socket_path, version, ClientboundPacket, Condition, Schedule, ServerboundPacket, Task, +}; use log::{error, info}; use std::{os::unix::net::UnixStream, path::PathBuf, process::exit}; @@ -91,37 +93,49 @@ fn main() { t.description .unwrap_or("\x1b[3m\x1b[2m(no description)\x1b[0m".to_string()) ); - if let Some(o) = t.occurence { - println!( - " \x1b[38;2;100;255;100mOccurence:\x1b[0m {}", - fmt_condition(&o) - ); - print!(" \x1b[38;2;100;255;100mNext instances: \x1b[0m"); + if !t.tags.is_empty() { + println!(" \x1b[38;2;100;255;100mTags:\x1b[0m {}", t.tags.join(", ")); + } + 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::Static(t) => { + println!( + "from {} to {}", + NaiveDateTime::from_timestamp(t.start, 0), + NaiveDateTime::from_timestamp(t.end, 0) + ) + } + Schedule::Condition(o) => { + println!("when {}", fmt_condition(&o)); + print!(" \x1b[38;2;100;255;100mNext instances: \x1b[0m"); - client.send(ServerboundPacket::ListInstances { - task: t.id, - limit: 5, - range: Some(Utc::now().naive_local().timestamp())..None, - }); - if let ClientboundPacket::InstanceList(instances) = - client.receiver.recv().unwrap() - { - for i in instances { - println!( - "\x1b[19G{} - {}", - i.at.start - .map(|e| format!( - "{}", - NaiveDateTime::from_timestamp(e as i64, 0) - )) - .unwrap_or("...".to_string()), - i.at.end - .map(|e| format!( - "{}", - NaiveDateTime::from_timestamp(e as i64, 0) - )) - .unwrap_or("...".to_string()), - ); + client.send(ServerboundPacket::ListInstances { + task: t.id, + limit: 5, + range: Some(Utc::now().naive_local().timestamp())..None, + }); + if let ClientboundPacket::InstanceList(instances) = + client.receiver.recv().unwrap() + { + for i in instances { + println!( + "\x1b[19G{} - {}", + i.at.start + .map(|e| format!( + "{}", + NaiveDateTime::from_timestamp(e, 0) + )) + .unwrap_or("...".to_string()), + i.at.end + .map(|e| format!( + "{}", + NaiveDateTime::from_timestamp(e, 0) + )) + .unwrap_or("...".to_string()), + ); + } } } } @@ -156,11 +170,7 @@ impl TaskSpec { name: self.name, description: self.description, tags: self.tags, - priority: 0.0, - completed: None, - scheduled: None, - occurence: None, - deadline: None, + schedule: Schedule::Never, } } } diff --git a/karlc/src/pretty.rs b/karlc/src/pretty.rs index bf9cf20..abd5f96 100644 --- a/karlc/src/pretty.rs +++ b/karlc/src/pretty.rs @@ -7,10 +7,14 @@ pub fn indent(s: &str) -> String { pub fn fmt_condition(c: &Condition) -> String { match c { Condition::From(_) => todo!(), - Condition::Or(_) => todo!(), + Condition::Or(cs) => cs + .iter() + .map(|e| format!("{{ {} }}", fmt_condition(e))) + .reduce(|a, b| format!("{} ∨ {}", a, b)) + .unwrap_or("never".to_string()), Condition::And(cs) => cs .iter() - .map(|e| fmt_condition(e)) + .map(|e| format!("{{ {} }}", fmt_condition(e))) .reduce(|a, b| format!("{} ∧ {}", a, b)) .unwrap_or("never".to_string()), Condition::Invert(_) => todo!(), @@ -26,10 +30,16 @@ pub fn fmt_condition(c: &Condition) -> String { } } Condition::Range { - prop: _, - min: _, - max: _, - modulus: _, - } => todo!(), + prop, + min, + max, + modulus, + } => { + if let Some(m) = modulus { + format!("{} < {:?} < {} (mod {})", min, prop, max, m) + } else { + format!("{} < {:?} < {}", min, prop, max) + } + } } } diff --git a/karlcommon/Cargo.toml b/karlcommon/Cargo.toml index 6ce571e..c56085e 100644 --- a/karlcommon/Cargo.toml +++ b/karlcommon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "karlcommon" -version = "0.1.0" +version = "0.1.2" edition = "2021" [dependencies] diff --git a/karlcommon/src/protocol.rs b/karlcommon/src/protocol.rs index f971ef2..de65802 100644 --- a/karlcommon/src/protocol.rs +++ b/karlcommon/src/protocol.rs @@ -41,15 +41,21 @@ pub struct Task { pub id: u64, pub name: String, pub description: Option<String>, - pub tags: Vec<String>, - pub priority: f64, - - pub completed: Option<i64>, - pub scheduled: Option<i64>, + pub schedule: Schedule, +} - pub occurence: Option<Condition>, - pub deadline: Option<Condition>, +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", content = "options", rename_all = "snake_case")] +pub enum Schedule { + Never, + Dynamic { + priority: f64, + scheduled: Option<i64>, + deadline: Option<Condition>, + }, + Condition(Condition), + Static(Range<i64>), } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/karld/Cargo.toml b/karld/Cargo.toml index 0e4d712..b797dc9 100644 --- a/karld/Cargo.toml +++ b/karld/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "karld" -version = "0.1.1" +version = "0.1.5" edition = "2021" [dependencies] diff --git a/karld/protocol.d.ts b/karld/protocol.d.ts index be1a9bd..2eb1630 100644 --- a/karld/protocol.d.ts +++ b/karld/protocol.d.ts @@ -7,7 +7,7 @@ interface Error { type: "error", data: { kind: "unknown_task", details: null } | interface Handshake { type: "handshake", data: { version: string } } interface ListTasks { type: "list_tasks", data: null } interface TaskList { type: "task_list", data: Task[] } -interface ListInstances { type: "list_instances", data: null } +interface ListInstances { type: "list_instances", data: { task: number, range: Range } } interface InstanceList { type: "instance_list", data: Instance[] } interface UpdateTask { type: "update_task", data: Task } interface RemoveTask { type: "remove_task", data: number } diff --git a/karld/src/condition.rs b/karld/src/condition.rs index db1cf1d..81f7245 100644 --- a/karld/src/condition.rs +++ b/karld/src/condition.rs @@ -1,18 +1,9 @@ use chrono::{Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; use karlcommon::{Condition, Property}; -use serde::{Deserialize, Serialize}; use std::cmp::{max, min}; use Direction::*; use Edge::*; -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Range<T>(T, T); -impl<T: PartialOrd + PartialEq> Range<T> { - pub fn includes(&self, a: T) -> bool { - a > self.0 && a < self.1 - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Edge { Start, diff --git a/karld/src/helper.rs b/karld/src/helper.rs new file mode 100644 index 0000000..2e601b0 --- /dev/null +++ b/karld/src/helper.rs @@ -0,0 +1,98 @@ +use crate::condition::{ConditionFind, Direction, Edge}; +use chrono::{NaiveDate, NaiveDateTime}; +use karlcommon::{Schedule, Task}; +use std::{collections::HashMap, ops::Range}; + +pub struct DiscreteCache { + tasks: HashMap<u64, DiscreteCacheTask>, +} +pub struct DiscreteCacheTask { + inner: Task, + cached: Option<Range<NaiveDateTime>>, + cache: Vec<Range<NaiveDateTime>>, +} + +impl DiscreteCache { + pub fn new_for(tasks: HashMap<u64, Task>) -> Self { + Self { + tasks: HashMap::from_iter( + tasks + .into_iter() + .map(|(k, v)| (k, DiscreteCacheTask::new(v))), + ), + } + } +} + +impl DiscreteCacheTask { + pub fn new(inner: Task) -> Self { + Self { + inner, + cached: None, + cache: vec![], + } + } + + pub fn find(&mut self, from: NaiveDateTime, dir: Direction) -> Range<Option<NaiveDateTime>> { + assert_eq!(dir, Direction::Forward); + // TODO cache + // if let Some(c) = self.cached {} + match &self.inner.schedule { + Schedule::Condition(o) => { + let start = o.find(Edge::Start, dir, from); + let end = o.find(Edge::End, dir, from); + match (start, end) { + (Some(start), Some(end)) => { + if end < start { + if let Some(start) = o.find(Edge::Start, dir.invert(), from) { + assert!(start < end); + Some(start)..Some(end) + } else { + None..Some(end) + } + } else { + Some(start)..Some(end) + } + } + (None, Some(end)) => { + if let Some(start) = o.find(Edge::Start, dir.invert(), from) { + assert!(start < end); + Some(start)..Some(end) + } else { + None..Some(end) + } + } + (Some(start), None) => Some(start)..None, + (None, None) => None..None, + } + } + Schedule::Never => None..None, + Schedule::Static(_) => None..None, // TODO + Schedule::Dynamic { .. } => None..None, // TODO + } + } +} + +pub trait Overlaps<T> { + fn overlaps(&self, v: T) -> bool; +} +impl Overlaps<i64> for Range<i64> { + fn overlaps(&self, v: i64) -> bool { + self.start <= v && v < self.end + } +} +impl Overlaps<i64> for Range<Option<i64>> { + fn overlaps(&self, v: i64) -> bool { + match (self.start, self.end) { + (Some(s), Some(e)) => s <= v && v < e, + (Some(s), None) => s <= v, + (None, Some(e)) => v < e, + (None, None) => false, + } + } +} +impl Overlaps<Range<i64>> for Range<Option<i64>> { + fn overlaps(&self, v: Range<i64>) -> bool { + self.overlaps(v.start) || self.overlaps(v.end) + } +} diff --git a/karld/src/main.rs b/karld/src/main.rs index 0983554..2d0c9e9 100644 --- a/karld/src/main.rs +++ b/karld/src/main.rs @@ -1,12 +1,15 @@ pub mod condition; +pub mod helper; pub mod interface; +pub mod schedule; use chrono::NaiveDateTime; use condition::ConditionFind; use crossbeam_channel::Sender; +use helper::Overlaps; use interface::network_loop; use karlcommon::{ - ClientboundPacket, Condition, Instance, Property, ProtoError, ServerboundPacket, Task, + ClientboundPacket, Condition, Instance, Property, ProtoError, Schedule, ServerboundPacket, Task, }; use log::{debug, info}; use std::{collections::HashMap, sync::RwLock}; @@ -20,11 +23,8 @@ fn main() { id: 0, name: "Mittagessen im Februar".to_string(), description: None, - tags: vec![], - priority: 69.0, - completed: None, - scheduled: None, - occurence: Some(Condition::And(vec![ + tags: vec!["Essen".to_string(), "Unwichtig".to_string()], + schedule: Schedule::Condition(Condition::And(vec![ Condition::Equal { modulus: None, prop: Property::Monthofyear, @@ -36,7 +36,37 @@ fn main() { value: 12, }, ])), - deadline: None, + }, + ); + TASKS.write().unwrap().insert( + 1, + Task { + id: 1, + name: "Abendessen oder Frühstück".to_string(), + description: Some("Nom nom nom".to_string()), + tags: vec!["Essen".to_string()], + schedule: Schedule::Condition(Condition::Or(vec![ + Condition::Equal { + modulus: None, + prop: Property::Hour, + value: 18, + }, + Condition::Equal { + modulus: None, + prop: Property::Hour, + value: 7, + }, + ])), + }, + ); + TASKS.write().unwrap().insert( + 2, + Task { + id: 2, + description: None, + name: "Wichtiger termin™".to_string(), + tags: vec![], + schedule: Schedule::Static(1654997366..1655007366), }, ); network_loop(); @@ -77,25 +107,38 @@ pub fn handle_packet(client: u32, packet: ServerboundPacket, responder: Sender<C }; let mut ocs = vec![]; - if let Some(o) = &t.occurence { - let mut time = NaiveDateTime::from_timestamp(range.start.unwrap_or(0), 0); - let end_time = range.end.map(|e| NaiveDateTime::from_timestamp(e, 0)); - for _ in 0..limit { - let start = o.find(condition::Edge::Start, condition::Direction::Forward, time); - let end = o.find(condition::Edge::End, condition::Direction::Forward, time); - ocs.push(Instance { - of: t.id, - at: start.map(|e| e.timestamp())..end.map(|e| e.timestamp()), - }); - if let Some(s) = end { - if let Some(e) = end_time { - if s > e { - break; + match t.schedule { + Schedule::Never => (), + Schedule::Dynamic { .. } => (), // TODO + Schedule::Static(r) => { + if range.overlaps(r.clone()) { + ocs.push(Instance { + of: t.id, + at: Some(r.start)..Some(r.end), + }) + } + } + Schedule::Condition(o) => { + let mut time = NaiveDateTime::from_timestamp(range.start.unwrap_or(0), 0); + let end_time = range.end.map(|e| NaiveDateTime::from_timestamp(e, 0)); + for _ in 0..limit { + let start = + o.find(condition::Edge::Start, condition::Direction::Forward, time); + let end = o.find(condition::Edge::End, condition::Direction::Forward, time); + ocs.push(Instance { + of: t.id, + at: start.map(|e| e.timestamp())..end.map(|e| e.timestamp()), + }); + if let Some(s) = end { + if let Some(e) = end_time { + if s > e { + break; + } } + time = s; + } else { + break; } - time = s; - } else { - break; } } } diff --git a/karld/src/schedule.rs b/karld/src/schedule.rs new file mode 100644 index 0000000..1f3c479 --- /dev/null +++ b/karld/src/schedule.rs @@ -0,0 +1,5 @@ + + +pub fn schedule_dynamic() { + +} |