rings_core/message/handlers/
mod.rs1#![warn(missing_docs)]
2use std::sync::Arc;
5
6use async_recursion::async_recursion;
7use async_trait::async_trait;
8
9use super::effects::lower_dht_action;
10use super::effects::ConnectionFunctor;
11use super::effects::CoreEffect;
12use super::effects::CoreEffectInterpreter;
13use super::MessagePayload;
14use crate::dht::ChordStorageRepair;
15use crate::dht::CorrectChord;
16use crate::dht::Did;
17use crate::dht::PeerRing;
18use crate::dht::PeerRingAction;
19use crate::error::Error;
20use crate::error::Result;
21use crate::swarm::callback::InnerSwarmCallback;
22use crate::swarm::callback::SharedSwarmCallback;
23use crate::swarm::transport::SwarmTransport;
24
25pub mod connection;
27pub mod custom;
29pub mod e2e;
31pub mod stabilization;
33pub mod storage;
35pub mod subring;
37
38#[derive(Clone)]
43pub struct MessageHandler {
44 transport: Arc<SwarmTransport>,
45 dht: Arc<PeerRing>,
46 swarm_callback: SharedSwarmCallback,
47}
48
49#[cfg_attr(feature = "wasm", async_trait(?Send))]
51#[cfg_attr(not(feature = "wasm"), async_trait)]
52pub trait HandleMsg<T> {
53 async fn handle(&self, ctx: &MessagePayload, msg: &T) -> Result<()>;
55}
56
57impl MessageHandler {
58 pub fn new(transport: Arc<SwarmTransport>, swarm_callback: SharedSwarmCallback) -> Self {
60 let dht = transport.dht.clone();
61 Self {
62 transport,
63 dht,
64 swarm_callback,
65 }
66 }
67
68 fn inner_callback(&self) -> InnerSwarmCallback {
69 InnerSwarmCallback::new(self.transport.clone(), self.swarm_callback.clone())
70 }
71
72 pub(crate) async fn run_effects<'payload>(
73 &self,
74 effects: impl IntoIterator<Item = CoreEffect<'payload>>,
75 ) -> Result<()> {
76 CoreEffectInterpreter::new(&self.transport, &self.swarm_callback)
77 .run_all(effects)
78 .await
79 }
80
81 pub(crate) async fn connect_dht_peer(&self, peer: Did) -> Result<()> {
87 self.run_effects([ConnectionFunctor::connect_dht_peer(peer).into()])
88 .await
89 }
90
91 pub(crate) async fn connect_dht_peers(
93 &self,
94 peers: impl IntoIterator<Item = Did>,
95 ) -> Result<()> {
96 for peer in self.transport.order_dht_candidates_by_quality(peers).await {
97 self.connect_dht_peer(peer).await?;
98 }
99 Ok(())
100 }
101
102 pub(crate) async fn join_dht(&self, peer: Did) -> Result<()> {
103 let conn = self
106 .transport
107 .get_connection(peer)
108 .ok_or(Error::SwarmMissDidInTable(peer))?;
109 let dht_ev = self.dht.join_then_sync(conn).await?;
110 if let Err(e) = self.handle_dht_events(&dht_ev).await {
114 tracing::warn!("Failed to handle dht events while joining {peer}: {e:?}");
115 }
116 Ok(())
117 }
118
119 pub(crate) async fn leave_dht(&self, peer: Did) -> Result<()> {
120 if self
121 .transport
122 .get_and_check_connection(peer)
123 .await
124 .is_none()
125 {
126 let should_repair = self
127 .dht
128 .peer_may_share_storage_responsibility(peer, self.transport.storage_redundancy())
129 .await?;
130 self.dht.remove(peer)?;
131 if should_repair {
132 let repair = self
133 .dht
134 .republish_local_entries(self.transport.storage_redundancy())
135 .await?;
136 storage::handle_storage_repair_act(self.transport.clone(), repair).await?;
137 }
138 };
139 Ok(())
140 }
141
142 fn collect_dht_effects(
143 &self,
144 act: &PeerRingAction,
145 effects: &mut Vec<CoreEffect<'static>>,
146 ) -> Result<()> {
147 match act {
148 PeerRingAction::MultiActions(acts) => {
149 for act in acts {
150 self.collect_dht_effects(act, effects)?;
151 }
152 Ok(())
153 }
154 act => {
155 if let Some(effect) =
156 lower_dht_action(act, |did| self.transport.get_connection(did).is_some())?
157 {
158 effects.push(effect);
159 }
160 Ok(())
161 }
162 }
163 }
164
165 async fn run_prioritized_dht_effects(&self, effects: Vec<CoreEffect<'static>>) -> Result<()> {
166 let mut connection_peers = Vec::new();
167 let mut other_effects = Vec::new();
168 for effect in effects {
169 match effect {
170 CoreEffect::Connection(ConnectionFunctor::ConnectDhtPeer { peer }) => {
171 connection_peers.push(peer);
172 }
173 effect => other_effects.push(effect),
174 }
175 }
176
177 for peer in self
178 .transport
179 .order_dht_candidates_by_quality(connection_peers)
180 .await
181 {
182 if let Err(e) = self.connect_dht_peer(peer).await {
183 tracing::error!("Failed on handle multi connection action: {e:?}");
184 }
185 }
186
187 for effect in other_effects {
188 if let Err(e) = self.run_effects([effect]).await {
189 tracing::error!("Failed on handle multi action: {e:?}");
190 }
191 }
192
193 Ok(())
194 }
195
196 #[cfg_attr(feature = "wasm", async_recursion(?Send))]
197 #[cfg_attr(not(feature = "wasm"), async_recursion)]
198 pub(crate) async fn handle_dht_events(&self, act: &PeerRingAction) -> Result<()> {
199 if matches!(act, PeerRingAction::MultiActions(_)) {
200 let mut effects = Vec::new();
201 self.collect_dht_effects(act, &mut effects)?;
202 self.run_prioritized_dht_effects(effects).await
203 } else {
204 let effects =
205 lower_dht_action(act, |did| self.transport.get_connection(did).is_some())?;
206 self.run_effects(effects).await
207 }
208 }
209}