use std::collections::HashMap;
use futures::channel::mpsc;
use futures_locks::RwLock;
use uuid::Uuid;
use autopush_common::errors::{ApcErrorKind, Result};
use autopush_common::notification::Notification;
use crate::protocol::ServerNotification;
#[derive(Debug)]
struct RegisteredClient {
pub uaid: Uuid,
pub uid: Uuid,
pub tx: mpsc::UnboundedSender<ServerNotification>,
}
#[derive(Default)]
pub struct ClientRegistry {
clients: RwLock<HashMap<Uuid, RegisteredClient>>,
}
impl ClientRegistry {
pub async fn connect(
&self,
uaid: Uuid,
uid: Uuid,
) -> mpsc::UnboundedReceiver<ServerNotification> {
trace!("ClientRegistry::connect");
let (tx, snotif_stream) = mpsc::unbounded();
let client = RegisteredClient { uaid, uid, tx };
let mut clients = self.clients.write().await;
if let Some(client) = clients.insert(client.uaid, client) {
let result = client.tx.unbounded_send(ServerNotification::Disconnect);
if result.is_ok() {
debug!("ClientRegistry::connect Ghosting client, new one wants to connect");
}
}
snotif_stream
}
pub async fn notify(&self, uaid: Uuid, notif: Notification) -> Result<()> {
trace!("ClientRegistry::notify");
let clients = self.clients.read().await;
if let Some(client) = clients.get(&uaid) {
debug!("ClientRegistry::notify Found a client to deliver a notification to");
let result = client
.tx
.unbounded_send(ServerNotification::Notification(notif));
if result.is_ok() {
debug!("ClientRegistry::notify Dropped notification in queue");
return Ok(());
}
}
Err(ApcErrorKind::GeneralError("User not connected".into()).into())
}
pub async fn check_storage(&self, uaid: Uuid) -> Result<()> {
trace!("ClientRegistry::check_storage");
let clients = self.clients.read().await;
if let Some(client) = clients.get(&uaid) {
let result = client.tx.unbounded_send(ServerNotification::CheckStorage);
if result.is_ok() {
debug!("ClientRegistry::check_storage Told client to check storage");
return Ok(());
}
}
Err(ApcErrorKind::GeneralError("User not connected".into()).into())
}
pub async fn disconnect(&self, uaid: &Uuid, uid: &Uuid) -> Result<()> {
trace!("ClientRegistry::disconnect");
let mut clients = self.clients.write().await;
let client_exists = clients.get(uaid).map_or(false, |client| client.uid == *uid);
if client_exists {
clients.remove(uaid).expect("Couldn't remove client?");
return Ok(());
}
Err(ApcErrorKind::GeneralError("User not connected".into()).into())
}
}