time parser struct

This commit is contained in:
jude 2020-09-01 15:34:50 +01:00
parent c1a4092e3c
commit 74617d50a5
5 changed files with 166 additions and 42 deletions

View File

@ -72,7 +72,12 @@ async fn clock(ctx: &Context, msg: &Message, args: String) -> CommandResult {
let now = Utc::now().with_timezone(&tz); let now = Utc::now().with_timezone(&tz);
if args == "12".to_string() {
let _ = msg.channel_id.say(&ctx, format!("Current time: **{}**", now.format("%I:%M:%S %p"))).await;
}
else {
let _ = msg.channel_id.say(&ctx, format!("Current time: **{}**", now.format("%H:%M:%S"))).await; let _ = msg.channel_id.say(&ctx, format!("Current time: **{}**", now.format("%H:%M:%S"))).await;
}
Ok(()) Ok(())
} }

View File

@ -22,6 +22,7 @@ use crate::{
}, },
SQLPool, SQLPool,
framework::SendFromDb, framework::SendFromDb,
time_parser::TimeParser,
}; };
lazy_static! { lazy_static! {
@ -143,15 +144,3 @@ async fn prefix(ctx: &Context, msg: &Message, args: String) -> CommandResult {
Ok(()) Ok(())
} }
#[command]
async fn pause(ctx: &Context, msg: &Message, args: String) -> CommandResult {
let pool = ctx.data.read().await
.get::<SQLPool>().cloned().expect("Could not get SQLPool from data");
let channel = ChannelData::from_channel(msg.channel(&ctx).await.unwrap(), pool.clone()).await.unwrap();
channel.commit_changes(pool).await;
Ok(())
}

View File

@ -0,0 +1,73 @@
use regex_command_attr::command;
use serenity::{
client::Context,
model::{
channel::{
Message,
},
},
framework::standard::CommandResult,
};
use chrono_tz::{
Tz,
Etc::UTC,
};
use crate::{
models::{
ChannelData,
UserData,
},
SQLPool,
framework::SendFromDb,
time_parser::TimeParser,
};
use chrono::NaiveDateTime;
#[command]
async fn pause(ctx: &Context, msg: &Message, args: String) -> CommandResult {
let pool = ctx.data.read().await
.get::<SQLPool>().cloned().expect("Could not get SQLPool from data");
let user_data = UserData::from_id(&msg.author, &ctx, pool.clone()).await.unwrap();
let mut channel = ChannelData::from_channel(msg.channel(&ctx).await.unwrap(), pool.clone()).await.unwrap();
if args.len() == 0 {
channel.paused = !channel.paused;
channel.paused_until = None;
channel.commit_changes(pool).await;
if channel.paused {
let _ = msg.channel_id.say_named(&ctx, user_data.language, "paused/paused_indefinite").await;
}
else {
let _ = msg.channel_id.say_named(&ctx, user_data.language, "paused/unpaused").await;
}
}
else {
let parser = TimeParser::new(args, user_data.timezone.parse().unwrap());
let pause_until = parser.timestamp();
match pause_until {
Ok(timestamp) => {
channel.paused = true;
channel.paused_until = Some(NaiveDateTime::from_timestamp(timestamp, 0));
channel.commit_changes(pool).await;
let _ = msg.channel_id.say_named(&ctx, user_data.language, "paused/paused_until").await;
},
Err(_) => {
let _ = msg.channel_id.say_named(&ctx, user_data.language, "paused/invalid_time").await;
},
}
}
Ok(())
}

View File

@ -65,7 +65,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
.add_command("todo", &todo_cmds::TODO_PARSE_COMMAND) .add_command("todo", &todo_cmds::TODO_PARSE_COMMAND)
.add_command("blacklist", &moderation_cmds::BLACKLIST_COMMAND) .add_command("blacklist", &moderation_cmds::BLACKLIST_COMMAND)
.add_command("timezone", &moderation_cmds::TIMEZONE_COMMAND) .add_command("timezone", &moderation_cmds::TIMEZONE_COMMAND)
.add_command("language", &moderation_cmds::LANGUAGE_COMMAND) .add_command("lang", &moderation_cmds::LANGUAGE_COMMAND)
.add_command("pause", &reminder_cmds::PAUSE_COMMAND)
.build(); .build();
let mut client = Client::new(&env::var("DISCORD_TOKEN").expect("Missing DISCORD_TOKEN from environment")) let mut client = Client::new(&env::var("DISCORD_TOKEN").expect("Missing DISCORD_TOKEN from environment"))

View File

@ -3,16 +3,38 @@ use std::time::{
UNIX_EPOCH, UNIX_EPOCH,
}; };
use std::fmt::{
Formatter,
Display,
Result as FmtResult,
};
use chrono_tz::Tz; use chrono_tz::Tz;
use chrono::offset::Utc; use chrono::offset::Utc;
use chrono::{Timelike, Datelike, TimeZone}; use chrono::{Timelike, Datelike, TimeZone};
#[derive(Debug)]
pub enum InvalidTime {
ParseErrorDMY,
ParseErrorHMS,
ParseErrorDisplacement,
ParseErrorChrono,
}
impl Display for InvalidTime {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "InvalidTime: {:?}", self)
}
}
impl std::error::Error for InvalidTime {}
enum ParseType { enum ParseType {
Explicit, Explicit,
Displacement, Displacement,
} }
struct TimeParser { pub struct TimeParser {
timezone: Tz, timezone: Tz,
inverted: bool, inverted: bool,
time_string: String, time_string: String,
@ -43,19 +65,10 @@ impl TimeParser {
} }
} }
pub fn timestamp(&self) -> i32 { pub fn timestamp(&self) -> Result<i64, InvalidTime> {
0
}
pub fn displacement(&self) -> i32 {
0
}
fn process(&self) -> i32 {
match self.parse_type { match self.parse_type {
ParseType::Explicit => { ParseType::Explicit => {
// TODO remove unwrap from here Ok(self.process_explicit()?)
self.process_explicit().unwrap()
}, },
ParseType::Displacement => { ParseType::Displacement => {
@ -64,45 +77,88 @@ impl TimeParser {
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
.expect("Time calculated as going backwards. Very bad"); .expect("Time calculated as going backwards. Very bad");
since_epoch.as_secs() as i32 + self.process_displacement() Ok(since_epoch.as_secs() as i64 + self.process_displacement()?)
}, },
} }
} }
fn process_explicit(&self) -> Result<i32, Box<dyn std::error::Error>> { pub fn displacement(&self) -> Result<i64, InvalidTime> {
let dt = self.timezone.datetime_from_str(self.time_string.as_str(), "%d/%m/%Y-%H:%M:%S")?; match self.parse_type {
ParseType::Explicit => {
let now = SystemTime::now();
let since_epoch = now
.duration_since(UNIX_EPOCH)
.expect("Time calculated as going backwards. Very bad");
Ok(dt.timestamp() as i32) Ok(self.process_explicit()? - since_epoch.as_secs() as i64)
},
ParseType::Displacement => {
Ok(self.process_displacement()?)
},
}
} }
fn process_displacement(&self) -> i32 {
fn process_explicit(&self) -> Result<i64, InvalidTime> {
let segments = self.time_string.matches("-").count();
let parse_string = if segments == 1 {
let slashes = self.time_string.matches("/").count();
match slashes {
0 => Ok("%d-".to_string()),
1 => Ok("%d/%m-".to_string()),
2 => Ok("%d/%m/%Y-".to_string()),
_ => Err(InvalidTime::ParseErrorDMY)
}
} else {
Ok("".to_string())
}? + if segments == 1 {
let colons = self.time_string.matches(":").count();
match colons {
1 => Ok("%H:%M"),
2 => Ok("%H:%M:%S"),
_ => Err(InvalidTime::ParseErrorHMS)
}
} else {
Ok("")
}?;
let dt = self.timezone.datetime_from_str(self.time_string.as_str(), &parse_string).map_err(|_| InvalidTime::ParseErrorChrono)?;
Ok(dt.timestamp() as i64)
}
fn process_displacement(&self) -> Result<i64, InvalidTime> {
let mut current_buffer = "0".to_string(); let mut current_buffer = "0".to_string();
let mut seconds = 0 as i32; let mut seconds = 0 as i64;
let mut minutes = 0 as i32; let mut minutes = 0 as i64;
let mut hours = 0 as i32; let mut hours = 0 as i64;
let mut days = 0 as i32; let mut days = 0 as i64;
for character in self.time_string.chars() { for character in self.time_string.chars() {
match character { match character {
's' => { 's' => {
seconds = current_buffer.parse::<i32>().unwrap(); seconds = current_buffer.parse::<i64>().unwrap();
current_buffer = String::from("0"); current_buffer = String::from("0");
}, },
'm' => { 'm' => {
minutes = current_buffer.parse::<i32>().unwrap(); minutes = current_buffer.parse::<i64>().unwrap();
current_buffer = String::from("0"); current_buffer = String::from("0");
}, },
'h' => { 'h' => {
hours = current_buffer.parse::<i32>().unwrap(); hours = current_buffer.parse::<i64>().unwrap();
current_buffer = String::from("0"); current_buffer = String::from("0");
}, },
'd' => { 'd' => {
days = current_buffer.parse::<i32>().unwrap(); days = current_buffer.parse::<i64>().unwrap();
current_buffer = String::from("0"); current_buffer = String::from("0");
}, },
@ -111,15 +167,15 @@ impl TimeParser {
current_buffer += &c.to_string(); current_buffer += &c.to_string();
} }
else { else {
// raise exception return Err(InvalidTime::ParseErrorDisplacement)
} }
}, },
} }
} }
let full = seconds + (minutes * 60) + (hours * 3600) + (days * 86400) + current_buffer.parse::<i32>().unwrap() * let full = seconds + (minutes * 60) + (hours * 3600) + (days * 86400) + current_buffer.parse::<i64>().unwrap() *
if self.inverted { -1 } else { 1 }; if self.inverted { -1 } else { 1 };
full Ok(full)
} }
} }