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> {
26 let core = self.core.upgrade().ok_or_else(closed)?;
27 let gate = lock(&core.gate);
28 if gate.failed || gate.close_started {
29 return Err(closed());
30 }
31 let permit = core.transports.clone().try_acquire_owned().map_err(|_| {
32 DiscoveryError::new(
33 ErrorCode::CapacityExceeded,
34 "owner transport task capacity reached",
35 )
36 })?;
37 Ok(TransportLease {
38 core: Arc::downgrade(&core),
39 stop: core.stop.child_token(),
40 permit,
41 })
42 }
43}
44
45impl TransportLease {
46 pub async fn cancelled(&self) {
52 self.stop.cancelled().await;
53 }
54
55 pub fn spawn(
63 self,
64 deadline: Instant,
65 future: impl Future<Output = ()> + Send + 'static,
66 ) -> Result<AbortHandle> {
67 let core = self.core.upgrade().ok_or_else(closed)?;
68 let gate = lock(&core.gate);
69 if gate.failed || gate.close_started {
70 return Err(closed());
71 }
72 if deadline <= Instant::now() {
73 return Err(crate::timeout());
74 }
75 Ok(spawn_owned(&core, async move {
76 let _permit = self.permit;
77 tokio::select! {
78 biased;
79 _ = self.stop.cancelled() => {},
80 _ = tokio::time::sleep_until(deadline) => {},
81 _ = future => {},
82 }
83 }))
84 }
85}