aboutsummaryrefslogtreecommitdiff
path: root/src/commands/meme/history.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/commands/meme/history.rs')
-rw-r--r--src/commands/meme/history.rs216
1 files changed, 115 insertions, 101 deletions
diff --git a/src/commands/meme/history.rs b/src/commands/meme/history.rs
index 5e200b1..ed50e27 100644
--- a/src/commands/meme/history.rs
+++ b/src/commands/meme/history.rs
@@ -1,7 +1,11 @@
+use anyhow::anyhow;
use diesel::{
result::Error as DieselError,
NotFound,
+ PgConnection,
};
+use itertools::Itertools;
+use lazy_static::lazy_static;
use log::{
debug,
error,
@@ -11,25 +15,23 @@ use serenity::{
framework::standard::{
macros::command,
Args,
+ CommandError,
+ CommandResult,
+ },
+ futures::{
+ StreamExt,
+ TryFutureExt,
+ TryStreamExt,
},
model::channel::Message,
prelude::*,
};
+use tap::Pipe;
use timeago::{
Formatter,
TimeUnit,
};
-use anyhow::anyhow;
-use lazy_static::lazy_static;
-use serenity::{
- framework::standard::{
- CommandError,
- CommandResult,
- },
- futures::TryFutureExt,
-};
-
use crate::{
db::{
self,
@@ -39,7 +41,6 @@ use crate::{
Metadata,
},
util,
- Result,
CONFIG,
};
@@ -53,10 +54,10 @@ lazy_static! {
};
}
-static CLEAN_DATE_FORMAT: &'static str = "%b %-e %Y";
+static CLEAN_DATE_FORMAT: &str = "%b %-e %Y";
#[command]
-#[aliases("what")]
+#[aliases("what", "hwaet", "hwæt")]
pub async fn wat(ctx: &Context, msg: &Message, _: Args) -> CommandResult {
let mut conn = connection()?;
@@ -80,7 +81,7 @@ pub async fn wat(ctx: &Context, msg: &Message, _: Args) -> CommandResult {
match meme {
Ok(ref meme) => {
let metadata = Metadata::find(&mut conn, meme.metadata_id)?;
- let author = CONFIG.discord.guild().member(&ctx, metadata.created_by as u64)?;
+ let author = CONFIG.discord.guild().member(&ctx, metadata.created_by as u64).await?;
util::send(
ctx,
@@ -98,22 +99,22 @@ pub async fn wat(ctx: &Context, msg: &Message, _: Args) -> CommandResult {
Err(e) => {
if let Some(NotFound) = e.downcast_ref::<DieselError>() {
info!("last meme not found in database");
- return util::send(ctx, msg.channel_id, "heuueueeeeh?", msg.tts).await;
+ return util::send(ctx, msg.channel_id, "heuueueeeeh?", msg.tts)
+ .await
+ .map_err(CommandError::from);
}
util::send(ctx, msg.channel_id, "do i look like i know what a jpeg is", msg.tts)
.await?;
- return Err(e);
+ return Err(e.into());
},
};
- meme.map(|_| {})
+ meme.map(|_| {}).map_err(CommandError::from)
}
#[command]
pub async fn history(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
- use itertools::Itertools;
-
let mut conn = connection()?;
let n = args.single_quoted::<usize>().unwrap_or(CONFIG.default_hist);
@@ -135,66 +136,76 @@ pub async fn history(ctx: &Context, msg: &Message, mut args: Args) -> CommandRes
}
info!("reporting meme history (len {})", n);
- let resp = records
- .into_iter()
- .enumerate()
- .rev()
- .map(|(i, rec)| {
- let dt = chrono::DateTime::from_utc(rec.time, chrono::Utc {});
- let ago = TIME_FORMATTER.convert((chrono::Utc::now() - dt).to_std().unwrap());
- let rand = if rec.random {
- "R, "
- } else {
- ""
- };
- Meme::find(&mut conn, rec.meme_id)
- .and_then(|meme| {
- Metadata::find(&mut conn, meme.metadata_id).map(|metadata| (metadata, meme))
- })
- .map(|(metadata, meme)| {
- let author_name = CONFIG
- .discord
- .guild()
- .member(&ctx, metadata.created_by as u64)
- .map(|m| m.display_name().into_owned())
- .unwrap_or("???".to_owned());
- let invoker_name = CONFIG
- .discord
- .guild()
- .member(&ctx, rec.user_id as u64)
- .map(|m| m.display_name().into_owned())
- .unwrap_or("???".to_owned());
- format!(
- "{}. [{}{}] \"{}\" by {} ({}). invoked by {}.",
- i + 1,
- rand,
- ago,
- meme.title,
- author_name,
- metadata.created.date().format(CLEAN_DATE_FORMAT),
- invoker_name
- )
- })
- .unwrap_or_else(|e| {
- if let Some(variant) = e.downcast_ref::<DieselError>() {
- if *variant != NotFound {
- error!("error encountered loading meme history: {}", e);
- }
- }
+ let resp = serenity::futures::stream::iter(records.into_iter().enumerate().rev())
+ .then(|(i, rec)| ir_info(ctx, i, rec, &mut conn))
+ .try_collect::<Vec<String>>()
+ .await?;
- let invoker_name = CONFIG
- .discord
- .guild()
- .member(&ctx, rec.user_id as u64)
- .map(|m| m.display_name().into_owned())
- .unwrap_or("???".to_owned());
- format!("{}. [{}{}] not found. invoked by {}.", i + 1, rand, ago, invoker_name)
- })
- })
- .join("\n");
+ let resp = resp.join("\n");
- util::send(ctx, msg.channel_id, &resp, false).await
+ util::send(ctx, msg.channel_id, &resp, false).await.map_err(CommandError::from)
+}
+
+async fn ir_info(
+ ctx: &Context,
+ i: usize,
+ rec: InvocationRecord,
+ conn: &mut PgConnection,
+) -> Result<String, CommandError> {
+ let dt = chrono::DateTime::from_utc(rec.time, chrono::Utc {});
+ let ago = TIME_FORMATTER.convert((chrono::Utc::now() - dt).to_std().unwrap());
+
+ let rand = if rec.random {
+ "R, "
+ } else {
+ ""
+ };
+
+ let meme = Meme::find(conn, rec.meme_id)
+ .and_then(|meme| Metadata::find(conn, meme.metadata_id).map(|metadata| (metadata, meme)));
+
+ let invoker_name = CONFIG
+ .discord
+ .guild()
+ .member(&ctx, rec.user_id as u64)
+ .await
+ .map(|m| m.display_name().to_owned())
+ .unwrap_or("???".to_owned());
+
+ let result = match meme {
+ Ok((metadata, meme)) => {
+ let author_name = CONFIG
+ .discord
+ .guild()
+ .member(&ctx, metadata.created_by as u64)
+ .await
+ .map(|m| m.display_name().to_owned())
+ .unwrap_or("???".to_owned());
+
+ format!(
+ "{}. [{}{}] \"{}\" by {} ({}). invoked by {}.",
+ i + 1,
+ rand,
+ ago,
+ meme.title,
+ author_name,
+ metadata.created.date().format(CLEAN_DATE_FORMAT),
+ invoker_name
+ )
+ },
+ Err(e) => {
+ if let Some(variant) = e.downcast_ref::<DieselError>() {
+ if *variant != NotFound {
+ error!("error encountered loading meme history: {}", e);
+ }
+ }
+
+ format!("{}. [{}{}] not found. invoked by {}.", i + 1, rand, ago, invoker_name)
+ },
+ };
+
+ Ok(result)
}
#[command]
@@ -211,11 +222,12 @@ pub async fn stats(ctx: &Context, msg: &Message, _: Args) -> CommandResult {
debug!("reporting stats");
- let rand_user: User = UserId::new(stats.most_random_meme_user).to_user(&ctx)?;
- let direct_user: User = UserId::new(stats.most_directly_named_meme_user).to_user(&ctx)?;
+ let rand_user: User = UserId::new(stats.most_random_meme_user).to_user(&ctx).await?;
+ let direct_user: User = UserId::new(stats.most_directly_named_meme_user).to_user(&ctx).await?;
- let rand_user = rand_user.nick_in(&ctx, CONFIG.discord.guild()).unwrap_or(rand_user.name);
- let direct_user = direct_user.nick_in(&ctx, CONFIG.discord.guild()).unwrap_or(direct_user.name);
+ let rand_user = rand_user.nick_in(&ctx, CONFIG.discord.guild()).await.unwrap_or(rand_user.name);
+ let direct_user =
+ direct_user.nick_in(&ctx, CONFIG.discord.guild()).await.unwrap_or(direct_user.name);
let s = format!(
r#"
@@ -270,15 +282,14 @@ and *{}* was the most-memed overall ({})"#,
#[command]
pub async fn memers(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
- use db;
- use itertools::Itertools;
use serenity::model::id::UserId;
let s = db::memers()?
.into_iter()
- .map(|info| {
- let user = UserId::new(info.user_id).to_user(&ctx)?;
- let username = user.nick_in(&ctx, CONFIG.discord.guild()).unwrap_or(user.name);
+ .pipe(serenity::futures::stream::iter)
+ .then(|info| async move {
+ let user = UserId::new(info.user_id).to_user(&ctx).await?;
+ let username = user.nick_in(&ctx, CONFIG.discord.guild()).await.unwrap_or(user.name);
let res = format!(
"**{}**: {} total, {} random, {} specific. favorite meme: *{}* ({})",
@@ -290,9 +301,10 @@ pub async fn memers(ctx: &Context, msg: &Message, _args: Args) -> CommandResult
info.most_used_meme_count,
);
- Ok(res)
+ Result::<_, CommandError>::Ok(res)
})
- .collect::<Result<Vec<_>>>()?
+ .try_collect::<Vec<String>>()
+ .await?
.into_iter()
.join("\n");
@@ -301,11 +313,9 @@ pub async fn memers(ctx: &Context, msg: &Message, _args: Args) -> CommandResult
#[command]
pub async fn query(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
- use std::borrow::Borrow;
-
- use itertools::Itertools;
use regex::Regex;
use serenity::model::id::UserId;
+ use std::borrow::Borrow;
use crate::{
db,
@@ -318,11 +328,10 @@ pub async fn query(ctx: &Context, msg: &Message, mut args: Args) -> CommandResul
static ref AGE_REGEX: Regex = Regex::new(r"(?i)(?:age|order)=(.*)").unwrap();
}
- let guild = msg.channel_id.to_channel(&ctx)?.guild().ok_or(anyhow!("couldn't find guild"))?;
-
- let guild = guild.read().guild(&ctx).ok_or(anyhow!("couldn't find guild"))?;
+ let guild =
+ msg.channel_id.to_channel(&ctx).await?.guild().ok_or(anyhow!("couldn't find guild"))?;
- let guild = guild.read();
+ let guild = guild.guild(&ctx).ok_or(anyhow!("couldn't find guild"))?;
let creator: Option<u64> = {
let creator = args.quoted().current().map(|s| CREATOR_REGEX.is_match(s)).unwrap_or(false);
@@ -354,11 +363,13 @@ pub async fn query(ctx: &Context, msg: &Message, mut args: Args) -> CommandResul
}
};
- let result = db::query_meme(args.rest(), creator, order)?
- .into_iter()
- .map(|(meme, metadata)| {
- let user = UserId::new(metadata.created_by as u64).to_user(&ctx)?;
- let username = user.nick_in(&ctx, CONFIG.discord.guild()).unwrap_or(user.name);
+ let iter = db::query_meme(args.rest(), creator, order)?.into_iter();
+
+ let result = iter
+ .pipe(serenity::futures::stream::iter)
+ .then(|(meme, metadata)| async move {
+ let user = UserId::new(metadata.created_by as u64).to_user(&ctx).await?;
+ let username = user.nick_in(&ctx, CONFIG.discord.guild()).await.unwrap_or(user.name);
Ok(format!(
"*{}* by **{}** ({}). text length: **{}**, image: **{}**, audio: **{}**",
@@ -368,9 +379,12 @@ pub async fn query(ctx: &Context, msg: &Message, mut args: Args) -> CommandResul
meme.content.map_or(0, |s| s.len()),
meme.image_id.map_or("NO", |_s| "YES"),
meme.audio_id.map_or("NO", |_s| "YES"),
- ))
+ )) as Result<String, CommandError>
})
- .collect::<Result<Vec<_>>>()?
+ .try_collect::<Vec<String>>()
+ .await;
+
+ let result = result?
.into_iter()
.scan(0, |state, line| {
*state = *state + line.len() + 1;