nadisc_runtime/
transport.rs1use crate::{closed, lock, spawn_owned, Core, DiscoveryHandle};
4use nadisc::managed::{DiscoveryError, ErrorCode, Result};
5use std::{
6 future::Future,
7 sync::{Arc, Weak},
8};
9use tokio::{sync::OwnedSemaphorePermit, task::AbortHandle, time::Instant};
10use tokio_util::sync::CancellationToken;
11
12pub struct TransportLease {
14 core: Weak<Core>,
15 stop: CancellationToken,
16 permit: OwnedSemaphorePermit,
17}
18
19impl DiscoveryHandle {
20 pub fn reserve_transport(&self) -> Result<TransportLease> {
24 let core = self.core.upgrade().ok_or_else(closed)?;
25 let gate = lock(&core.gate);
26 if gate.failed || gate.close_started {
27 return Err(closed());
28 }
29 let permit = core.transports.clone().try_acquire_owned().map_err(|_| {
30 DiscoveryError::new(
31 ErrorCode::CapacityExceeded,
32 "owner transport task capacity reached",
33 )
34 })?;
35 Ok(TransportLease {
36 core: Arc::downgrade(&core),
37 stop: core.stop.child_token(),
38 permit,
39 })
40 }
41}
42
43impl TransportLease {
44 pub async fn cancelled(&self) {
48 self.stop.cancelled().await;
49 }
50
51 pub fn spawn(
55 self,
56 deadline: Instant,
57 future: impl Future<Output = ()> + Send + 'static,
58 ) -> Result<AbortHandle> {
59 let core = self.core.upgrade().ok_or_else(closed)?;
60 let gate = lock(&core.gate);
61 if gate.failed || gate.close_started {
62 return Err(closed());
63 }
64 if deadline <= Instant::now() {
65 return Err(crate::timeout());
66 }
67 Ok(spawn_owned(&core, async move {
68 let _permit = self.permit;
69 tokio::select! {
70 biased;
71 _ = self.stop.cancelled() => {},
72 _ = tokio::time::sleep_until(deadline) => {},
73 _ = future => {},
74 }
75 }))
76 }
77}