aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2021-12-04 20:37:59 -0700
committerMelody Horn <melody@boringcactus.com>2021-12-04 20:37:59 -0700
commitfffdc8aab1086eb60bc9537fafb725ba876c46f2 (patch)
tree2eb9e64cbda93847aa8f0ee8e233bef137a2a237 /src
parentdef3018a26189fdf56f9776f8b7c06ea681f0577 (diff)
downloadqueue-go-brrr-fffdc8aab1086eb60bc9537fafb725ba876c46f2.tar.gz
queue-go-brrr-fffdc8aab1086eb60bc9537fafb725ba876c46f2.zip
slightly improve ETA calculation
Diffstat (limited to 'src')
-rw-r--r--src/history.rs64
1 files changed, 43 insertions, 21 deletions
diff --git a/src/history.rs b/src/history.rs
index f8ffec2..6031499 100644
--- a/src/history.rs
+++ b/src/history.rs
@@ -1,6 +1,7 @@
// god is dead and we have killed him and consequently std::time::Instant doesn't work on wasm
use chrono::prelude::*;
+use chrono::Duration;
use wasm_bindgen::prelude::*;
struct Reading {
@@ -18,36 +19,57 @@ pub enum NoETA {
Fuck,
}
+// Duration doesn't impl Mul<f32> so we have to do percents
+const RECENCY_PERCENT: i32 = 20;
+
impl History {
pub fn record(&mut self, queue_size: u32) {
- self.data.push(Reading {
- time: Local::now(),
- queue_size,
- });
+ let redundant = match self.data.last() {
+ Some(last) => queue_size == last.queue_size,
+ None => false,
+ };
+ if !redundant {
+ self.data.push(Reading {
+ time: Local::now(),
+ queue_size,
+ });
+ }
}
pub fn completion_time(&self) -> Result<js_sys::Date, NoETA> {
- // TODO make this not suck
- let &Reading {
- time: first_time,
- queue_size: first_size,
- ..
- } = self.data.first().ok_or(NoETA::Pending)?;
+ let weighted_average_step_time = self
+ .data
+ .iter()
+ .zip(self.data.iter().skip(1))
+ .map(|(one, two)| {
+ // queue velocity should ideally be measured in distance per time,
+ // but the units wind up fucky (reciprocal duration not implemented)
+ // so instead we use time per distance
+ if one.time > two.time {
+ return Err(NoETA::Fuck);
+ }
+ let delta_time = two.time - one.time;
+ let delta_queue = match one.queue_size.checked_sub(two.queue_size) {
+ Some(d) => d,
+ None => return Err(NoETA::Fuck),
+ };
+ Ok(delta_time / delta_queue as i32)
+ })
+ .reduce(|previous, current| match (previous, current) {
+ (Ok(previous), Ok(current)) => {
+ let previous_term = previous * (100 - RECENCY_PERCENT) / 100;
+ let current_term = current * RECENCY_PERCENT / 100;
+ Ok(previous_term + current_term)
+ }
+ (Err(e), _) => Err(e),
+ (_, Err(e)) => Err(e),
+ })
+ .ok_or(NoETA::Pending)??;
let &Reading {
time: last_time,
queue_size: last_size,
} = self.data.last().ok_or(NoETA::Pending)?;
- let overall_time_elapsed = last_time - first_time;
- if overall_time_elapsed.is_zero() {
- return Err(NoETA::Pending);
- }
- let overall_queue_motion = match first_size.checked_sub(last_size) {
- Some(0) => return Err(NoETA::Pending),
- Some(x) => x,
- None => return Err(NoETA::Fuck),
- };
- let duration_per_step = overall_time_elapsed / overall_queue_motion as i32;
- let remaining_duration = duration_per_step * last_size as i32;
+ let remaining_duration = weighted_average_step_time * last_size as i32;
let completion_time = last_time + remaining_duration;
let completion_time_gmt = completion_time.timestamp_millis();
Ok(js_sys::Date::new(&JsValue::from(