use std::collections::HashMap;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use tokio::sync::{mpsc, oneshot};
use crate::metrics::AsyncMetricSink;
use crate::trace::TraceHooks;
use helix_core::effect::TransportId;
use helix_core::PortError;
pub type TransportTable<Tr> = HashMap<TransportId, Arc<Tr>>;
pub struct TransportRegistration<Fs> {
pub(super) id: TransportId,
pub(super) sender: Arc<Fs>,
pub(super) registered_tx: oneshot::Sender<()>,
}
pub async fn register_transport<Fs>(
registration_tx: &mpsc::UnboundedSender<TransportRegistration<Fs>>,
id: TransportId,
sender: Arc<Fs>,
) -> Result<(), PortError> {
let (registered_tx, registered_rx) = oneshot::channel();
registration_tx
.send(TransportRegistration {
id,
sender,
registered_tx,
})
.map_err(|_| PortError::Transport("transport registration channel closed".into()))?;
registered_rx
.await
.map_err(|_| PortError::Transport("transport registration was not acknowledged".into()))
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TransportLifecycleEvent {
Disconnected {
transport_id: TransportId,
reason: &'static str,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TransportTraceEvent {
pub transport_id: TransportId,
pub name: &'static str,
pub action: &'static str,
pub attempt: Option<u32>,
pub delay_ms: Option<u64>,
pub next_delay_ms: Option<u64>,
pub reason: Option<&'static str>,
pub error_class: Option<String>,
}
pub const TRANSPORT_TRACE_QUEUE_CAPACITY: usize = 256;
#[derive(Clone, Debug, Default)]
pub struct TransportTraceStats {
dropped: Arc<AtomicU64>,
}
impl TransportTraceStats {
pub fn dropped_count(&self) -> u64 {
self.dropped.load(Ordering::Relaxed)
}
}
#[derive(Clone, Debug)]
pub struct TransportTraceSink {
tx: mpsc::Sender<TransportTraceEvent>,
stats: TransportTraceStats,
}
impl TransportTraceSink {
pub fn channel() -> (Self, mpsc::Receiver<TransportTraceEvent>) {
let (tx, rx) = mpsc::channel(TRANSPORT_TRACE_QUEUE_CAPACITY);
let stats = TransportTraceStats::default();
(Self { tx, stats }, rx)
}
pub fn try_emit(&self, event: TransportTraceEvent) -> bool {
match self.tx.try_send(event) {
Ok(()) => true,
Err(_) => {
self.stats.dropped.fetch_add(1, Ordering::Relaxed);
false
}
}
}
pub fn stats(&self) -> TransportTraceStats {
self.stats.clone()
}
}
pub struct EngineDeps<S, H, U, E, C> {
pub storage: Arc<S>,
pub http: Arc<H>,
pub uploader: Arc<U>,
pub event_sink: Arc<E>,
pub clock: C,
pub trace: TraceHooks,
pub metrics: Arc<dyn AsyncMetricSink>,
pub max_http_inflight: usize,
pub transport_lifecycle_tx: Option<mpsc::UnboundedSender<TransportLifecycleEvent>>,
pub transport_trace_tx: Option<TransportTraceSink>,
}