use bloop_server_framework::event::Event;
use bloop_server_framework::nfc_uid::NfcUid;
use bloop_server_framework::player::{PlayerInfo, PlayerMutator};
use chrono::{DateTime, Utc};
use hex::FromHex;
use std::collections::HashMap;
use std::convert::Infallible;
use tokio::sync::broadcast;
use tokio::sync::broadcast::error::RecvError;
use tokio_graceful_shutdown::{FutureExt, IntoSubsystem, SubsystemHandle};
use tracing::{debug, warn};
use uuid::{Uuid, uuid};
#[derive(Debug)]
pub struct Player {
pub id: Uuid,
pub nfc_uid: NfcUid,
pub total_bloops: usize,
pub awarded_achievements: HashMap<Uuid, DateTime<Utc>>,
}
impl PlayerInfo for Player {
fn id(&self) -> Uuid {
self.id
}
fn nfc_uid(&self) -> NfcUid {
self.nfc_uid
}
fn total_bloops(&self) -> usize {
self.total_bloops
}
fn awarded_achievements(&self) -> &HashMap<Uuid, DateTime<Utc>> {
&self.awarded_achievements
}
}
impl PlayerMutator for Player {
fn increment_bloops(&mut self) {
self.total_bloops += 1;
}
fn add_awarded_achievement(&mut self, achievement_id: Uuid, awarded_at: DateTime<Utc>) {
self.awarded_achievements.insert(achievement_id, awarded_at);
}
}
pub struct DummyPlayerRepository;
impl DummyPlayerRepository {
pub async fn load_all(&self) -> Result<Vec<Player>, Infallible> {
let player = Player {
id: uuid!("5e9e052c-c276-49f6-8f4d-1e05af0040be"),
nfc_uid: NfcUid::from_hex("ababababababab").unwrap(),
total_bloops: 0,
awarded_achievements: HashMap::new(),
};
Ok(vec![player])
}
}
pub struct AwardedAchievementsPersister {
pub event_rx: broadcast::Receiver<Event>,
}
impl AwardedAchievementsPersister {
pub async fn process_events(&mut self) -> anyhow::Result<()> {
loop {
match self.event_rx.recv().await {
Ok(Event::AchievementsAwarded(_awarded)) => {
}
Ok(_) => {}
Err(RecvError::Lagged(n)) => {
warn!(
"AwardedAchievementsPersister lagged by {n} messages, some achievements were missed"
);
}
Err(RecvError::Closed) => {
debug!("AwardedAchievementsPersister event stream closed, exiting event loop");
break;
}
}
}
Ok(())
}
}
impl IntoSubsystem<anyhow::Error> for AwardedAchievementsPersister {
async fn run(mut self, subsys: &mut SubsystemHandle) -> anyhow::Result<()> {
let _ = self.process_events().cancel_on_shutdown(subsys).await;
Ok(())
}
}