aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <yvchraiqi@protonmail.com>2022-06-11 14:32:45 +0200
committermetamuffin <yvchraiqi@protonmail.com>2022-06-11 14:32:45 +0200
commitc2699d114c921ab2ceb1f467b32a26257dddcf3d (patch)
tree0e886d333d944094c8c66905cac36a21cd010405
parent9769c17c0b4c271c1cfbe726b19a6d3f9250c7c8 (diff)
downloadkarlender-c2699d114c921ab2ceb1f467b32a26257dddcf3d.tar
karlender-c2699d114c921ab2ceb1f467b32a26257dddcf3d.tar.bz2
karlender-c2699d114c921ab2ceb1f467b32a26257dddcf3d.tar.zst
changing the protocol again
-rw-r--r--Cargo.lock6
-rw-r--r--karlc/Cargo.toml2
-rw-r--r--karlc/src/main.rs82
-rw-r--r--karlc/src/pretty.rs24
-rw-r--r--karlcommon/Cargo.toml2
-rw-r--r--karlcommon/src/protocol.rs20
-rw-r--r--karld/Cargo.toml2
-rw-r--r--karld/protocol.d.ts2
-rw-r--r--karld/src/condition.rs9
-rw-r--r--karld/src/helper.rs98
-rw-r--r--karld/src/main.rs91
-rw-r--r--karld/src/schedule.rs5
12 files changed, 253 insertions, 90 deletions
diff --git a/Cargo.lock b/Cargo.lock
index e233ef1..7b01c0c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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() {
+
+}