guzzles data
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 88 |
1 files changed, 81 insertions, 7 deletions
diff --git a/src/main.rs b/src/main.rs index c92aa9b..4f4342d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,89 @@ use anyhow::Result; +use chrono::{DateTime, Datelike, TimeZone, Utc}; use emoji::named::*; use poise::serenity_prelude::*; use serenity::futures::StreamExt; use std::fs::read_to_string; use std::io::Write; +use std::ops::{Deref, Sub}; type Context<'a> = poise::Context<'a, (), anyhow::Error>; + +#[derive(poise::ChoiceParameter, Default, Copy, Clone, Debug)] +enum Period { + #[name = "all time"] + #[default] + AllTime, + #[name = "year"] + LastYear, + #[name = "month"] + LastMonth, + #[name = "week"] + LastWeek, +} + +struct Days(usize); + +impl Deref for Days { + type Target = usize; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Sub<usize> for Days { + type Output = Days; + + fn sub(self, rhs: usize) -> Self::Output { + Self(self.0 - rhs) + } +} + +impl Days { + fn t(self) -> DateTime<Utc> { + Utc.timestamp_millis_opt(((*self as i64 * (60 * 60 * 24) as i64) + 1420070400) * 1000) + .single() + .unwrap() + } + + fn now() -> Self { + Self::from(Utc::now().timestamp() as usize) + } +} + +impl From<usize> for Days { + fn from(value: usize) -> Self { + Self((value - 1420070400) / (60 * 60 * 24)) + } +} + +impl Period { + fn from(self) -> Days { + match self { + Self::AllTime => Days(0), + Self::LastYear => Days::now() - 365, + Self::LastMonth => Days::now() - 30, + Self::LastWeek => Days::now() - 7, + } + } + + fn tic(self, t: Days) -> bool { + match self { + Self::LastYear | Self::AllTime => t.t().day() == 1, + Self::LastMonth => t.t().day() % 7 == 0, + Self::LastWeek => true, + } + } +} + #[poise::command(slash_command)] -pub async fn users(c: Context<'_>) -> Result<()> { +/// graph of users over time +pub async fn users( + c: Context<'_>, + #[description = "time period to graph (defaults to all time)"] period: Option<Period>, +) -> Result<()> { c.defer().await?; + let p = period.unwrap_or_default(); let g = { let Some(g) = c.guild() else { _ = c.reply(format!("{CANCEL} need guild")); @@ -21,23 +97,21 @@ pub async fn users(c: Context<'_>) -> Result<()> { let mut max = 0; while let Some(x) = s.next().await { let x = x?.joined_at.unwrap(); - let d = (x.timestamp() as usize - 1420070400) / (60 * 60 * 24); + let d = *Days::from(x.timestamp() as usize); min = min.min(d); max = max.max(d); data[d] += 1; } + let min = min.max(*p.from()); let mut f = std::fs::File::create("1.dat").unwrap(); let mut sum = 0; for (i, &d) in data[min..max].iter().enumerate() { sum += d; - let t = - Timestamp::from_unix_timestamp(((i + min) as i64 * (60 * 60 * 24) as i64) + 1420070400) - .unwrap(); writeln!( &mut f, r"{},{sum}", - if t.format("%d").to_string() == "01" { - t.format("%m/%d/%y").to_string() + if p.tic(Days(i + min)) { + Days(i + min).t().format("%m/%d/%y").to_string() } else { "".to_string() } |