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 type PeerEventListener = EventListener<PeerEventTopic, PeerEvent>;
55
56pub struct PeerPool {
57 pub id: PeerID,
59
60 conn_queue: Arc<ConnQueue>,
62
63 peers: RwLock<HashMap<PeerID, Arc<Peer>>>,
65
66 pub(crate) protocols: RwLock<HashMap<ProtocolID, Box<ProtocolConstructor>>>,
68
69 pub(crate) protocol_meta: RwLock<HashMap<ProtocolID, ProtocolMeta>>,
73
74 peer_emitter: Arc<EventEmitter<PeerEventTopic>>,
77
78 task_group: TaskGroup,
80
81 pub(crate) executor: Executor,
83
84 pub(crate) config: Arc<Config>,
86
87 monitor: Arc<Monitor>,
89}
90
91impl PeerPool {
92 pub fn new(
94 id: &PeerID,
95 conn_queue: Arc<ConnQueue>,
96 config: Arc<Config>,
97 monitor: Arc<Monitor>,
98 executor: Executor,
99 ) -> Arc<Self> {
100 Arc::new(Self {
101 id: id.clone(),
102 conn_queue,
103 peers: RwLock::new(HashMap::new()),
104 protocols: RwLock::new(HashMap::new()),
105 protocol_meta: RwLock::new(HashMap::new()),
106 peer_emitter: EventEmitter::new(),
107 task_group: TaskGroup::with_executor(executor.clone()),
108 executor,
109 monitor,
110 config,
111 })
112 }
113
114 pub fn register_peer_events(&self) -> EventListener<PeerEventTopic, PeerEvent> {
116 self.peer_emitter.register(&PeerEventTopic::Lifecycle)
117 }
118
119 pub async fn start(self: &Arc<Self>) -> Result<()> {
121 self.task_group.spawn(self.clone().run());
122 Ok(())
123 }
124
125 pub async fn shutdown(&self) {
127 self.task_group.cancel().await;
131
132 for peer in self.peers.read().await.values() {
133 let _ = peer.shutdown().await;
134 }
135 }
136
137 pub async fn attach_protocol<P: Protocol>(&self, c: Box<ProtocolConstructor>) -> Result<()> {
140 let id = P::id();
141 self.protocols.write().await.insert(id.clone(), c);
142 self.protocol_meta.write().await.insert(
143 id,
144 ProtocolMeta {
145 version: P::version()?,
146 flags: P::flags(),
147 },
148 );
149 Ok(())
150 }
151
152 pub async fn broadcast(&self, proto_id: &ProtocolID, msg: Vec<u8>) {
154 for (pid, peer) in self.peers.read().await.iter() {
155 if let Err(err) = peer.send(proto_id.to_string(), msg.clone()).await {
156 error!("failed to send msg to {pid}: {err}");
157 continue;
158 }
159 }
160 }
161
162 pub async fn broadcast_to(
164 &self,
165 proto_id: &ProtocolID,
166 msg: Vec<u8>,
167 targets: &HashSet<PeerID>,
168 ) {
169 for (pid, peer) in self.peers.read().await.iter() {
170 if !targets.contains(pid) {
171 continue;
172 }
173 if let Err(err) = peer.send(proto_id.to_string(), msg.clone()).await {
174 error!("failed to send msg to {pid}: {err}");
175 }
176 }
177 }
178
179 pub async fn send_to(
182 &self,
183 peer_id: &PeerID,
184 proto_id: &ProtocolID,
185 msg: Vec<u8>,
186 ) -> Result<()> {
187 let peers = self.peers.read().await;
188 let peer = peers
189 .get(peer_id)
190 .ok_or_else(|| Error::PeerNotFound(peer_id.to_string()))?;
191 peer.send(proto_id.to_string(), msg).await
192 }
193
194 pub async fn peer_protocol_set(&self, pid: &PeerID) -> Option<HashSet<ProtocolID>> {
196 self.peers
197 .read()
198 .await
199 .get(pid)
200 .map(|p| p.negotiated_protocols().clone())
201 }
202
203 pub async fn contains_peer(&self, pid: &PeerID) -> bool {
205 self.peers.read().await.contains_key(pid)
206 }
207
208 pub async fn peers_len(&self) -> usize {
210 self.peers.read().await.len()
211 }
212
213 pub async fn inbound_peers(&self) -> HashMap<PeerID, Endpoint> {
215 let mut peers = HashMap::new();
216 for (id, peer) in self.peers.read().await.iter() {
217 if peer.is_inbound() {
218 peers.insert(id.clone(), peer.remote_endpoint().clone());
219 }
220 }
221 peers
222 }
223
224 pub async fn outbound_peers(&self) -> HashMap<PeerID, Endpoint> {
226 let mut peers = HashMap::new();
227 for (id, peer) in self.peers.read().await.iter() {
228 if !peer.is_inbound() {
229 peers.insert(id.clone(), peer.remote_endpoint().clone());
230 }
231 }
232 peers
233 }
234
235 async fn run(self: Arc<Self>) {
236 loop {
237 let mut queued = self.conn_queue.next().await;
238
239 let meta = self.protocol_meta.read().await.clone();
243
244 let params = HandshakeParams {
245 own_id: &self.id,
246 is_inbound: matches!(queued.direction, ConnDirection::Inbound),
247 config_version: &self.config.version,
248 protocols: &meta,
249 timeout_secs: self.config.handshake_timeout,
250 verified_peer_id: queued.verified_peer_id.as_ref(),
251 };
252 let handshake = handshake(&mut queued.reader, &mut queued.writer, ¶ms).await;
253
254 let (pid, negotiated) = match handshake {
255 Ok(v) => v,
256 Err(err) => {
257 let pid = queued.verified_peer_id.clone();
258 self.monitor
259 .notify(PoolEvent::HandshakeFailed(pid.clone()))
260 .await;
261 let _ = self
262 .peer_emitter
263 .emit(&PeerEvent::HandshakeFailed(pid))
264 .await;
265 let _ = queued.disconnect_signal.send(Err(err)).await;
266 continue;
267 }
268 };
269
270 let candidate = PeerCandidate {
273 peer_id: &pid,
274 remote_endpoint: &queued.remote_endpoint,
275 negotiated_protocols: &negotiated,
276 };
277 let allowed = self.config.access_control.allow(
278 &Subject::Peer(&candidate),
279 Action::Connect(queued.direction.clone()),
280 );
281
282 if !allowed {
283 warn!("Access denied for peer {pid}");
284 self.monitor
285 .notify(PoolEvent::HandshakeFailed(Some(pid.clone())))
286 .await;
287 let _ = self
288 .peer_emitter
289 .emit(&PeerEvent::HandshakeFailed(Some(pid)))
290 .await;
291 let _ = queued
292 .disconnect_signal
293 .send(Err(Error::AccessDenied))
294 .await;
295 continue;
296 }
297
298 if let Err(err) = self.new_peer(queued, pid, negotiated).await {
299 error!("new_peer failed: {err}");
300 }
301 }
302 }
303
304 async fn new_peer(
306 self: &Arc<Self>,
307 queued: QueuedConn,
308 pid: PeerID,
309 negotiated: Vec<ProtocolID>,
310 ) -> Result<()> {
311 if self.contains_peer(&pid).await {
312 self.monitor
313 .notify(PoolEvent::PeerAlreadyConnected(pid.clone()))
314 .await;
315 let _ = queued
316 .disconnect_signal
317 .send(Err(Error::PeerAlreadyConnected))
318 .await;
319 return Err(Error::PeerAlreadyConnected);
320 }
321
322 let protocol_ids: Vec<ProtocolID> = self.protocols.read().await.keys().cloned().collect();
323 let negotiated: HashSet<ProtocolID> = negotiated.into_iter().collect();
324
325 let peer = Peer::new(self.clone(), queued, pid.clone(), negotiated, protocol_ids).await?;
326
327 self.peers.write().await.insert(pid.clone(), peer.clone());
328
329 let on_disconnect = {
330 let this = self.clone();
331 let pid = pid.clone();
332 |result| async move {
333 if let TaskResult::Completed(_) = result {
334 if let Err(err) = this.remove_peer(&pid).await {
335 error!("Failed to remove peer {pid}: {err}");
336 }
337 }
338 }
339 };
340
341 self.task_group
342 .spawn_then(peer.clone().run(), on_disconnect);
343
344 info!("Add new peer {pid}");
345 self.monitor.notify(PoolEvent::NewPeer(pid.clone())).await;
346 let _ = self.peer_emitter.emit(&PeerEvent::Added(pid)).await;
347
348 Ok(())
349 }
350
351 async fn remove_peer(&self, pid: &PeerID) -> Result<()> {
353 let result = self.peers.write().await.remove(pid);
354
355 let peer = match result {
356 Some(p) => p,
357 None => return Ok(()),
358 };
359
360 let _ = peer.shutdown().await;
361
362 self.monitor
363 .notify(PoolEvent::RemovePeer(pid.clone()))
364 .await;
365 let _ = self
366 .peer_emitter
367 .emit(&PeerEvent::Removed(pid.clone()))
368 .await;
369
370 warn!("Peer {pid} removed",);
371 Ok(())
372 }
373}