aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/condition.rs365
-rw-r--r--src/interface.rs68
-rw-r--r--src/main.rs44
-rw-r--r--src/protocol.rs32
4 files changed, 0 insertions, 509 deletions
diff --git a/src/condition.rs b/src/condition.rs
deleted file mode 100644
index bc1b3ec..0000000
--- a/src/condition.rs
+++ /dev/null
@@ -1,365 +0,0 @@
-use std::cmp::{max, min};
-
-use chrono::{Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Timelike};
-use serde::{Deserialize, Serialize};
-use Direction::*;
-use Edge::*;
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-#[serde(rename_all = "snake_case")]
-pub enum Condition {
- From(Box<Condition>),
-
- Or(Vec<Condition>),
- And(Vec<Condition>),
- Invert(Box<Condition>),
-
- Equal {
- prop: Property,
- value: i64,
- modulus: Option<i64>,
- },
- Range {
- prop: Property,
- min: i64,
- max: i64,
- modulus: Option<i64>,
- },
-}
-
-#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
-#[serde(rename_all = "snake_case")]
-pub enum Property {
- Year,
- Monthofyear,
- Weekofmonth,
- Dayofyear,
- Dayofmonth,
- Dayofweek,
- Hour,
- Minute,
- Second,
- Unix,
-}
-
-#[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,
- End,
-}
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum Direction {
- Forward,
- Backward,
-}
-
-impl Condition {
- pub fn find(
- &self,
- edge: Edge,
- dir: Direction,
- mut from: NaiveDateTime,
- ) -> Option<NaiveDateTime> {
- match self {
- Condition::And(cs) => loop {
- // TODO improve efficiency for backward search
- let last_start = cs
- .iter()
- .map(|c| c.find(Start, dir, from))
- .reduce(|a, b| Some(max(a?, b?)))?;
- let first_end = cs
- .iter()
- .map(|c| c.find(End, dir, from))
- .reduce(|a, b| Some(min(a?, b?)))?;
- match last_start {
- Some(start) => match first_end {
- Some(end) => {
- if end > start {
- break Some(match edge {
- Start => start,
- End => end,
- });
- } else {
- from = start - Duration::seconds(10); // TODO proper fix
- }
- }
- None => break Some(start),
- },
- None => break None,
- }
- },
- Condition::Or(cs) => {
- cs.iter()
- .filter_map(|c| c.find(edge, dir, from))
- .reduce(match dir {
- Forward => min,
- Backward => max,
- })
- }
- Condition::From(_c) => todo!(),
- Condition::Invert(c) => c.find(edge.invert(), dir, from),
- Condition::Equal {
- prop,
- value,
- modulus: _,
- } => {
- let value = *value;
- let off: i64 = match edge {
- Start => 0,
- End => 1,
- };
- let dir_off = match dir {
- Forward => 0,
- Backward => -1,
- };
- match prop {
- Property::Year => {
- let geq = match dir {
- Forward => |a, b| a >= b,
- Backward => |a, b| a < b,
- };
-
- if geq(from.year(), (value + off) as i32) {
- None
- } else {
- Some(NaiveDateTime::new(
- NaiveDate::from_ymd((value + off) as i32, 1, 1),
- NaiveTime::from_hms(0, 0, 0),
- ))
- }
- }
- Property::Monthofyear => {
- let rollover = (value + off) / 12;
- let value = (value + off) % 12;
- // month still coming for this year
- if from.month0() < value as u32 {
- Some(NaiveDateTime::new(
- NaiveDate::from_ymd(
- from.year() + (rollover + dir_off) as i32,
- value as u32 + 1,
- 1,
- ),
- NaiveTime::from_hms(0, 0, 0),
- ))
- } else {
- Some(NaiveDateTime::new(
- NaiveDate::from_ymd(
- from.year() + (rollover + dir_off + 1) as i32,
- value as u32 + 1,
- 1,
- ),
- NaiveTime::from_hms(0, 0, 0),
- ))
- }
- }
- Property::Weekofmonth => todo!(),
- Property::Dayofyear => {
- todo!()
- }
- Property::Dayofmonth => {
- // let mut target = NaiveDateTime::new(
- // NaiveDate::from_ymd(from.year(), from.month(), value as u32),
- // NaiveTime::from_hms(0, 0, 0),
- // );
- // if edge == End {
- // target += Duration::days(1)
- // }
- // fn increment_month(d: NaiveDateTime) -> NaiveDateTime {
- // NaiveDateTime::new(
- // NaiveDate::from_ymd(
- // d.year() + (d.month() as i32 / 12),
- // (d.month() + 1) % 12,
- // d.day(),
- // ),
- // NaiveTime::from_hms(d.hour(), d.minute(), d.second()),
- // )
- // }
- // let dir_off = match dir {
- // Forward => |d| d,
- // Backward => increment_month,
- // };
- // if target > from {
- // Some(dir_off(target))
- // } else {
- // Some(increment_month(dir_off(target)))
- // }
- todo!()
- }
- Property::Dayofweek => todo!(),
- Property::Hour => {
- let mut target = NaiveDateTime::new(
- NaiveDate::from_ymd(from.year(), from.month(), from.day()),
- NaiveTime::from_hms(value as u32, 0, 0),
- );
- if edge == End {
- target += Duration::hours(1)
- }
- let dir_off = match dir {
- Forward => Duration::zero(),
- Backward => Duration::days(-1),
- };
- if target > from {
- Some(target + dir_off)
- } else {
- Some(target + dir_off + Duration::days(1))
- }
- }
- Property::Minute => {
- let mut target = NaiveDateTime::new(
- NaiveDate::from_ymd(from.year(), from.month(), from.day()),
- NaiveTime::from_hms(from.hour(), value as u32, 0),
- );
- if edge == End {
- target += Duration::minutes(1)
- }
- let dir_off = match dir {
- Forward => Duration::zero(),
- Backward => Duration::hours(-1),
- };
- if target > from {
- Some(target + dir_off)
- } else {
- Some(target + dir_off + Duration::hours(1))
- }
- }
- Property::Second => {
- let mut target = NaiveDateTime::new(
- NaiveDate::from_ymd(from.year(), from.month(), from.day()),
- NaiveTime::from_hms(from.hour(), from.minute(), value as u32),
- );
- if edge == End {
- target += Duration::seconds(1)
- }
- let dir_off = match dir {
- Forward => Duration::zero(),
- Backward => Duration::minutes(-1),
- };
- if target > from {
- Some(target + dir_off)
- } else {
- Some(target + dir_off + Duration::minutes(1))
- }
- }
- Property::Unix => {
- let geq = match dir {
- Forward => |a, b| a >= b,
- Backward => |a, b| a < b,
- };
- if geq(from.timestamp(), (value + off) as i64) {
- None
- } else {
- Some(NaiveDateTime::from_timestamp(value, 0))
- }
- }
- }
- }
- Condition::Range {
- prop: _,
- min: _,
- max: _,
- modulus: _,
- } => todo!(),
- }
- }
-}
-
-impl Edge {
- pub fn invert(self) -> Self {
- match self {
- Edge::Start => Edge::End,
- Edge::End => Edge::Start,
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::{Condition, Direction, Edge, Property};
- use chrono::{NaiveDateTime, Utc};
- use std::str::FromStr;
- use Direction::*;
- use Edge::*;
-
- #[test]
- fn blub() {
- let cond = Condition::And(vec![
- Condition::Equal {
- modulus: None,
- prop: Property::Monthofyear,
- value: 1,
- },
- Condition::Equal {
- modulus: None,
- prop: Property::Hour,
- value: 12,
- },
- ]);
- // let cond = Condition::Equal {
- // modulus: None,
- // prop: Property::Hour,
- // value: 12,
- // };
- let dt = Utc::now().naive_utc();
- println!("START FORWARD => {:?}", cond.find(Start, Forward, dt));
- println!("END FORWARD => {:?}", cond.find(End, Forward, dt));
- println!("START BACKWARD => {:?}", cond.find(Start, Backward, dt));
- println!("END BACKWARD => {:?}", cond.find(End, Backward, dt));
- }
-
- #[test]
- fn year_equal() {
- let cond = Condition::Equal {
- modulus: None,
- prop: Property::Year,
- value: 2023,
- };
-
- let dt = NaiveDateTime::from_str("2022-06-07T13:37:48").unwrap();
- assert_eq!(
- cond.find(Edge::Start, Direction::Forward, dt).unwrap(),
- NaiveDateTime::from_str("2023-01-01T00:00:00").unwrap(),
- );
- assert_eq!(
- cond.find(Edge::End, Direction::Forward, dt).unwrap(),
- NaiveDateTime::from_str("2024-01-01T00:00:00").unwrap(),
- );
- assert_eq!(cond.find(Edge::End, Direction::Backward, dt), None);
- assert_eq!(cond.find(Edge::Start, Direction::Backward, dt), None);
- }
-
- #[test]
- fn month_equal() {
- let cond = Condition::Equal {
- modulus: None,
- prop: Property::Monthofyear,
- value: 3,
- };
-
- let dt = NaiveDateTime::from_str("2022-06-07T13:37:48").unwrap();
-
- assert_eq!(
- cond.find(Edge::Start, Direction::Forward, dt),
- Some(NaiveDateTime::from_str("2023-04-01T00:00:00").unwrap())
- );
- assert_eq!(
- cond.find(Edge::End, Direction::Forward, dt),
- Some(NaiveDateTime::from_str("2023-05-01T00:00:00").unwrap())
- );
- assert_eq!(
- cond.find(Edge::Start, Direction::Backward, dt),
- Some(NaiveDateTime::from_str("2022-04-01T00:00:00").unwrap())
- );
- assert_eq!(
- cond.find(Edge::End, Direction::Backward, dt),
- Some(NaiveDateTime::from_str("2022-05-01T00:00:00").unwrap())
- );
- }
-}
diff --git a/src/interface.rs b/src/interface.rs
deleted file mode 100644
index fcdb470..0000000
--- a/src/interface.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-use super::protocol::{ClientboundPacket, ServerboundPacket};
-use crate::handle_packet;
-use log::{debug, error, info, warn};
-use std::io;
-use std::io::{BufRead, BufReader, ErrorKind, Write};
-use std::os::unix::net::{UnixListener, UnixStream};
-use std::thread;
-
-pub fn network_loop() {
- let listener = UnixListener::bind("/run/user/1000/calendar").unwrap();
- let mut id_counter = 0;
-
- loop {
- let (stream, addr) = listener.accept().unwrap();
- let id = id_counter;
- id_counter += 1;
- thread::spawn(move || {
- info!("client connected: {:?}", addr);
- if let Err(err) = handle_connection(id, stream.try_clone().unwrap()) {
- warn!("client dropped: {:?} ({})", addr, err);
- } else {
- info!("client dropped: {:?}", addr);
- }
- });
- }
-}
-
-fn handle_connection(id: u32, mut stream: UnixStream) -> io::Result<()> {
- let mut reader = BufReader::new(stream.try_clone()?);
- let (responder, responses) = crossbeam_channel::unbounded();
- responder
- .send(ClientboundPacket::Handshake {
- version: env!("CARGO_PKG_VERSION").to_string(),
- })
- .unwrap();
- thread::spawn(move || {
- for m in responses {
- debug!("{id} -> {m:?}");
- match stream
- .write_fmt(format_args!("{}\n", serde_json::to_string(&m).unwrap()))
- .map_err(|e| e.kind())
- {
- Ok(_) => (),
- Err(ErrorKind::BrokenPipe) => break,
- Err(e) => error!("network error: {:?}", e),
- }
- }
- });
- {
- let mut buf = String::new();
- loop {
- if reader.read_line(&mut buf)? == 0 {
- break Ok(());
- };
- match serde_json::from_str::<ServerboundPacket>(buf.as_str()) {
- Ok(packet) => {
- debug!("{id} <- {packet:?}");
- handle_packet(id, packet, responder.clone());
- }
- Err(err) => responder
- .send(ClientboundPacket::Error(format!("{}", &err)))
- .map_err(|_| io::Error::from(ErrorKind::InvalidInput))?,
- }
-
- buf.clear();
- }
- }
-}
diff --git a/src/main.rs b/src/main.rs
deleted file mode 100644
index 9a84286..0000000
--- a/src/main.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-pub mod condition;
-pub mod interface;
-pub mod protocol;
-
-use crate::{
- condition::{Condition, Property},
- protocol::Task,
-};
-use crossbeam_channel::Sender;
-use interface::network_loop;
-use protocol::{ClientboundPacket, ServerboundPacket};
-
-fn main() {
- network_loop();
-}
-
-pub fn handle_packet(client: u32, packet: ServerboundPacket, responder: Sender<ClientboundPacket>) {
- println!("{:?}, {:?}, {:?}", client, packet, responder);
- match packet {
- ServerboundPacket::Download => {
- let _ = responder.send(ClientboundPacket::DownloadResponse(vec![Task {
- name: "blub".to_string(),
- description: "blob".to_string(),
- tags: vec![],
- priority: 69.0,
- completed: None,
- scheduled: None,
- occurence: Some(Condition::And(vec![
- Condition::Equal {
- modulus: None,
- prop: Property::Monthofyear,
- value: 1,
- },
- Condition::Equal {
- modulus: None,
- prop: Property::Hour,
- value: 12,
- },
- ])),
- deadline: None,
- }]));
- }
- }
-}
diff --git a/src/protocol.rs b/src/protocol.rs
deleted file mode 100644
index af89263..0000000
--- a/src/protocol.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-use serde::{Deserialize, Serialize};
-
-use crate::condition::Condition;
-
-#[derive(Debug, Serialize, Deserialize)]
-#[serde(tag = "type", content = "data", rename_all = "snake_case")]
-pub enum ClientboundPacket {
- Handshake { version: String },
- Error(String),
- DownloadResponse(Vec<Task>),
-}
-
-#[derive(Debug, Serialize, Deserialize)]
-#[serde(tag = "type", content = "data", rename_all = "snake_case")]
-pub enum ServerboundPacket {
- Download,
-}
-
-#[derive(Debug, Serialize, Deserialize)]
-pub struct Task {
- pub name: String,
- pub description: String,
-
- pub tags: Vec<String>,
- pub priority: f64,
-
- pub completed: Option<u64>,
- pub scheduled: Option<u64>,
-
- pub occurence: Option<Condition>,
- pub deadline: Option<Condition>,
-}