From 27e68e4b0d6b6bf3d05166e6d6a68d56ff5a0704 Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Fri, 13 Nov 2020 15:20:09 +0100 Subject: update dependencies This is a bit bigger than usual, because it brings the serenity update from 0.8.x to 0.9 with a lot of API changes. The biggest offender is the new async environment, which means that we need to sprinkle some .awaits here and there, as well as use tokio to spawn a runtime. Serenity currently uses tokio 0.2, so we need to stick to the older version until serenity updates, otherwise we'll get a runtime mismatch. Another small change comes from serenity switching to typemap_rev[1] instead of their old implementation, which is currently still missing some methods. Until those are implemented[2], we're patching the dependency directly. The good news is that all of the changes are pretty much contained to src/discord.rs only, as the other parts of ezau could stay untouched. [1]: https://github.com/bdashore3/typemap_rev [2]: https://github.com/bdashore3/typemap_rev/pull/1 --- src/discord.rs | 74 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/discord.rs b/src/discord.rs index 839b1c8..976b2d6 100644 --- a/src/discord.rs +++ b/src/discord.rs @@ -6,6 +6,7 @@ use evtclib::{Log, Outcome}; use serenity::client::bridge::gateway::ShardManager; use serenity::model::id::*; use serenity::prelude::*; +use tokio::runtime::Runtime; use log::info; @@ -34,61 +35,78 @@ struct Handler { } impl Handler { - fn do_link_update(&self, ctx: &Context) -> Result<()> { - let mut messages = ChannelId(self.channel_id).messages(&ctx, |r| r.limit(25))?; + async fn do_link_update(&self, ctx: &Context) -> Result<()> { + let mut messages = ChannelId(self.channel_id) + .messages(&ctx, |r| r.limit(25)) + .await?; messages.sort_by_key(|m| m.timestamp); - messages.retain(|m| { - m.is_own(ctx) - && Utc::now().signed_duration_since(m.timestamp) - < chrono::Duration::hours(MAX_HOURS) - }); + + // Retain does not work with async predicates, so we have to do it the old-fashioned way. + // This is slower than a proper implementation because we do more element shifts than + // needed, but it is also the easiest way to implement it and shouldn't matter for the 25 + // messages that we load. + let mut i = 0; + while i < messages.len() { + let is_good = messages[i].is_own(ctx).await + && Utc::now().signed_duration_since(messages[i].timestamp) + < chrono::Duration::hours(MAX_HOURS); + if is_good { + i += 1; + } else { + messages.remove(i); + } + } if let Some(mut m) = messages.pop() { let new_text = insert_link(&m.content, &self.log, &self.link); if new_text.len() <= MAX_MESSAGE_LENGTH { - m.edit(ctx, |m| m.content(new_text))?; + m.edit(ctx, |m| m.content(new_text)).await?; return Ok(()); } } let new_text = insert_link("", &self.log, &self.link); - ChannelId(self.channel_id).say(ctx, new_text)?; + ChannelId(self.channel_id).say(ctx, new_text).await?; Ok(()) } } +#[serenity::async_trait] impl EventHandler for Handler { - fn ready(&self, ctx: Context, _ready: serenity::model::gateway::Ready) { + async fn ready(&self, ctx: Context, _ready: serenity::model::gateway::Ready) { info!("Discord client is ready"); - let result = self.do_link_update(&ctx); + let result = self.do_link_update(&ctx).await; - let mut data = ctx.data.write(); + let mut data = ctx.data.write().await; data.insert::(result); if let Some(manager) = data.get::() { - manager.lock().shutdown_all(); + manager.lock().await.shutdown_all().await; } } } pub fn post_link(discord_token: &str, channel_id: u64, log: Log, link: String) -> Result<()> { - let mut client = Client::new( - discord_token, - Handler { - channel_id, - log, - link, - }, - )?; - { - let mut data = client.data.write(); - data.insert::(Arc::clone(&client.shard_manager)); - } - client.start()?; + let mut rt = Runtime::new()?; + + rt.block_on(async { + let mut client = Client::builder(discord_token) + .event_handler(Handler { + channel_id, + log, + link, + }) + .await?; + { + let mut data = client.data.write().await; + data.insert::(Arc::clone(&client.shard_manager)); + } + client.start().await?; - let mut data = client.data.write(); - data.remove::().unwrap_or(Ok(())) + let mut data = client.data.write().await; + data.remove::().unwrap_or(Ok(())) + }) } fn find_insertion(text: &str, category: &str) -> Option { -- cgit v1.2.3