cuprate_p2p_core/
handles.rs1use std::{
6 sync::{Arc, OnceLock},
7 time::Duration,
8};
9
10use tokio::sync::OwnedSemaphorePermit;
11use tokio_util::sync::{CancellationToken, WaitForCancellationFutureOwned};
12
13#[derive(Default, Debug)]
15pub struct HandleBuilder {
16 permit: Option<OwnedSemaphorePermit>,
17}
18
19impl HandleBuilder {
20 pub const fn new() -> Self {
22 Self { permit: None }
23 }
24
25 #[must_use]
27 pub fn with_permit(mut self, permit: Option<OwnedSemaphorePermit>) -> Self {
28 self.permit = permit;
29 self
30 }
31
32 pub fn build(self) -> (ConnectionGuard, ConnectionHandle) {
36 let token = CancellationToken::new();
37
38 (
39 ConnectionGuard {
40 token: token.clone(),
41 on_close: None,
42 _permit: self.permit,
43 },
44 ConnectionHandle {
45 token,
46 ban: Arc::new(OnceLock::new()),
47 },
48 )
49 }
50}
51
52#[derive(Debug, Copy, Clone)]
54pub struct BanPeer(pub Duration);
55
56pub struct ConnectionGuard {
58 token: CancellationToken,
59 on_close: Option<Box<dyn FnOnce() + Send>>,
60 _permit: Option<OwnedSemaphorePermit>,
61}
62
63impl ConnectionGuard {
64 pub fn should_shutdown(&self) -> WaitForCancellationFutureOwned {
66 self.token.clone().cancelled_owned()
67 }
68 pub fn connection_closed(&self) {
72 self.token.cancel();
73 }
74 #[must_use]
76 pub(crate) fn with_on_close(mut self, callback: impl FnOnce() + Send + 'static) -> Self {
77 self.on_close = Some(Box::new(callback));
78 self
79 }
80}
81
82impl Drop for ConnectionGuard {
83 fn drop(&mut self) {
84 self.token.cancel();
85
86 if let Some(callback) = self.on_close.take() {
87 callback();
88 }
89 }
90}
91
92#[derive(Debug, Clone)]
95pub struct ConnectionHandle {
96 token: CancellationToken,
97 ban: Arc<OnceLock<BanPeer>>,
98}
99
100impl ConnectionHandle {
101 pub fn closed(&self) -> WaitForCancellationFutureOwned {
102 self.token.clone().cancelled_owned()
103 }
104 pub fn ban_peer(&self, duration: Duration) {
106 #[expect(
107 clippy::let_underscore_must_use,
108 reason = "error means peer is already banned; fine to ignore"
109 )]
110 let _ = self.ban.set(BanPeer(duration));
111 self.token.cancel();
112 }
113 pub fn is_closed(&self) -> bool {
115 self.token.is_cancelled()
116 }
117 pub fn check_should_ban(&mut self) -> Option<BanPeer> {
119 self.ban.get().copied()
120 }
121 pub fn send_close_signal(&self) {
123 self.token.cancel();
124 }
125}