Handle failures and record chewing

This commit is contained in:
Natsu Kagami 2021-02-08 01:18:22 +09:00
parent 3a89c009da
commit edaa461d78
Signed by: nki
GPG key ID: 7306B3D3C3AD6E51
3 changed files with 35 additions and 22 deletions

View file

@ -46,29 +46,25 @@ impl youmubot_prelude::Announcer for Announcer {
) -> Result<()> { ) -> Result<()> {
// For each user... // For each user...
let data = OsuSavedUsers::open(&*d.read().await).borrow()?.clone(); let data = OsuSavedUsers::open(&*d.read().await).borrow()?.clone();
let now = chrono::Utc::now();
let data = data let data = data
.into_iter() .into_iter()
.map(|(user_id, osu_user)| { .map(|(user_id, osu_user)| {
let d = d.clone();
let channels = &channels; let channels = &channels;
let c = c.clone(); let ctx = Context {
c: c.clone(),
data: d.clone(),
};
let s = &self; let s = &self;
async move { async move {
let channels = channels.channels_of(c.clone(), user_id).await; let channels = channels.channels_of(ctx.c.clone(), user_id).await;
if channels.is_empty() { if channels.is_empty() {
return (user_id, osu_user); // We don't wanna update an user without any active server return (user_id, osu_user); // We don't wanna update an user without any active server
} }
let pp = match (&[Mode::Std, Mode::Taiko, Mode::Catch, Mode::Mania]) let pp = match (&[Mode::Std, Mode::Taiko, Mode::Catch, Mode::Mania])
.into_iter() .into_iter()
.map(|m| { .map(|m| {
s.handle_user_mode( s.handle_user_mode(&ctx, now, &osu_user, user_id, channels.clone(), *m)
c.clone(),
&osu_user,
user_id,
channels.clone(),
*m,
d.clone(),
)
}) })
.collect::<stream::FuturesOrdered<_>>() .collect::<stream::FuturesOrdered<_>>()
.try_collect::<Vec<_>>() .try_collect::<Vec<_>>()
@ -77,15 +73,21 @@ impl youmubot_prelude::Announcer for Announcer {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
eprintln!("osu: Cannot update {}: {}", osu_user.id, e); eprintln!("osu: Cannot update {}: {}", osu_user.id, e);
return (user_id, osu_user); return (
user_id,
OsuUser {
failures: Some(osu_user.failures.unwrap_or(0) + 1),
..osu_user
},
);
} }
}; };
let last_update = chrono::Utc::now();
( (
user_id, user_id,
OsuUser { OsuUser {
pp, pp,
last_update, last_update: now,
failures: None,
..osu_user ..osu_user
}, },
) )
@ -100,9 +102,17 @@ impl youmubot_prelude::Announcer for Announcer {
let mut db = db.borrow_mut()?; let mut db = db.borrow_mut()?;
data.into_iter() data.into_iter()
.for_each(|(k, v)| match db.get(&k).map(|v| v.last_update.clone()) { .for_each(|(k, v)| match db.get(&k).map(|v| v.last_update.clone()) {
Some(d) if d > v.last_update => (), Some(d) if d > now => (),
_ => { _ => {
db.insert(k, v); if v.failures.unwrap_or(0) > 5 {
eprintln!(
"osu: Removing user {} [{}] due to 5 consecutive failures",
k, v.id
);
db.remove(&k);
} else {
db.insert(k, v);
}
} }
}); });
Ok(()) Ok(())
@ -113,14 +123,14 @@ impl Announcer {
/// 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.
async fn handle_user_mode( async fn handle_user_mode(
&self, &self,
c: Arc<CacheAndHttp>, ctx: &Context,
now: chrono::DateTime<chrono::Utc>,
osu_user: &OsuUser, osu_user: &OsuUser,
user_id: UserId, user_id: UserId,
channels: Vec<ChannelId>, channels: Vec<ChannelId>,
mode: Mode, mode: Mode,
d: AppData,
) -> Result<Option<f64>, Error> { ) -> Result<Option<f64>, Error> {
let days_since_last_update = (chrono::Utc::now() - osu_user.last_update).num_days() + 1; let days_since_last_update = (now - osu_user.last_update).num_days() + 1;
let last_update = osu_user.last_update.clone(); let last_update = osu_user.last_update.clone();
let (scores, user) = { let (scores, user) = {
let scores = self.scan_user(osu_user, mode).await?; let scores = self.scan_user(osu_user, mode).await?;
@ -136,19 +146,20 @@ impl Announcer {
}; };
let client = self.client.clone(); let client = self.client.clone();
let pp = user.pp; let pp = user.pp;
let ctx = ctx.clone();
spawn_future(async move { spawn_future(async move {
let event_scores = user let event_scores = user
.events .events
.iter() .iter()
.filter_map(|u| u.to_event_rank()) .filter_map(|u| u.to_event_rank())
.filter(|u| u.mode == mode && u.date > last_update) .filter(|u| u.mode == mode && u.date > last_update && u.date <= now)
.map(|ev| CollectedScore::from_event(&*client, &user, ev, user_id, &channels[..])) .map(|ev| CollectedScore::from_event(&*client, &user, ev, user_id, &channels[..]))
.collect::<stream::FuturesUnordered<_>>() .collect::<stream::FuturesUnordered<_>>()
.filter_map(|u| future::ready(u.pls_ok())) .filter_map(|u| future::ready(u.pls_ok()))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.await; .await;
let top_scores = scores.into_iter().filter_map(|(rank, score)| { let top_scores = scores.into_iter().filter_map(|(rank, score)| {
if score.date > last_update { if score.date > last_update && score.date <= now {
Some(CollectedScore::from_top_score( Some(CollectedScore::from_top_score(
&user, &user,
score, score,
@ -161,7 +172,6 @@ impl Announcer {
None None
} }
}); });
let ctx = Context { data: d, c };
event_scores event_scores
.into_iter() .into_iter()
.chain(top_scores) .chain(top_scores)

View file

@ -23,4 +23,6 @@ pub struct OsuUser {
pub last_update: DateTime<Utc>, pub last_update: DateTime<Utc>,
#[serde(default)] #[serde(default)]
pub pp: Vec<Option<f64>>, pub pp: Vec<Option<f64>>,
/// More than 5 failures => gone
pub failures: Option<u8>,
} }

View file

@ -249,6 +249,7 @@ fn add_user(target: serenity::model::id::UserId, user_id: u64, data: &TypeMap) -
target, target,
OsuUser { OsuUser {
id: user_id, id: user_id,
failures: None,
last_update: chrono::Utc::now(), last_update: chrono::Utc::now(),
pp: vec![], pp: vec![],
}, },