werewolves/werewolves-server/src/communication/connect.rs

75 lines
2.3 KiB
Rust
Raw Normal View History

// Copyright (C) 2025 Emilis Bliūdžius
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2025-10-04 09:26:37 +01:00
use core::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tokio::sync::Mutex;
use werewolves_proto::player::PlayerId;
#[derive(Debug, Clone)]
pub struct ConnectUpdate {
updated: Arc<AtomicBool>,
connected: Arc<Mutex<Vec<PlayerId>>>,
}
impl ConnectUpdate {
pub fn new() -> Self {
Self {
updated: Arc::new(AtomicBool::new(false)),
connected: Arc::new(Mutex::new(Vec::new())),
}
}
pub async fn connect(&self, pid: PlayerId) {
let mut connected = self.connected.lock().await;
if connected.iter().any(|c| c == &pid) {
return;
}
connected.push(pid);
self.updated.store(true, Ordering::SeqCst);
}
pub async fn disconnect(&self, pid: PlayerId) {
let mut connected = self.connected.lock().await;
if let Some(idx) = connected
.iter()
.enumerate()
.find_map(|(idx, c)| (c == &pid).then_some(idx))
{
connected.swap_remove(idx);
self.updated.store(true, Ordering::SeqCst);
}
}
}
impl Future for ConnectUpdate {
type Output = Arc<[PlayerId]>;
fn poll(
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
if self.updated.load(Ordering::SeqCst)
&& let Ok(connected) = self.connected.try_lock()
{
self.updated.store(false, Ordering::SeqCst);
std::task::Poll::Ready(connected.clone().into())
} else {
cx.waker().wake_by_ref();
std::task::Poll::Pending
}
}
}