mod bloop;
mod player;
use crate::bloop::DummyBloopRepository;
use crate::player::{AwardedAchievementsPersister, DummyPlayerRepository, Player};
use argon2::password_hash::PasswordHashString;
use bloop_server_framework::achievement::AchievementBuilder;
use bloop_server_framework::bloop::ProcessedBloopSinkBuilder;
use bloop_server_framework::engine::EngineBuilder;
use bloop_server_framework::evaluator::min_bloops::MinBloopsEvaluator;
use bloop_server_framework::network::NetworkListenerBuilder;
use bloop_server_framework::player::PlayerRegistry;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::{Mutex, RwLock, broadcast, mpsc};
use tokio_graceful_shutdown::{IntoSubsystem, SubsystemBuilder, SubsystemHandle, Toplevel};
use uuid::uuid;
pub type Achievement = bloop_server_framework::achievement::Achievement<(), Player, (), ()>;
const BLOOP_RETENTION: Duration = Duration::from_secs(60 * 30);
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let achievement = AchievementBuilder::new()
.id(uuid!("565fd1d0-d973-4870-b9db-9574fa6d81d2"))
.evaluator(MinBloopsEvaluator::new(1))
.build()?;
let achievements: Vec<Achievement> = vec![achievement];
let player_repository = DummyPlayerRepository;
let players = player_repository.load_all().await?;
let player_registry = PlayerRegistry::new(players);
let bloop_repository = DummyBloopRepository;
let bloops = bloop_repository
.load_recent(&player_registry, BLOOP_RETENTION)
.await?;
let player_registry = Arc::new(Mutex::new(player_registry));
let mut clients = HashMap::new();
clients.insert(
"test".to_string(),
PasswordHashString::new(
"$argon2id$v=19$m=16,t=2,p=1$NEZFVERXYlFGVFA2SW1CVQ$9YXEyfXaMMr8XmP6D3x2pg",
)
.unwrap(),
);
let clients = Arc::new(RwLock::new(clients));
let (engine_tx, engine_rx) = mpsc::channel(512);
let (event_tx, event_rx) = broadcast::channel(512);
let engine = EngineBuilder::new()
.player_registry(player_registry)
.achievements(achievements)
.bloops(bloops)
.bloop_retention(Duration::from_secs(60 * 30))
.audio_base_path("./audio")
.network_rx(engine_rx)
.event_tx(event_tx.clone())
.build()?;
let network_listener = NetworkListenerBuilder::new()
.address("[::]:4500")
.cert_path("examples/cert.pem")
.key_path("examples/key.pem")
.clients(clients)
.event_tx(event_tx.clone())
.engine_tx(engine_tx)
.build()?;
let processed_bloop_sink = ProcessedBloopSinkBuilder::new()
.repository(bloop_repository)
.max_batch_size(500)
.max_batch_duration(Duration::from_secs(60))
.event_rx(event_rx)
.build()?;
let awarded_achievements_persister = AwardedAchievementsPersister {
event_rx: event_tx.subscribe(),
};
Toplevel::new(async |s: &mut SubsystemHandle| {
s.start(SubsystemBuilder::new("Engine", engine.into_subsystem()));
s.start(SubsystemBuilder::new(
"NetworkListener",
network_listener.into_subsystem(),
));
s.start(SubsystemBuilder::new(
"ProcessedBloopSink",
processed_bloop_sink.into_subsystem(),
));
s.start(SubsystemBuilder::new(
"AwardedAchievementsPersister",
awarded_achievements_persister.into_subsystem(),
));
})
.catch_signals()
.handle_shutdown_requests(Duration::from_secs(1))
.await
.map_err(Into::into)
}