osu: Asyncify oppai cache

This commit is contained in:
Natsu Kagami 2020-09-07 14:31:45 -04:00
parent da2997d8f9
commit bfe12d3946
Signed by: nki
GPG key ID: 73376E117CD20735
2 changed files with 45 additions and 40 deletions

View file

@ -128,12 +128,14 @@ fn handle_old_links<'a>(
.map(|v| Mods::from_str(v.as_str()).ok()) .map(|v| Mods::from_str(v.as_str()).ok())
.flatten() .flatten()
.unwrap_or(Mods::NOMOD); .unwrap_or(Mods::NOMOD);
let info = mode.unwrap_or(b.mode).to_oppai_mode().and_then(|mode| { let info = match mode.unwrap_or(b.mode).to_oppai_mode() {
cache Some(mode) => cache
.get_beatmap(b.beatmap_id) .get_beatmap(b.beatmap_id)
.await
.and_then(|b| b.get_info_with(Some(mode), mods)) .and_then(|b| b.get_info_with(Some(mode), mods))
.ok() .ok(),
}); None => None,
};
Some(ToPrint { Some(ToPrint {
embed: EmbedType::Beatmap(b, info, mods), embed: EmbedType::Beatmap(b, info, mods),
link: capture.get(0).unwrap().as_str(), link: capture.get(0).unwrap().as_str(),
@ -198,15 +200,14 @@ fn handle_new_links<'a>(
.name("mods") .name("mods")
.and_then(|v| Mods::from_str(v.as_str()).ok()) .and_then(|v| Mods::from_str(v.as_str()).ok())
.unwrap_or(Mods::NOMOD); .unwrap_or(Mods::NOMOD);
let info = mode let info = match mode.unwrap_or(beatmap.mode).to_oppai_mode() {
.unwrap_or(beatmap.mode) Some(mode) => cache
.to_oppai_mode()
.and_then(|mode| {
cache
.get_beatmap(beatmap.beatmap_id) .get_beatmap(beatmap.beatmap_id)
.await
.and_then(|b| b.get_info_with(Some(mode), mods)) .and_then(|b| b.get_info_with(Some(mode), mods))
.ok() .ok(),
}); None => None,
};
Some(ToPrint { Some(ToPrint {
embed: EmbedType::Beatmap(beatmap, info, mods), embed: EmbedType::Beatmap(beatmap, info, mods),
link, link,
@ -265,15 +266,14 @@ fn handle_short_links<'a>(
.name("mods") .name("mods")
.and_then(|v| Mods::from_str(v.as_str()).ok()) .and_then(|v| Mods::from_str(v.as_str()).ok())
.unwrap_or(Mods::NOMOD); .unwrap_or(Mods::NOMOD);
let info = mode let info = match mode.unwrap_or(beatmap.mode).to_oppai_mode() {
.unwrap_or(beatmap.mode) Some(mode) => cache
.to_oppai_mode()
.and_then(|mode| {
cache
.get_beatmap(beatmap.beatmap_id) .get_beatmap(beatmap.beatmap_id)
.await
.and_then(|b| b.get_info_with(Some(mode), mods)) .and_then(|b| b.get_info_with(Some(mode), mods))
.ok() .ok(),
}); None => None,
};
let r: Result<_> = Ok(ToPrint { let r: Result<_> = Ok(ToPrint {
embed: EmbedType::Beatmap(beatmap, info, mods), embed: EmbedType::Beatmap(beatmap, info, mods),
link: capture.get(0).unwrap().as_str(), link: capture.get(0).unwrap().as_str(),

View file

@ -1,12 +1,12 @@
use serenity::framework::standard::CommandError; use serenity::framework::standard::CommandError;
use std::{ffi::CString, sync::Arc}; use std::ffi::CString;
use youmubot_prelude::TypeMapKey; use youmubot_prelude::*;
/// the information collected from a download/Oppai request. /// the information collected from a download/Oppai request.
#[derive(Clone, Debug)] #[derive(Debug)]
pub struct BeatmapContent { pub struct BeatmapContent {
id: u64, id: u64,
content: Arc<CString>, content: CString,
} }
/// the output of "one" oppai run. /// the output of "one" oppai run.
@ -56,39 +56,44 @@ impl BeatmapContent {
} }
/// A central cache for the beatmaps. /// A central cache for the beatmaps.
#[derive(Clone, Debug)] #[derive(Debug)]
pub struct BeatmapCache { pub struct BeatmapCache {
client: reqwest::blocking::Client, client: reqwest::Client,
cache: Arc<dashmap::DashMap<u64, BeatmapContent>>, cache: dashmap::DashMap<u64, BeatmapContent>,
} }
impl BeatmapCache { impl BeatmapCache {
/// Create a new cache. /// Create a new cache.
pub fn new(client: reqwest::blocking::Client) -> Self { pub fn new(client: reqwest::Client) -> Self {
BeatmapCache { BeatmapCache {
client, client,
cache: Arc::new(dashmap::DashMap::new()), cache: dashmap::DashMap::new(),
} }
} }
fn download_beatmap(&self, id: u64) -> Result<BeatmapContent, CommandError> { async fn download_beatmap(&self, id: u64) -> Result<BeatmapContent> {
let content = self let content = self
.client .client
.get(&format!("https://osu.ppy.sh/osu/{}", id)) .get(&format!("https://osu.ppy.sh/osu/{}", id))
.send()? .send()
.bytes()?; .await?
.bytes()
.await?;
Ok(BeatmapContent { Ok(BeatmapContent {
id, id,
content: Arc::new(CString::new(content.into_iter().collect::<Vec<_>>())?), content: CString::new(content.into_iter().collect::<Vec<_>>())?,
}) })
} }
/// Get a beatmap from the cache. /// Get a beatmap from the cache.
pub fn get_beatmap(&self, id: u64) -> Result<BeatmapContent, CommandError> { pub async fn get_beatmap<'a>(
self.cache &'a self,
.entry(id) id: u64,
.or_try_insert_with(|| self.download_beatmap(id)) ) -> Result<impl std::ops::Deref<Target = BeatmapContent> + 'a, CommandError> {
.map(|v| v.clone()) if !self.cache.contains_key(&id) {
self.cache.insert(id, self.download_beatmap(id).await?);
}
Ok(self.cache.get(&id).unwrap())
} }
} }