diff --git a/youmubot-osu/src/discord/announcer.rs b/youmubot-osu/src/discord/announcer.rs index fed7c16..4dbb119 100644 --- a/youmubot-osu/src/discord/announcer.rs +++ b/youmubot-osu/src/discord/announcer.rs @@ -1,5 +1,5 @@ use super::db::{OsuSavedUsers, OsuUser}; -use super::{embeds::score_embed, BeatmapWithMode, OsuClient}; +use super::{embeds::score_embed, BeatmapWithMode}; use crate::{ discord::beatmap_cache::BeatmapMetaCache, discord::cache::save_beatmap, @@ -21,7 +21,15 @@ use youmubot_prelude::*; pub const ANNOUNCER_KEY: &'static str = "osu"; /// The announcer struct implementing youmubot_prelude::Announcer -pub struct Announcer; +pub struct Announcer { + client: Osu, +} + +impl Announcer { + pub fn new(client: Osu) -> Self { + Self { client } + } +} #[async_trait] impl youmubot_prelude::Announcer for Announcer { @@ -39,6 +47,7 @@ impl youmubot_prelude::Announcer for Announcer { let d = d.clone(); let channels = &channels; let c = c.clone(); + let s = &self; async move { let channels = channels.channels_of(c.clone(), user_id).await; if channels.is_empty() { @@ -47,7 +56,7 @@ impl youmubot_prelude::Announcer for Announcer { let pp = match (&[Mode::Std, Mode::Taiko, Mode::Catch, Mode::Mania]) .into_iter() .map(|m| { - handle_user_mode( + s.handle_user_mode( c.clone(), &osu_user, user_id, @@ -86,87 +95,91 @@ impl youmubot_prelude::Announcer for Announcer { } } -/// Handles an user/mode scan, announces all possible new scores, return the new pp value. -async fn handle_user_mode( - c: Arc, - osu_user: &OsuUser, - user_id: UserId, - channels: Vec, - mode: Mode, - d: AppData, -) -> Result, Error> { - let (scores, user) = { - let data = d.read().await; - let osu = data.get::().unwrap(); - let scores = scan_user(osu, osu_user, mode).await?; - let user = osu - .user(UserID::ID(osu_user.id), |f| f.mode(mode)) - .await? - .ok_or(Error::msg("user not found"))?; - (scores, user) - }; - let pp = user.pp; - spawn_future(async move { - scores - .into_iter() - .map(|(rank, score)| { - let d = d.clone(); - async move { - let data = d.read().await; - let cache = data.get::().unwrap(); - let oppai = data.get::().unwrap(); - let beatmap = cache.get_beatmap_default(score.beatmap_id).await?; - let content = oppai.get_beatmap(beatmap.beatmap_id).await?; - let r: Result<_> = Ok((rank, score, BeatmapWithMode(beatmap, mode), content)); - r - } - }) - .collect::>() - .filter_map(|v| future::ready(v.ok())) - .for_each(move |(rank, score, beatmap, content)| { - let channels = channels.clone(); - let d = d.clone(); - let c = c.clone(); - let user = user.clone(); - async move { - let data = d.read().await; - for channel in (&channels).iter() { - if let Err(e) = channel - .send_message(c.http(), |c| { - c.content(format!("New top record from {}!", user_id.mention())) - .embed(|e| { - score_embed( - &score, - &beatmap, - &content, - &user, - Some(rank), - e, - ) - }) - }) - .await - { - dbg!(e); - } - save_beatmap(&*data, *channel, &beatmap).ok(); +impl Announcer { + /// Handles an user/mode scan, announces all possible new scores, return the new pp value. + async fn handle_user_mode( + &self, + c: Arc, + osu_user: &OsuUser, + user_id: UserId, + channels: Vec, + mode: Mode, + d: AppData, + ) -> Result, Error> { + let (scores, user) = { + let scores = self.scan_user(osu_user, mode).await?; + let user = self + .client + .user(UserID::ID(osu_user.id), |f| f.mode(mode)) + .await? + .ok_or(Error::msg("user not found"))?; + (scores, user) + }; + let pp = user.pp; + spawn_future(async move { + scores + .into_iter() + .map(|(rank, score)| { + let d = d.clone(); + async move { + let data = d.read().await; + let cache = data.get::().unwrap(); + let oppai = data.get::().unwrap(); + let beatmap = cache.get_beatmap_default(score.beatmap_id).await?; + let content = oppai.get_beatmap(beatmap.beatmap_id).await?; + let r: Result<_> = + Ok((rank, score, BeatmapWithMode(beatmap, mode), content)); + r } - } - }) - .await; - }); - Ok(pp) -} + }) + .collect::>() + .filter_map(|v| future::ready(v.ok())) + .for_each(move |(rank, score, beatmap, content)| { + let channels = channels.clone(); + let d = d.clone(); + let c = c.clone(); + let user = user.clone(); + async move { + let data = d.read().await; + for channel in (&channels).iter() { + if let Err(e) = channel + .send_message(c.http(), |c| { + c.content(format!("New top record from {}!", user_id.mention())) + .embed(|e| { + score_embed( + &score, + &beatmap, + &content, + &user, + Some(rank), + e, + ) + }) + }) + .await + { + dbg!(e); + } + save_beatmap(&*data, *channel, &beatmap).ok(); + } + } + }) + .await; + }); + Ok(pp) + } -async fn scan_user(osu: &Osu, u: &OsuUser, mode: Mode) -> Result, Error> { - let scores = osu - .user_best(UserID::ID(u.id), |f| f.mode(mode).limit(25)) - .await?; - let scores = scores - .into_iter() - .enumerate() - .filter(|(_, s)| s.date >= u.last_update) - .map(|(i, v)| ((i + 1) as u8, v)) - .collect(); - Ok(scores) + async fn scan_user(&self, u: &OsuUser, mode: Mode) -> Result, Error> { + let scores = self + .client + .user_best(UserID::ID(u.id), |f| f.mode(mode).limit(25)) + .await?; + let scores = scores + .into_iter() + .enumerate() + .filter(|(_, s)| s.date >= u.last_update) + .map(|(i, v)| ((i + 1) as u8, v)) + .collect(); + Ok(scores) + } } diff --git a/youmubot-osu/src/discord/mod.rs b/youmubot-osu/src/discord/mod.rs index 5ecfb4a..2d8aa99 100644 --- a/youmubot-osu/src/discord/mod.rs +++ b/youmubot-osu/src/discord/mod.rs @@ -66,9 +66,12 @@ pub fn setup( // API client let http_client = data.get::().unwrap().clone(); - let osu_client = Arc::new(OsuHttpClient::new( - std::env::var("OSU_API_KEY").expect("Please set OSU_API_KEY as osu! api key."), - )); + let make_client = || { + OsuHttpClient::new( + std::env::var("OSU_API_KEY").expect("Please set OSU_API_KEY as osu! api key."), + ) + }; + let osu_client = Arc::new(make_client()); data.insert::(osu_client.clone()); data.insert::(oppai_cache::BeatmapCache::new(http_client)); data.insert::(beatmap_cache::BeatmapMetaCache::new( @@ -76,7 +79,10 @@ pub fn setup( )); // Announcer - announcers.add(announcer::ANNOUNCER_KEY, announcer::Announcer); + announcers.add( + announcer::ANNOUNCER_KEY, + announcer::Announcer::new(make_client()), + ); Ok(()) } diff --git a/youmubot-osu/src/lib.rs b/youmubot-osu/src/lib.rs index b850884..31df742 100644 --- a/youmubot-osu/src/lib.rs +++ b/youmubot-osu/src/lib.rs @@ -13,7 +13,7 @@ use std::convert::TryInto; use youmubot_prelude::{ratelimit::Ratelimit, *}; /// The number of requests per minute to the osu! server. -const REQUESTS_PER_MINUTE: usize = 200; +const REQUESTS_PER_MINUTE: usize = 60; /// Client is the client that will perform calls to the osu! api server. pub struct Client {