nari/models/
event.rs

1use std::{
2    collections::{BTreeMap, HashSet},
3    fs::File,
4    io::{BufReader, Read},
5    path::Path,
6    sync::{Arc, Mutex},
7    time::{SystemTime, UNIX_EPOCH},
8};
9
10use file_lock::{FileLock, FileOptions};
11use notify::{event::ModifyKind::Data, EventKind, RecommendedWatcher, Watcher};
12use serde::{Deserialize, Serialize};
13use tokio::{
14    sync::mpsc,
15    time::{interval, Duration},
16};
17
18use super::{Database, EventId, UserId};
19
20#[derive(Debug, Serialize, Deserialize, Clone)]
21pub struct Event {
22    pub id: EventId,
23    pub name: String,
24    pub description: String,
25    pub next_occurence: u64,
26    pub users: HashSet<UserId>,
27    pub repeats: Repeatability,
28    pub priority: Priority,
29}
30impl Event {
31    pub fn save_to_db(self, db: &Database) {
32        db.add_event(self);
33    }
34}
35impl PartialEq for Event {
36    fn eq(&self, other: &Self) -> bool {
37        self.id == other.id
38    }
39}
40impl Eq for Event {}
41
42#[derive(Debug, Default, Serialize, Deserialize, Clone)]
43pub enum Repeatability {
44    Yearly,
45    Biyearly,
46    Quarterly,
47    Monthly,
48    Bimonthly,
49    Weekly,
50    Daily,
51    Hourly,
52    #[default]
53    Never,
54}
55
56#[derive(Debug, Default, Serialize, Deserialize, Clone)]
57pub enum Priority {
58    Urgent,
59    VeryHigh,
60    High,
61    Medium,
62    #[default]
63    Low,
64    Minimal,
65}
66
67#[derive(Debug, Default)]
68pub struct EventBuilder {
69    id: EventId,
70    name: String,
71    description: String,
72    next_occurence: u64,
73    users: HashSet<UserId>,
74    repeats: Repeatability,
75    priority: Priority,
76}
77impl EventBuilder {
78    pub fn new(id: EventId, name: &str, next_occurence: u64) -> Self {
79        Self {
80            id,
81            name: String::from(name),
82            next_occurence,
83            ..Self::default()
84        }
85    }
86    pub fn description(mut self, desc: &str) -> Self {
87        self.description = String::from(desc);
88        self
89    }
90    pub fn users<I>(mut self, users: I) -> Self
91    where
92        I: IntoIterator<Item = UserId>,
93    {
94        for user in users {
95            self.users.insert(user);
96        }
97        self
98    }
99    pub fn repeats(mut self, repeats: Repeatability) -> Self {
100        self.repeats = repeats;
101        self
102    }
103    pub fn priority(mut self, priority: Priority) -> Self {
104        self.priority = priority;
105        self
106    }
107    pub fn build(self) -> Event {
108        Event {
109            id: self.id,
110            name: self.name,
111            description: self.description,
112            next_occurence: self.next_occurence,
113            users: self.users,
114            repeats: self.repeats,
115            priority: self.priority,
116        }
117    }
118}
119#[non_exhaustive]
120#[derive(Debug)]
121pub struct EventListener {
122    sender: mpsc::Sender<Event>,
123    refresh_rate: u64,
124}
125impl EventListener {
126    pub fn new(sender: mpsc::Sender<Event>, refresh_rate: u64) -> Self {
127        Self {
128            sender,
129            refresh_rate,
130        }
131    }
132    pub async fn start(self) {
133        // this may look dirty, cuz it is, please send help, i am not fit for this
134        let options = FileOptions::new().read(true).write(true).create(true);
135        let mut filelock = FileLock::lock("./db/event_cache.ron", true, options).unwrap();
136        let mut bytes = vec![];
137        filelock.file.read_to_end(&mut bytes).unwrap();
138        let event_cache: BTreeMap<u64, u64> = ron::de::from_bytes(&bytes).unwrap();
139        let event_cache = Arc::new(Mutex::new(event_cache));
140        let copy = Arc::clone(&event_cache);
141
142        let _watcher = tokio::spawn(async move {
143            let event_cache = Arc::clone(&event_cache);
144
145            let (tx, rx) = std::sync::mpsc::channel();
146            let mut w = RecommendedWatcher::new(tx, notify::Config::default()).unwrap();
147            w.watch(
148                Path::new("./db/event_cache.ron"),
149                notify::RecursiveMode::Recursive,
150            )
151            .unwrap();
152            while let Ok(f_ev) = rx.recv() {
153                if let Ok(file_event) = f_ev {
154                    match file_event.kind {
155                        EventKind::Modify(Data(_)) => {
156                            let options = FileOptions::new().read(true).write(true).create(true);
157                            let mut filelock =
158                                FileLock::lock("./db/event_cache.ron", true, options).unwrap();
159                            let mut bytes = vec![];
160                            filelock.file.read_to_end(&mut bytes).unwrap();
161                            let mut event_cache = event_cache.lock().unwrap();
162                            *event_cache =
163                                ron::de::from_bytes::<BTreeMap<u64, u64>>(&bytes).unwrap();
164                        }
165                        _ => (),
166                    }
167                }
168            }
169        });
170        let mut interval = interval(Duration::from_millis(self.refresh_rate));
171        let mut ids: Vec<u64> = vec![];
172        loop {
173            let now = SystemTime::now()
174                .duration_since(UNIX_EPOCH)
175                .unwrap()
176                .as_secs();
177            if Self::has_passed_event(now, &copy.lock().unwrap()) {
178                let mut lock = copy.lock().unwrap();
179                for (_, id) in lock.range(..now) {
180                    ids.push(*id);
181                }
182                lock.retain(|k, _| *k >= now);
183                let writer = File::create("./db/event_cache.ron").unwrap();
184                ron::ser::to_writer(writer, &*lock).unwrap();
185                drop(lock);
186            }
187            if !ids.is_empty() {
188                for id in &ids {
189                    let buf = BufReader::new(File::open(format!("./db/events/{id}.ron")).unwrap());
190                    let e: Event = ron::de::from_reader(buf).unwrap();
191                    self.sender.send(e.clone()).await.unwrap();
192                }
193                ids.clear();
194            }
195            interval.tick().await;
196        }
197    }
198    fn has_passed_event(now: u64, events: &BTreeMap<u64, u64>) -> bool {
199        if let Some((k, _)) = events.first_key_value() {
200            *k <= now
201        } else {
202            false
203        }
204    }
205}