use crate::{
crypto::StaticPublicKey,
i2np::{HopRole, Message},
primitives::{MessageId, RouterId, Str, TunnelId},
runtime::Runtime,
tunnel::{
noise::{NoiseContext, OutboundSession},
pool::TunnelPoolContextHandle,
},
};
use bytes::Bytes;
use hashbrown::HashSet;
use thingbuf::mpsc::Receiver;
use alloc::{collections::VecDeque, vec::Vec};
use core::{marker::PhantomData, num::NonZeroUsize};
pub mod inbound;
pub mod outbound;
pub mod pending;
#[derive(Debug)]
pub struct TunnelHop {
key_context: OutboundSession,
record_idx: Option<usize>,
router: RouterId,
tunnel_id: TunnelId,
}
impl TunnelHop {
#[cfg(test)]
pub fn outbound_session(&self) -> &OutboundSession {
&self.key_context
}
pub fn router_id(&self) -> &RouterId {
&self.router
}
pub fn set_record_index(&mut self, record_idx: usize) {
self.record_idx = Some(record_idx);
}
pub fn record_index(&self) -> usize {
self.record_idx.expect("to exist")
}
}
#[derive(Debug)]
pub enum TunnelDirection {
Inbound,
Outbound,
}
pub trait Tunnel<R: Runtime>: Send {
fn new(
name: Str,
tunnel_id: TunnelId,
receiver: ReceiverKind,
hops: Vec<TunnelHop>,
metrics_handle: R::MetricsHandle,
) -> Self;
fn hop_roles(num_hops: NonZeroUsize) -> impl Iterator<Item = HopRole>;
fn direction() -> TunnelDirection;
fn tunnel_id(&self) -> &TunnelId;
fn hops(&self) -> HashSet<RouterId>;
}
pub struct TunnelBuilder<R: Runtime, T: Tunnel<R>> {
hops: VecDeque<TunnelHop>,
metrics_handle: R::MetricsHandle,
name: Str,
receiver: ReceiverKind,
tunnel_id: TunnelId,
_tunnel: PhantomData<T>,
}
impl<R: Runtime, T: Tunnel<R>> TunnelBuilder<R, T> {
pub fn new(
name: Str,
tunnel_id: TunnelId,
receiver: ReceiverKind,
metrics_handle: R::MetricsHandle,
) -> Self {
Self {
hops: VecDeque::new(),
metrics_handle,
name,
receiver,
tunnel_id,
_tunnel: Default::default(),
}
}
pub fn with_hop(mut self, hop: TunnelHop) -> Self {
self.hops.push_back(hop);
self
}
pub fn build(self) -> T {
T::new(
self.name,
self.tunnel_id,
self.receiver,
self.hops.into_iter().rev().collect(),
self.metrics_handle,
)
}
}
pub enum ReceiverKind {
Outbound,
Inbound {
message_rx: Receiver<Message>,
handle: TunnelPoolContextHandle,
},
}
impl ReceiverKind {
pub fn inbound(self) -> (Receiver<Message>, TunnelPoolContextHandle) {
match self {
Self::Inbound { message_rx, handle } => (message_rx, handle),
_ => panic!("state mismatch"),
}
}
}
#[derive(Debug)]
pub enum TunnelInfo {
Outbound {
gateway: TunnelId,
router_id: Bytes,
tunnel_id: TunnelId,
},
Inbound {
tunnel_id: TunnelId,
router_id: Bytes,
},
}
impl TunnelInfo {
pub fn destruct(self) -> (TunnelId, TunnelId, Bytes) {
match self {
Self::Outbound {
gateway,
tunnel_id,
router_id,
} => (gateway, tunnel_id, router_id),
Self::Inbound {
tunnel_id,
router_id,
} => (tunnel_id, tunnel_id, router_id),
}
}
}
pub struct TunnelBuildParameters<R: Runtime> {
pub hops: Vec<(Bytes, StaticPublicKey)>,
pub message_id: MessageId,
pub metrics_handle: R::MetricsHandle,
pub name: Str,
pub noise: NoiseContext,
pub receiver: ReceiverKind,
pub tunnel_info: TunnelInfo,
}