1use std::{
2 collections::{HashMap, HashSet},
3 sync::Arc,
4};
5
6use log::{error, info, warn};
7
8use karyon_core::{
9 async_runtime::{lock::RwLock, Executor},
10 async_util::{TaskGroup, TaskResult},
11};
12
13use karyon_eventemitter::{EventEmitter, EventListener, EventTopic, EventValue};
14
15use karyon_net::Endpoint;
16
17use crate::{
18 access_control::{Action, PeerCandidate, Subject},
19 config::Config,
20 conn_queue::{ConnQueue, QueuedConn},
21 handshake::{handshake, HandshakeParams},
22 monitor::{Monitor, PoolEvent},
23 peer::{ConnDirection, Peer},
24 protocol::{Protocol, ProtocolConstructor, ProtocolID, ProtocolMeta},
25 Error, PeerID, Result,
26};
27
28#[derive(Hash, PartialEq, Eq, Debug, Clone)]
30pub enum PeerEventTopic {
31 Lifecycle,
32}
33
34#[derive(Debug, Clone, EventValue)]
37pub enum PeerEvent {
38 Added(PeerID),
40 Removed(PeerID),
42 HandshakeFailed(Option<PeerID>),
44}
45
46impl EventTopic for PeerEvent {
47 type Topic = PeerEventTopic;
48 fn topic() -> Self::Topic {
49 PeerEventTopic::Lifecycle
50 }
51}
52
53pub struct PeerPool {
54 pub id: PeerID,
56
57 conn_queue: Arc<ConnQueue>,
59
60 peers: RwLock<HashMap<PeerID, Arc<Peer>>>,
62
63 pub(crate) protocols: RwLock<HashMap<ProtocolID, Box<ProtocolConstructor>>>,
65
66 pub(crate) protocol_meta: RwLock<HashMap<ProtocolID, ProtocolMeta>>,
70
71 peer_emitter: Arc<EventEmitter<PeerEventTopic>>,
74
75 task_group: TaskGroup,
77
78 pub(crate) executor: Executor,
80
81 pub(crate) config: Arc<Config>,
83
84 monitor: Arc<Monitor>,
86}
87
88impl PeerPool {
89 pub fn new(
91 id: &PeerID,
92 conn_queue: Arc<ConnQueue>,
93 config: Arc<Config>,
94 monitor: Arc<Monitor>,
95 executor: Executor,
96 ) -> Arc<Self> {
97 Arc::new(Self {
98 id: id.clone(),
99 conn_queue,
100 peers: RwLock::new(HashMap::new()),
101 protocols: RwLock::new(HashMap::new()),
102 protocol_meta: RwLock::new(HashMap::new()),
103 peer_emitter: EventEmitter::new(),
104 task_group: TaskGroup::with_executor(executor.clone()),
105 executor,
106 monitor,
107 config,
108 })
109 }
110
111 pub fn register_peer_events(&self) -> EventListener<PeerEventTopic, PeerEvent> {
113 self.peer_emitter.register(&PeerEventTopic::Lifecycle)
114 }
115
116 pub async fn start(self: &Arc<Self>) -> Result<()> {
118 self.task_group.spawn(self.clone().run());
119 Ok(())
120 }
121
122 pub async fn shutdown(&self) {
124 for peer in self.peers.read().await.values() {
125 let _ = peer.shutdown().await;
126 }
127
128 self.task_group.cancel().await;
129 }
130
131 pub async fn attach_protocol<P: Protocol>(&self, c: Box<ProtocolConstructor>) -> Result<()> {
134 let id = P::id();
135 self.protocols.write().await.insert(id.clone(), c);
136 self.protocol_meta.write().await.insert(
137 id,
138 ProtocolMeta {
139 version: P::version()?,
140 kind: P::kind(),
141 },
142 );
143 Ok(())
144 }
145
146 pub async fn broadcast(&self, proto_id: &ProtocolID, msg: Vec<u8>) {
148 for (pid, peer) in self.peers.read().await.iter() {
149 if let Err(err) = peer.send(proto_id.to_string(), msg.clone()).await {
150 error!("failed to send msg to {pid}: {err}");
151 continue;
152 }
153 }
154 }
155
156 pub async fn broadcast_to(
158 &self,
159 proto_id: &ProtocolID,
160 msg: Vec<u8>,
161 targets: &HashSet<PeerID>,
162 ) {
163 for (pid, peer) in self.peers.read().await.iter() {
164 if !targets.contains(pid) {
165 continue;
166 }
167 if let Err(err) = peer.send(proto_id.to_string(), msg.clone()).await {
168 error!("failed to send msg to {pid}: {err}");
169 }
170 }
171 }
172
173 pub async fn send_to(
176 &self,
177 peer_id: &PeerID,
178 proto_id: &ProtocolID,
179 msg: Vec<u8>,
180 ) -> Result<()> {
181 let peers = self.peers.read().await;
182 let peer = peers
183 .get(peer_id)
184 .ok_or_else(|| Error::PeerNotFound(peer_id.to_string()))?;
185 peer.send(proto_id.to_string(), msg).await
186 }
187
188 pub async fn peer_protocol_set(&self, pid: &PeerID) -> Option<HashSet<ProtocolID>> {
190 self.peers
191 .read()
192 .await
193 .get(pid)
194 .map(|p| p.negotiated_protocols().clone())
195 }
196
197 pub async fn contains_peer(&self, pid: &PeerID) -> bool {
199 self.peers.read().await.contains_key(pid)
200 }
201
202 pub async fn peers_len(&self) -> usize {
204 self.peers.read().await.len()
205 }
206
207 pub async fn inbound_peers(&self) -> HashMap<PeerID, Endpoint> {
209 let mut peers = HashMap::new();
210 for (id, peer) in self.peers.read().await.iter() {
211 if peer.is_inbound() {
212 peers.insert(id.clone(), peer.remote_endpoint().clone());
213 }
214 }
215 peers
216 }
217
218 pub async fn outbound_peers(&self) -> HashMap<PeerID, Endpoint> {
220 let mut peers = HashMap::new();
221 for (id, peer) in self.peers.read().await.iter() {
222 if !peer.is_inbound() {
223 peers.insert(id.clone(), peer.remote_endpoint().clone());
224 }
225 }
226 peers
227 }
228
229 async fn run(self: Arc<Self>) {
230 loop {
231 let mut queued = self.conn_queue.next().await;
232
233 let meta = self.protocol_meta.read().await.clone();
237
238 let params = HandshakeParams {
239 own_id: &self.id,
240 is_inbound: matches!(queued.direction, ConnDirection::Inbound),
241 config_version: &self.config.version,
242 protocols: &meta,
243 timeout_secs: self.config.handshake_timeout,
244 verified_peer_id: queued.verified_peer_id.as_ref(),
245 };
246 let handshake = handshake(&mut queued.reader, &mut queued.writer, ¶ms).await;
247
248 let (pid, negotiated) = match handshake {
249 Ok(v) => v,
250 Err(err) => {
251 let pid = queued.verified_peer_id.clone();
252 self.monitor
253 .notify(PoolEvent::HandshakeFailed(pid.clone()))
254 .await;
255 let _ = self
256 .peer_emitter
257 .emit(&PeerEvent::HandshakeFailed(pid))
258 .await;
259 let _ = queued.disconnect_signal.send(Err(err)).await;
260 continue;
261 }
262 };
263
264 let candidate = PeerCandidate {
267 peer_id: &pid,
268 remote_endpoint: &queued.remote_endpoint,
269 negotiated_protocols: &negotiated,
270 };
271 let allowed = self.config.access_control.allow(
272 &Subject::Peer(&candidate),
273 Action::Connect(queued.direction.clone()),
274 );
275
276 if !allowed {
277 warn!("Access denied for peer {pid}");
278 self.monitor
279 .notify(PoolEvent::HandshakeFailed(Some(pid.clone())))
280 .await;
281 let _ = self
282 .peer_emitter
283 .emit(&PeerEvent::HandshakeFailed(Some(pid)))
284 .await;
285 let _ = queued
286 .disconnect_signal
287 .send(Err(Error::AccessDenied))
288 .await;
289 continue;
290 }
291
292 if let Err(err) = self.new_peer(queued, pid, negotiated).await {
293 error!("new_peer failed: {err}");
294 }
295 }
296 }
297
298 async fn new_peer(
300 self: &Arc<Self>,
301 queued: QueuedConn,
302 pid: PeerID,
303 negotiated: Vec<ProtocolID>,
304 ) -> Result<()> {
305 if self.contains_peer(&pid).await {
306 self.monitor
307 .notify(PoolEvent::PeerAlreadyConnected(pid.clone()))
308 .await;
309 let _ = queued
310 .disconnect_signal
311 .send(Err(Error::PeerAlreadyConnected))
312 .await;
313 return Err(Error::PeerAlreadyConnected);
314 }
315
316 let protocol_ids: Vec<ProtocolID> = self.protocols.read().await.keys().cloned().collect();
317 let negotiated: HashSet<ProtocolID> = negotiated.into_iter().collect();
318
319 let peer = Peer::new(self.clone(), queued, pid.clone(), negotiated, protocol_ids).await?;
320
321 self.peers.write().await.insert(pid.clone(), peer.clone());
322
323 let on_disconnect = {
324 let this = self.clone();
325 let pid = pid.clone();
326 |result| async move {
327 if let TaskResult::Completed(_) = result {
328 if let Err(err) = this.remove_peer(&pid).await {
329 error!("Failed to remove peer {pid}: {err}");
330 }
331 }
332 }
333 };
334
335 self.task_group
336 .spawn_then(peer.clone().run(), on_disconnect);
337
338 info!("Add new peer {pid}");
339 self.monitor.notify(PoolEvent::NewPeer(pid.clone())).await;
340 let _ = self.peer_emitter.emit(&PeerEvent::Added(pid)).await;
341
342 Ok(())
343 }
344
345 async fn remove_peer(&self, pid: &PeerID) -> Result<()> {
347 let result = self.peers.write().await.remove(pid);
348
349 let peer = match result {
350 Some(p) => p,
351 None => return Ok(()),
352 };
353
354 let _ = peer.shutdown().await;
355
356 self.monitor
357 .notify(PoolEvent::RemovePeer(pid.clone()))
358 .await;
359 let _ = self
360 .peer_emitter
361 .emit(&PeerEvent::Removed(pid.clone()))
362 .await;
363
364 warn!("Peer {pid} removed",);
365 Ok(())
366 }
367}