use std::pin::Pin;
use iroh_base::EndpointId;
use portable_atomic::{AtomicU64, Ordering};
use tokio_util::sync::CancellationToken;
#[cfg(not(wasm_browser))]
use tokio_util::task::TaskTracker;
#[derive(Debug)]
pub struct Runtime {
id: EndpointId,
#[cfg(not(wasm_browser))]
tasks: TaskTracker,
#[cfg(not(wasm_browser))]
cancel: CancellationToken,
#[cfg(not(wasm_browser))]
task_counter: AtomicU64,
}
impl Runtime {
pub fn new(id: EndpointId) -> Self {
Self {
id,
#[cfg(not(wasm_browser))]
tasks: TaskTracker::new(),
#[cfg(not(wasm_browser))]
cancel: CancellationToken::new(),
#[cfg(not(wasm_browser))]
task_counter: AtomicU64::new(0),
}
}
#[cfg(not(wasm_browser))]
pub async fn shutdown(&self) {
if self.tasks.close() {
self.tasks.wait().await
}
}
#[cfg(not(wasm_browser))]
pub fn abort(&self) {
self.cancel.cancel();
self.tasks.close();
}
#[cfg(wasm_browser)]
pub async fn shutdown(&self) {}
#[cfg(wasm_browser)]
pub fn abort(&self) {}
}
impl noq::Runtime for Runtime {
#[cfg(not(wasm_browser))]
fn new_timer(&self, i: std::time::Instant) -> Pin<Box<dyn noq::AsyncTimer>> {
noq::TokioRuntime.new_timer(i)
}
#[cfg(wasm_browser)]
fn new_timer(&self, deadline: n0_future::time::Instant) -> Pin<Box<dyn noq::AsyncTimer>> {
Box::pin(web::Timer(n0_future::time::sleep_until(deadline)))
}
#[cfg(not(wasm_browser))]
fn spawn(&self, future: Pin<Box<dyn Future<Output = ()> + Send>>) {
if self.tasks.is_closed() {
tracing::debug!(me = %self.id.fmt_short(), "runtime closed, dropping spawned task");
return;
}
use tracing::{Instrument, trace_span};
let task_id = self.task_counter.fetch_add(1, Ordering::Relaxed);
let cancel = self.cancel.clone();
let span = trace_span!("runtime", me = %self.id.fmt_short(), task_id);
self.tasks.spawn(async move {
cancel.run_until_cancelled(future.instrument(span)).await;
});
}
#[cfg(wasm_browser)]
fn spawn(&self, future: Pin<Box<dyn Future<Output = ()> + Send>>) {
wasm_bindgen_futures::spawn_local(future);
}
#[cfg(not(wasm_browser))]
fn wrap_udp_socket(
&self,
t: std::net::UdpSocket,
) -> std::io::Result<Box<dyn noq::AsyncUdpSocket>> {
noq::TokioRuntime.wrap_udp_socket(t)
}
}
#[cfg(wasm_browser)]
mod web {
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
use n0_future::time;
#[derive(Debug)]
pub(crate) struct Timer(pub(crate) time::Sleep);
impl noq::AsyncTimer for Timer {
fn reset(mut self: Pin<&mut Self>, deadline: time::Instant) {
Pin::new(&mut self.0).reset(deadline)
}
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
Pin::new(&mut self.0).poll(cx)
}
}
}