mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-04-19 16:58:55 +00:00
WIP: osu: asyncify caches
This commit is contained in:
parent
bd5f4f0fd2
commit
07a8bc5579
2 changed files with 83 additions and 71 deletions
|
@ -22,15 +22,25 @@ use youmubot_prelude::*;
|
||||||
/// osu! announcer's unique announcer key.
|
/// osu! announcer's unique announcer key.
|
||||||
pub const ANNOUNCER_KEY: &'static str = "osu";
|
pub const ANNOUNCER_KEY: &'static str = "osu";
|
||||||
|
|
||||||
/// Announce osu! top scores.
|
/// The announcer struct implementing youmubot_prelude::Announcer
|
||||||
pub fn updates(c: Arc<CacheAndHttp>, d: AppData, channels: MemberToChannels) -> CommandResult {
|
pub struct Announcer;
|
||||||
let osu = d.get_cloned::<OsuClient>();
|
|
||||||
let cache = d.get_cloned::<BeatmapMetaCache>();
|
#[async_trait]
|
||||||
let oppai = d.get_cloned::<BeatmapCache>();
|
impl youmubot_prelude::Announcer for Announcer {
|
||||||
|
async fn updates(
|
||||||
|
&mut self,
|
||||||
|
c: Arc<CacheAndHttp>,
|
||||||
|
d: AppData,
|
||||||
|
channels: MemberToChannels,
|
||||||
|
) -> Result<()> {
|
||||||
|
let d = d.read().await;
|
||||||
|
let osu = d.get::<OsuClient>().unwrap();
|
||||||
|
let cache = d.get::<BeatmapMetaCache>().unwrap();
|
||||||
|
let oppai = d.get::<BeatmapCache>().unwrap();
|
||||||
// For each user...
|
// For each user...
|
||||||
let mut data = OsuSavedUsers::open(&*d.read()).borrow()?.clone();
|
let mut data = OsuSavedUsers::open(&*d).borrow()?.clone();
|
||||||
for (user_id, osu_user) in data.iter_mut() {
|
for (user_id, osu_user) in data.iter_mut() {
|
||||||
let channels = channels.channels_of(c.clone(), *user_id);
|
let channels = channels.channels_of(c.clone(), *user_id).await;
|
||||||
if channels.is_empty() {
|
if channels.is_empty() {
|
||||||
continue; // We don't wanna update an user without any active server
|
continue; // We don't wanna update an user without any active server
|
||||||
}
|
}
|
||||||
|
@ -46,7 +56,7 @@ pub fn updates(c: Arc<CacheAndHttp>, d: AppData, channels: MemberToChannels) ->
|
||||||
*user_id,
|
*user_id,
|
||||||
&channels[..],
|
&channels[..],
|
||||||
*m,
|
*m,
|
||||||
d.clone(),
|
&*d,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Result<_, _>>()
|
.collect::<Result<_, _>>()
|
||||||
|
@ -63,9 +73,10 @@ pub fn updates(c: Arc<CacheAndHttp>, d: AppData, channels: MemberToChannels) ->
|
||||||
*OsuSavedUsers::open(&*d.read()).borrow_mut()? = data;
|
*OsuSavedUsers::open(&*d.read()).borrow_mut()? = data;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Handles an user/mode scan, announces all possible new scores, return the new pp value.
|
/// Handles an user/mode scan, announces all possible new scores, return the new pp value.
|
||||||
fn handle_user_mode(
|
async fn handle_user_mode(
|
||||||
c: Arc<CacheAndHttp>,
|
c: Arc<CacheAndHttp>,
|
||||||
osu: &Osu,
|
osu: &Osu,
|
||||||
cache: &BeatmapMetaCache,
|
cache: &BeatmapMetaCache,
|
||||||
|
@ -74,15 +85,16 @@ fn handle_user_mode(
|
||||||
user_id: UserId,
|
user_id: UserId,
|
||||||
channels: &[ChannelId],
|
channels: &[ChannelId],
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
d: AppData,
|
d: &TypeMap,
|
||||||
) -> Result<Option<f64>, Error> {
|
) -> Result<Option<f64>, Error> {
|
||||||
let scores = scan_user(osu, osu_user, mode)?;
|
let scores = scan_user(osu, osu_user, mode)?;
|
||||||
let user = osu
|
let user = osu
|
||||||
.user(UserID::ID(osu_user.id), |f| f.mode(mode))?
|
.user(UserID::ID(osu_user.id), |f| f.mode(mode))
|
||||||
|
.await?
|
||||||
.ok_or(Error::from("user not found"))?;
|
.ok_or(Error::from("user not found"))?;
|
||||||
scores
|
scores
|
||||||
.into_par_iter()
|
.into_iter()
|
||||||
.map(|(rank, score)| -> Result<_, Error> {
|
.map(|(rank, score)| -> Result<_> {
|
||||||
let beatmap = cache.get_beatmap_default(score.beatmap_id)?;
|
let beatmap = cache.get_beatmap_default(score.beatmap_id)?;
|
||||||
let content = oppai.get_beatmap(beatmap.beatmap_id)?;
|
let content = oppai.get_beatmap(beatmap.beatmap_id)?;
|
||||||
Ok((rank, score, BeatmapWithMode(beatmap, mode), content))
|
Ok((rank, score, BeatmapWithMode(beatmap, mode), content))
|
||||||
|
|
|
@ -3,16 +3,14 @@ use crate::{
|
||||||
Client,
|
Client,
|
||||||
};
|
};
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use serenity::framework::standard::CommandError;
|
use youmubot_prelude::*;
|
||||||
use std::sync::Arc;
|
|
||||||
use youmubot_prelude::TypeMapKey;
|
|
||||||
|
|
||||||
/// BeatmapMetaCache intercepts beatmap-by-id requests and caches them for later recalling.
|
/// BeatmapMetaCache intercepts beatmap-by-id requests and caches them for later recalling.
|
||||||
/// Does not cache non-Ranked beatmaps.
|
/// Does not cache non-Ranked beatmaps.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BeatmapMetaCache {
|
pub struct BeatmapMetaCache {
|
||||||
client: Client,
|
client: Client,
|
||||||
cache: Arc<DashMap<(u64, Mode), Beatmap>>,
|
cache: DashMap<(u64, Mode), Beatmap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeMapKey for BeatmapMetaCache {
|
impl TypeMapKey for BeatmapMetaCache {
|
||||||
|
@ -24,10 +22,10 @@ impl BeatmapMetaCache {
|
||||||
pub fn new(client: Client) -> Self {
|
pub fn new(client: Client) -> Self {
|
||||||
BeatmapMetaCache {
|
BeatmapMetaCache {
|
||||||
client,
|
client,
|
||||||
cache: Arc::new(DashMap::new()),
|
cache: DashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn insert_if_possible(&self, id: u64, mode: Option<Mode>) -> Result<Beatmap, CommandError> {
|
async fn insert_if_possible(&self, id: u64, mode: Option<Mode>) -> Result<Beatmap> {
|
||||||
let beatmap = self
|
let beatmap = self
|
||||||
.client
|
.client
|
||||||
.beatmaps(crate::BeatmapRequestKind::Beatmap(id), |f| {
|
.beatmaps(crate::BeatmapRequestKind::Beatmap(id), |f| {
|
||||||
|
@ -36,35 +34,37 @@ impl BeatmapMetaCache {
|
||||||
}
|
}
|
||||||
f
|
f
|
||||||
})
|
})
|
||||||
.and_then(|v| {
|
.await
|
||||||
v.into_iter()
|
.and_then(|v| v.into_iter().next().ok_or(Error::msg("beatmap not found")))?;
|
||||||
.next()
|
|
||||||
.ok_or(CommandError::from("beatmap not found"))
|
|
||||||
})?;
|
|
||||||
if let ApprovalStatus::Ranked(_) = beatmap.approval {
|
if let ApprovalStatus::Ranked(_) = beatmap.approval {
|
||||||
self.cache.insert((id, beatmap.mode), beatmap.clone());
|
self.cache.insert((id, beatmap.mode), beatmap.clone());
|
||||||
};
|
};
|
||||||
Ok(beatmap)
|
Ok(beatmap)
|
||||||
}
|
}
|
||||||
/// Get the given beatmap
|
/// Get the given beatmap
|
||||||
pub fn get_beatmap(&self, id: u64, mode: Mode) -> Result<Beatmap, CommandError> {
|
pub async fn get_beatmap(&self, id: u64, mode: Mode) -> Result<Beatmap> {
|
||||||
self.cache
|
match self.cache.get(&(id, mode)).map(|v| v.clone()) {
|
||||||
.get(&(id, mode))
|
Some(v) => Ok(v),
|
||||||
.map(|b| Ok(b.clone()))
|
None => self.insert_if_possible(id, Some(mode)).await,
|
||||||
.unwrap_or_else(|| self.insert_if_possible(id, Some(mode)))
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a beatmap without a mode...
|
/// Get a beatmap without a mode...
|
||||||
pub fn get_beatmap_default(&self, id: u64) -> Result<Beatmap, CommandError> {
|
pub async fn get_beatmap_default(&self, id: u64) -> Result<Beatmap> {
|
||||||
(&[Mode::Std, Mode::Taiko, Mode::Catch, Mode::Mania])
|
Ok(
|
||||||
|
match (&[Mode::Std, Mode::Taiko, Mode::Catch, Mode::Mania])
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|&mode| {
|
.filter_map(|&mode| {
|
||||||
self.cache
|
self.cache
|
||||||
.get(&(id, mode))
|
.get(&(id, mode))
|
||||||
.filter(|b| b.mode == mode)
|
.filter(|b| b.mode == mode)
|
||||||
.map(|b| Ok(b.clone()))
|
.map(|b| b.clone())
|
||||||
})
|
})
|
||||||
.next()
|
.next()
|
||||||
.unwrap_or_else(|| self.insert_if_possible(id, None))
|
{
|
||||||
|
Some(v) => v,
|
||||||
|
None => self.insert_if_possible(id, None).await?,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue