Skip to content

Commit

Permalink
Remove usage of chrono in a few places and switch from FixedOffset to…
Browse files Browse the repository at this point in the history
… Utc (serenity-rs#935)
  • Loading branch information
qm3ster authored and arqunis committed Nov 9, 2020
1 parent 4982284 commit c9f935a
Show file tree
Hide file tree
Showing 17 changed files with 120 additions and 110 deletions.
8 changes: 4 additions & 4 deletions examples/e05_command_framework/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ async fn normal_message(_ctx: &Context, msg: &Message) {

#[hook]
async fn dispatch_error(ctx: &Context, msg: &Message, error: DispatchError) {
if let DispatchError::Ratelimited(seconds) = error {
if let DispatchError::Ratelimited(duration) = error {
let _ = msg
.channel_id
.say(&ctx.http, &format!("Try this again in {} seconds.", seconds))
.say(&ctx.http, &format!("Try this again in {} seconds.", duration.as_secs()))
.await;
}
}
Expand All @@ -179,10 +179,10 @@ async fn dispatch_error(ctx: &Context, msg: &Message, error: DispatchError) {
use serenity::{futures::future::BoxFuture, FutureExt};
fn _dispatch_error_no_macro<'fut>(ctx: &'fut mut Context, msg: &'fut Message, error: DispatchError) -> BoxFuture<'fut, ()> {
async move {
if let DispatchError::Ratelimited(seconds) = error {
if let DispatchError::Ratelimited(duration) = error {
let _ = msg
.channel_id
.say(&ctx.http, &format!("Try this again in {} seconds.", seconds))
.say(&ctx.http, &format!("Try this again in {} seconds.", duration.as_secs()))
.await;
};
}.boxed()
Expand Down
5 changes: 3 additions & 2 deletions src/cache/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,7 @@ impl Default for Cache {

#[cfg(test)]
mod test {
use chrono::DateTime;
use chrono::{DateTime, Utc};
use serde_json::{Number, Value};
use std::{
collections::HashMap,
Expand All @@ -994,7 +994,8 @@ mod test {
let datetime = DateTime::parse_from_str(
"1983 Apr 13 12:09:14.274 +0000",
"%Y %b %d %H:%M:%S%.3f %z",
).unwrap();
).unwrap()
.with_timezone(&Utc);
let mut event = MessageCreateEvent {
message: Message {
id: MessageId(3),
Expand Down
9 changes: 6 additions & 3 deletions src/framework/standard/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use crate::model::{

use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;

use tokio::sync::Mutex;
use futures::future::BoxFuture;
Expand All @@ -50,7 +51,7 @@ pub enum DispatchError {
CheckFailed(&'static str, Reason),
/// When the command requester has exceeded a ratelimit bucket. The attached
/// value is the time a requester has to wait to run the command again.
Ratelimited(i64),
Ratelimited(Duration),
/// When the requested command is disabled in bot configuration.
CommandDisabled(String),
/// When the user is blocked in bot configuration.
Expand Down Expand Up @@ -309,8 +310,10 @@ impl StandardFramework {
None => true,
};

if apply && rate_limit > 0 {
return Some(DispatchError::Ratelimited(rate_limit));
if let Some(rate_limit)= rate_limit {
if apply {
return Some(DispatchError::Ratelimited(rate_limit))
}
}
}
}
Expand Down
71 changes: 39 additions & 32 deletions src/framework/standard/structures/buckets.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
use chrono::Utc;
use crate::client::Context;
use crate::model::id::{ChannelId, GuildId, UserId};
use std::collections::HashMap;
use futures::future::BoxFuture;
use std::collections::HashMap;
use std::time::{Duration, Instant};

type Check = for<'fut> fn(&'fut Context, Option<GuildId>, ChannelId, UserId)
-> BoxFuture<'fut, bool>;
type Check =
for<'fut> fn(&'fut Context, Option<GuildId>, ChannelId, UserId) -> BoxFuture<'fut, bool>;

pub(crate) struct Ratelimit {
pub delay: i64,
pub limit: Option<(i64, i32)>,
pub delay: Duration,
pub limit: Option<(Duration, u32)>,
}

#[derive(Default)]
pub(crate) struct MemberRatelimit {
pub last_time: i64,
pub set_time: i64,
pub tickets: i32,
pub last_time: Option<Instant>,
pub set_time: Option<Instant>,
pub tickets: u32,
}

pub(crate) struct Bucket {
Expand All @@ -26,39 +26,46 @@ pub(crate) struct Bucket {
}

impl Bucket {
pub fn take(&mut self, user_id: u64) -> i64 {
let time = Utc::now().timestamp();
let user = self.users
.entry(user_id)
.or_insert_with(MemberRatelimit::default);

if let Some((timespan, limit)) = self.ratelimit.limit {
pub fn take(&mut self, user_id: u64) -> Option<Duration> {
let now = Instant::now();
let Self {
users, ratelimit, ..
} = self;
let user = users.entry(user_id).or_default();

if let Some((timespan, limit)) = ratelimit.limit {
if (user.tickets + 1) > limit {
if time < (user.set_time + timespan) {
return (user.set_time + timespan) - time;
if let Some(res) = user
.set_time
.and_then(|x| now.checked_duration_since(x + timespan))
{
return Some(res);
} else {
user.tickets = 0;
user.set_time = time;
user.set_time = Some(now);
}
}
}

if time < user.last_time + self.ratelimit.delay {
(user.last_time + self.ratelimit.delay) - time
if let Some(res) = user
.last_time
.and_then(|x| now.checked_duration_since(x + ratelimit.delay))
{
return Some(res);
} else {
user.tickets += 1;
user.last_time = time;

0
user.last_time = Some(now);
}

None
}
}

#[derive(Default)]
pub struct BucketBuilder {
pub(crate) delay: i64,
pub(crate) time_span: i64,
pub(crate) limit: i32,
pub(crate) delay: Duration,
pub(crate) time_span: Duration,
pub(crate) limit: u32,
pub(crate) check: Option<Check>,
}

Expand All @@ -67,8 +74,8 @@ impl BucketBuilder {
///
/// Expressed in seconds.
#[inline]
pub fn delay(&mut self, n: i64) -> &mut Self {
self.delay = n;
pub fn delay(&mut self, secs: u64) -> &mut Self {
self.delay = Duration::from_secs(secs);

self
}
Expand All @@ -77,8 +84,8 @@ impl BucketBuilder {
///
/// Expressed in seconds.
#[inline]
pub fn time_span(&mut self, n: i64) -> &mut Self {
self.time_span = n;
pub fn time_span(&mut self, secs: u64) -> &mut Self {
self.time_span = Duration::from_secs(secs);

self
}
Expand All @@ -89,7 +96,7 @@ impl BucketBuilder {
///
/// [`time_span`]: #method.time_span
#[inline]
pub fn limit(&mut self, n: i32) -> &mut Self {
pub fn limit(&mut self, n: u32) -> &mut Self {
self.limit = n;

self
Expand Down
4 changes: 2 additions & 2 deletions src/gateway/ws_client_ext.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use chrono::Utc;
use crate::constants::{self, OpCode};
use crate::gateway::{CurrentPresence, WsStream};
use crate::client::bridge::gateway::GatewayIntents;
Expand All @@ -7,6 +6,7 @@ use crate::internal::ws_impl::SenderExt;
use crate::model::id::GuildId;
use serde_json::json;
use std::env::consts;
use std::time::SystemTime;
use log::{debug, trace};
use async_trait::async_trait;

Expand Down Expand Up @@ -101,7 +101,7 @@ impl WebSocketGatewayClientExt for WsStream {
current_presence: &CurrentPresence,
) -> Result<()> {
let &(ref activity, ref status) = current_presence;
let now = Utc::now().timestamp() as u64;
let now = SystemTime::now();

debug!("[Shard {:?}] Sending presence update", shard_info);

Expand Down
60 changes: 30 additions & 30 deletions src/http/ratelimiting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,11 @@ use std::{
self,
FromStr,
},
time::SystemTime,
i64,
u64,
};
use tokio::time::{Duration, delay_for};
use tokio::time::{delay_for, Duration};
use super::{HttpError, Request};
use log::debug;

Expand Down Expand Up @@ -122,7 +123,9 @@ impl Ratelimiter {
/// let reader = routes.read().await;
///
/// if let Some(route) = reader.get(&Route::ChannelsId(7)) {
/// println!("Reset time at: {}", route.lock().await.reset());
/// if let Some(reset) = route.lock().await.reset() {
/// println!("Reset time at: {:?}", reset);
/// }
/// }
/// # Ok(())
/// # }
Expand Down Expand Up @@ -231,23 +234,20 @@ pub struct Ratelimit {
limit: i64,
/// The number of requests remaining in the period of time.
remaining: i64,
/// The absolute time in milliseconds when the interval resets.
reset: i64,
/// The total time in milliseconds when the interval resets.
reset_after: i64,
/// The absolute time when the interval resets.
reset: Option<SystemTime>,
/// The total time when the interval resets.
reset_after: Option<Duration>,
}

impl Ratelimit {
#[cfg(feature = "absolute_ratelimits")]
fn get_delay(&self) -> i64 {
use chrono::Utc;

let now = Utc::now().timestamp_millis();
self.reset - now
fn get_delay(&self) -> Option<Duration> {
self.reset?.duration_since(SystemTime::now()).ok()
}

#[cfg(not(feature = "absolute_ratelimits"))]
fn get_delay(&self) -> i64 {
fn get_delay(&self) -> Option<Duration> {
self.reset_after
}

Expand All @@ -256,25 +256,25 @@ impl Ratelimit {
return;
}

let delay = self.get_delay();

if delay < 0 {
// We're probably in the past.
self.remaining = self.limit;

return;
}
let delay = match self.get_delay() {
Some(delay) => delay,
None => {
// We're probably in the past.
self.remaining = self.limit;

return;
}
};

if self.remaining() == 0 {
let delay = delay as u64;

debug!(
"Pre-emptive ratelimit on route {:?} for {:?}ms",
"Pre-emptive ratelimit on route {:?} for {}ms",
route,
delay,
delay.as_millis(),
);

delay_for(Duration::from_millis(delay)).await;
delay_for(delay).await;

return;
}
Expand All @@ -292,11 +292,11 @@ impl Ratelimit {
}

if let Some(reset) = parse_header::<f64>(&response.headers(), "x-ratelimit-reset")? {
self.reset = (reset * 1000f64) as i64;
self.reset = Some(std::time::UNIX_EPOCH + Duration::from_secs_f64(reset));
}

if let Some(reset_after) = parse_header::<f64>(&response.headers(), "x-ratelimit-reset-after")? {
self.reset_after = (reset_after * 1000f64) as i64;
self.reset_after = Some(Duration::from_secs_f64(reset_after));
}

Ok(if response.status() != StatusCode::TOO_MANY_REQUESTS {
Expand Down Expand Up @@ -325,13 +325,13 @@ impl Ratelimit {

/// The absolute time in milliseconds when the interval resets.
#[inline]
pub fn reset(&self) -> i64 {
pub fn reset(&self) -> Option<SystemTime> {
self.reset
}

/// The total time in milliseconds when the interval resets.
#[inline]
pub fn reset_after(&self) -> i64 {
pub fn reset_after(&self) -> Option<Duration> {
self.reset_after
}
}
Expand All @@ -341,8 +341,8 @@ impl Default for Ratelimit {
Self {
limit: i64::MAX,
remaining: i64::MAX,
reset: i64::MAX,
reset_after: i64::MAX,
reset: None,
reset_after: None,
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/model/channel/guild_channel.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use chrono::{DateTime, FixedOffset};
use chrono::{DateTime, Utc};
use crate::model::prelude::*;

#[cfg(feature = "cache")]
Expand Down Expand Up @@ -70,7 +70,7 @@ pub struct GuildChannel {
/// The timestamp of the time a pin was most recently made.
///
/// **Note**: This is only available for text channels.
pub last_pin_timestamp: Option<DateTime<FixedOffset>>,
pub last_pin_timestamp: Option<DateTime<Utc>>,
/// The name of the channel.
pub name: String,
/// Permission overwrites for [`Member`]s and for [`Role`]s.
Expand Down
6 changes: 3 additions & 3 deletions src/model/channel/message.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Models relating to Discord channels.

use chrono::{DateTime, FixedOffset};
use chrono::{DateTime, Utc};
use crate::model::prelude::*;
use serde_json::Value;
use std::fmt::Display;
Expand Down Expand Up @@ -62,7 +62,7 @@ pub struct Message {
/// The content of the message.
pub content: String,
/// The timestamp of the last time the message was updated, if it was.
pub edited_timestamp: Option<DateTime<FixedOffset>>,
pub edited_timestamp: Option<DateTime<Utc>>,
/// Array of embeds sent with the message.
pub embeds: Vec<Embed>,
/// The Id of the [`Guild`] that the message was sent in. This value will
Expand Down Expand Up @@ -96,7 +96,7 @@ pub struct Message {
#[serde(default)]
pub reactions: Vec<MessageReaction>,
/// Initial message creation timestamp, calculated from its Id.
pub timestamp: DateTime<FixedOffset>,
pub timestamp: DateTime<Utc>,
/// Indicator of whether the command is to be played back via
/// text-to-speech.
///
Expand Down
Loading

0 comments on commit c9f935a

Please sign in to comment.