mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-04-19 00:38:54 +00:00
Add UserHeader as cacheable alternative to fetching a full user
This commit is contained in:
parent
0e72f12b6d
commit
7a98dc21a9
4 changed files with 64 additions and 69 deletions
|
@ -1,6 +1,8 @@
|
|||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures_util::lock::Mutex;
|
||||
use models::*;
|
||||
use request::builders::*;
|
||||
use request::*;
|
||||
|
@ -14,6 +16,8 @@ pub mod request;
|
|||
#[derive(Clone)]
|
||||
pub struct Client {
|
||||
rosu: Arc<rosu_v2::Osu>,
|
||||
|
||||
user_header_cache: Arc<Mutex<HashMap<u64, Option<UserHeader>>>>,
|
||||
}
|
||||
|
||||
pub fn vec_try_into<U, T: std::convert::TryFrom<U>>(v: Vec<U>) -> Result<Vec<T>, T::Error> {
|
||||
|
@ -36,6 +40,7 @@ impl Client {
|
|||
.await?;
|
||||
Ok(Client {
|
||||
rosu: Arc::new(rosu),
|
||||
user_header_cache: Arc::new(Mutex::new(HashMap::new())),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -54,9 +59,26 @@ impl Client {
|
|||
user: UserID,
|
||||
f: impl FnOnce(&mut UserRequestBuilder) -> &mut UserRequestBuilder,
|
||||
) -> Result<Option<User>, Error> {
|
||||
let mut r = UserRequestBuilder::new(user);
|
||||
let mut r = UserRequestBuilder::new(user.clone());
|
||||
f(&mut r);
|
||||
r.build(self).await
|
||||
let u = r.build(self).await?;
|
||||
if let UserID::ID(id) = user {
|
||||
self.user_header_cache
|
||||
.lock()
|
||||
.await
|
||||
.insert(id, u.clone().map(|v| v.into()));
|
||||
}
|
||||
Ok(u)
|
||||
}
|
||||
|
||||
/// Fetch the user header.
|
||||
pub async fn user_header(&self, id: u64) -> Result<Option<UserHeader>, Error> {
|
||||
Ok(
|
||||
match self.user_header_cache.lock().await.get(&id).cloned() {
|
||||
Some(v) => v,
|
||||
None => self.user(UserID::ID(id), |f| f).await?.map(|v| v.into()),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn scores(
|
||||
|
|
|
@ -460,6 +460,13 @@ impl UserEvent {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UserHeader {
|
||||
pub id: u64,
|
||||
pub username: String,
|
||||
pub country: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct User {
|
||||
pub id: u64,
|
||||
|
@ -498,6 +505,36 @@ impl User {
|
|||
}
|
||||
}
|
||||
|
||||
impl UserHeader {
|
||||
pub fn link(&self) -> String {
|
||||
format!("https://osu.ppy.sh/users/{}", self.id)
|
||||
}
|
||||
|
||||
pub fn avatar_url(&self) -> String {
|
||||
format!("https://a.ppy.sh/{}", self.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a User> for UserHeader {
|
||||
fn from(u: &'a User) -> Self {
|
||||
Self {
|
||||
id: u.id,
|
||||
username: u.username.clone(),
|
||||
country: u.country.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<User> for UserHeader {
|
||||
fn from(u: User) -> Self {
|
||||
Self {
|
||||
id: u.id,
|
||||
username: u.username,
|
||||
country: u.country,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Rank {
|
||||
SS,
|
||||
|
@ -547,6 +584,7 @@ pub struct Score {
|
|||
pub normalized_score: u32,
|
||||
pub pp: Option<f64>,
|
||||
pub rank: Rank,
|
||||
pub mode: Mode,
|
||||
pub mods: Mods, // Later
|
||||
|
||||
pub count_300: u64,
|
||||
|
|
|
@ -127,6 +127,7 @@ impl From<rosu::score::Score> for Score {
|
|||
server_accuracy: s.accuracy as f64,
|
||||
global_rank: s.rank_global,
|
||||
effective_pp: s.weight.map(|w| w.pp as f64),
|
||||
mode: s.mode.into(),
|
||||
mods: s
|
||||
.mods
|
||||
.iter()
|
||||
|
|
|
@ -1,55 +1,9 @@
|
|||
use crate::models::{Mode, Mods};
|
||||
use crate::Client;
|
||||
use chrono::{DateTime, Utc};
|
||||
use rosu_v2::error::OsuError;
|
||||
use youmubot_prelude::*;
|
||||
|
||||
trait ToQuery {
|
||||
fn to_query(&self) -> Vec<(&'static str, String)>;
|
||||
}
|
||||
|
||||
impl<T: ToQuery> ToQuery for Option<T> {
|
||||
fn to_query(&self) -> Vec<(&'static str, String)> {
|
||||
match self {
|
||||
Some(ref v) => v.to_query(),
|
||||
None => vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToQuery for Mods {
|
||||
fn to_query(&self) -> Vec<(&'static str, String)> {
|
||||
vec![("mods", format!("{}", self.bits()))]
|
||||
}
|
||||
}
|
||||
|
||||
impl ToQuery for Mode {
|
||||
fn to_query(&self) -> Vec<(&'static str, String)> {
|
||||
vec![("m", (*self as u8).to_string())]
|
||||
}
|
||||
}
|
||||
|
||||
impl ToQuery for (Mode, bool) {
|
||||
fn to_query(&self) -> Vec<(&'static str, String)> {
|
||||
vec![
|
||||
("m", (self.0 as u8).to_string()),
|
||||
("a", (self.1 as u8).to_string()),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl ToQuery for (&'static str, String) {
|
||||
fn to_query(&self) -> Vec<(&'static str, String)> {
|
||||
vec![(self.0, self.1.clone())]
|
||||
}
|
||||
}
|
||||
|
||||
impl ToQuery for (&'static str, DateTime<Utc>) {
|
||||
fn to_query(&self) -> Vec<(&'static str, String)> {
|
||||
vec![(self.0, format!("{}", self.1.format("%Y-%m-%d")))]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum UserID {
|
||||
Username(String),
|
||||
ID(u64),
|
||||
|
@ -74,32 +28,12 @@ impl UserID {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToQuery for UserID {
|
||||
fn to_query(&self) -> Vec<(&'static str, String)> {
|
||||
use UserID::*;
|
||||
match self {
|
||||
Username(ref s) => vec![("u", s.clone()), ("type", "string".to_owned())],
|
||||
ID(u) => vec![("u", u.to_string()), ("type", "id".to_owned())],
|
||||
}
|
||||
}
|
||||
}
|
||||
pub enum BeatmapRequestKind {
|
||||
Beatmap(u64),
|
||||
Beatmapset(u64),
|
||||
BeatmapHash(String),
|
||||
}
|
||||
|
||||
impl ToQuery for BeatmapRequestKind {
|
||||
fn to_query(&self) -> Vec<(&'static str, String)> {
|
||||
use BeatmapRequestKind::*;
|
||||
match self {
|
||||
Beatmap(b) => vec![("b", b.to_string())],
|
||||
Beatmapset(s) => vec![("s", s.to_string())],
|
||||
BeatmapHash(ref h) => vec![("h", h.clone())],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_not_found<T>(v: Result<T, OsuError>) -> Result<Option<T>, OsuError> {
|
||||
match v {
|
||||
Ok(v) => Ok(Some(v)),
|
||||
|
|
Loading…
Add table
Reference in a new issue