use std::{collections::BTreeMap, fmt, sync::Arc};
use aranya_runtime::{ClientState, PeerCache};
use derive_where::derive_where;
use tokio::sync::{Mutex, MutexGuard};
use crate::sync::SyncPeer;
pub(crate) type PeerCacheMap = Arc<Mutex<BTreeMap<SyncPeer, PeerCache>>>;
mod invalid_graphs {
use std::{collections::HashSet, sync::RwLock};
use aranya_runtime::GraphId;
#[derive(Debug, Default)]
pub(crate) struct InvalidGraphs {
map: RwLock<HashSet<GraphId>>,
}
impl InvalidGraphs {
pub fn insert(&self, graph_id: GraphId) {
#[allow(clippy::expect_used)]
self.map.write().expect("poisoned").insert(graph_id);
}
pub fn contains(&self, graph_id: GraphId) -> bool {
#[allow(clippy::expect_used)]
self.map.read().expect("poisoned").contains(&graph_id)
}
}
}
pub(crate) use invalid_graphs::InvalidGraphs;
#[derive_where(Clone)]
pub struct Client<PS, SP> {
aranya: Arc<Mutex<ClientState<PS, SP>>>,
caches: PeerCacheMap,
invalid_graphs: Arc<InvalidGraphs>,
}
impl<PS, SP> fmt::Debug for Client<PS, SP> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Client").finish_non_exhaustive()
}
}
impl<PS, SP> Client<PS, SP> {
pub fn new(aranya: ClientState<PS, SP>) -> Self {
Self {
aranya: Arc::new(Mutex::new(aranya)),
caches: Arc::default(),
invalid_graphs: Arc::default(),
}
}
pub async fn lock_aranya(&self) -> MutexGuard<'_, ClientState<PS, SP>> {
self.aranya.lock().await
}
pub(crate) async fn lock_aranya_and_caches(
&self,
) -> (
MutexGuard<'_, ClientState<PS, SP>>,
MutexGuard<'_, BTreeMap<SyncPeer, PeerCache>>,
) {
let aranya = self.lock_aranya().await;
let caches = self.caches.lock().await;
(aranya, caches)
}
pub(crate) fn invalid_graphs(&self) -> &InvalidGraphs {
&self.invalid_graphs
}
#[cfg(test)]
pub(crate) fn caches_for_test(&self) -> PeerCacheMap {
Arc::clone(&self.caches)
}
}