Skip to main content

open_chess_server/
lib.rs

1//! The open-chess server, as a library (the `open-chess` binary is a
2//! thin wrapper; integration tests drive the same pieces).
3
4pub mod ai;
5pub mod analyse;
6pub mod app;
7pub mod auth;
8pub mod challenges;
9pub mod cli;
10pub mod config;
11pub mod db;
12pub mod error;
13pub mod http;
14pub mod metrics;
15pub mod model;
16pub mod play;
17pub mod vision;
18
19use std::time::Duration;
20
21use tokio::sync::watch;
22use tracing::warn;
23
24/// Resolves once shutdown has begun (the watch guard isn't held, so the
25/// future stays `Send`).
26pub async fn stopped(stop: &mut watch::Receiver<bool>) {
27    let _ = stop.wait_for(|v| *v).await.map(drop);
28}
29
30/// What every serving replica runs besides HTTP: the LISTEN connection
31/// that brings other replicas' changes in, and the clock/challenge
32/// sweeper (rows are claimed with SKIP LOCKED, so replicas don't collide).
33pub fn spawn_background(ctx: &app::Ctx, stop: &watch::Receiver<bool>) {
34    tokio::spawn(ctx.db.clone().listen((*ctx.cfg).clone(), stop.clone()));
35    tokio::spawn(ai::run(ctx.clone(), stop.clone()));
36    let sweeper = ctx.clone();
37    let mut stop_sweep = stop.clone();
38    tokio::spawn(async move {
39        let mut t = tokio::time::interval(Duration::from_millis(sweeper.cfg.sweep_ms.max(100)));
40        t.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
41        loop {
42            tokio::select! {
43                _ = t.tick() => {
44                    if let Err(e) = play::sweep(&sweeper).await {
45                        warn!("sweeper: {e:#}");
46                    }
47                }
48                () = stopped(&mut stop_sweep) => break,
49            }
50        }
51    });
52}