#![warn(missing_docs)]
use std::sync::Arc;
use async_recursion::async_recursion;
use async_trait::async_trait;
use super::effects::lower_dht_action;
use super::effects::ConnectionFunctor;
use super::effects::CoreEffect;
use super::effects::CoreEffectInterpreter;
use super::MessagePayload;
use crate::dht::ChordStorageRepair;
use crate::dht::CorrectChord;
use crate::dht::Did;
use crate::dht::PeerRing;
use crate::dht::PeerRingAction;
use crate::error::Error;
use crate::error::Result;
use crate::swarm::callback::InnerSwarmCallback;
use crate::swarm::callback::SharedSwarmCallback;
use crate::swarm::transport::SwarmTransport;
pub mod connection;
pub mod custom;
pub mod e2e;
pub mod stabilization;
pub mod storage;
pub mod subring;
#[derive(Clone)]
pub struct MessageHandler {
transport: Arc<SwarmTransport>,
dht: Arc<PeerRing>,
swarm_callback: SharedSwarmCallback,
}
#[cfg_attr(feature = "wasm", async_trait(?Send))]
#[cfg_attr(not(feature = "wasm"), async_trait)]
pub trait HandleMsg<T> {
async fn handle(&self, ctx: &MessagePayload, msg: &T) -> Result<()>;
}
impl MessageHandler {
pub fn new(transport: Arc<SwarmTransport>, swarm_callback: SharedSwarmCallback) -> Self {
let dht = transport.dht.clone();
Self {
transport,
dht,
swarm_callback,
}
}
fn inner_callback(&self) -> InnerSwarmCallback {
InnerSwarmCallback::new(self.transport.clone(), self.swarm_callback.clone())
}
pub(crate) async fn run_effects<'payload>(
&self,
effects: impl IntoIterator<Item = CoreEffect<'payload>>,
) -> Result<()> {
CoreEffectInterpreter::new(&self.transport, &self.swarm_callback)
.run_all(effects)
.await
}
pub(crate) async fn connect_dht_peer(&self, peer: Did) -> Result<()> {
self.run_effects([ConnectionFunctor::connect_dht_peer(peer).into()])
.await
}
pub(crate) async fn join_dht(&self, peer: Did) -> Result<()> {
let conn = self
.transport
.get_connection(peer)
.ok_or(Error::SwarmMissDidInTable(peer))?;
let dht_ev = self.dht.join_then_sync(conn).await?;
if let Err(e) = self.handle_dht_events(&dht_ev).await {
tracing::warn!("Failed to handle dht events while joining {peer}: {e:?}");
}
Ok(())
}
pub(crate) async fn leave_dht(&self, peer: Did) -> Result<()> {
if self
.transport
.get_and_check_connection(peer)
.await
.is_none()
{
let should_repair = self
.dht
.peer_may_share_storage_responsibility(peer, self.transport.storage_redundancy())
.await?;
self.dht.remove(peer)?;
if should_repair {
let repair = self
.dht
.republish_local_entries(self.transport.storage_redundancy())
.await?;
storage::handle_storage_repair_act(self.transport.clone(), repair).await?;
}
};
Ok(())
}
#[cfg_attr(feature = "wasm", async_recursion(?Send))]
#[cfg_attr(not(feature = "wasm"), async_recursion)]
pub(crate) async fn handle_dht_events(&self, act: &PeerRingAction) -> Result<()> {
match act {
PeerRingAction::MultiActions(acts) => {
let jobs = acts
.iter()
.map(|act| async move { self.handle_dht_events(act).await });
for res in futures::future::join_all(jobs).await {
if res.is_err() {
tracing::error!("Failed on handle multi actions: {:#?}", res)
}
}
Ok(())
}
act => {
let effects =
lower_dht_action(act, |did| self.transport.get_connection(did).is_some())?;
self.run_effects(effects).await
}
}
}
}