use std::net::SocketAddr;
use std::sync::Arc;
use async_trait::async_trait;
use crate::error::MethodError;
use crate::method::{MethodOutcome, TraversalKind, TraversalMethod};
use crate::peer::PeerTarget;
use crate::relay::{RelayStatus, RelayTunnel};
#[async_trait]
pub trait RelayedDialer: Send + Sync {
fn relay_endpoint(&self) -> SocketAddr;
fn is_ready(&self) -> bool;
async fn open_dial_tunnel(
&self,
target_peer: &str,
network_id: &str,
) -> Result<RelayTunnel, String>;
}
#[async_trait]
impl RelayedDialer for ReservationRelayedTransport {
fn relay_endpoint(&self) -> SocketAddr {
self.relay_endpoint
}
fn is_ready(&self) -> bool {
self.status.relay_transport_ready()
}
async fn open_dial_tunnel(
&self,
target_peer: &str,
network_id: &str,
) -> Result<RelayTunnel, String> {
self.status.open_tunnel(target_peer, network_id)
}
}
pub struct RelayedDialMethod {
dialer: Arc<dyn RelayedDialer>,
}
impl RelayedDialMethod {
pub fn new(dialer: Arc<dyn RelayedDialer>) -> Self {
RelayedDialMethod { dialer }
}
}
#[async_trait]
impl TraversalMethod for RelayedDialMethod {
fn kind(&self) -> TraversalKind {
TraversalKind::Relayed
}
async fn attempt(&self, _peer: &PeerTarget) -> Result<MethodOutcome, MethodError> {
if !self.dialer.is_ready() {
return Err(MethodError::failed(
TraversalKind::Relayed,
"relay reservation not connected — relayed transport unavailable",
));
}
Ok(MethodOutcome::single(
TraversalKind::Relayed,
self.dialer.relay_endpoint(),
))
}
}
#[async_trait]
pub trait RelayedTransport: Send + Sync {
async fn open_relayed(&self, target_peer: &str, network_id: &str)
-> Result<SocketAddr, String>;
}
pub struct RelayedTransportMethod<T: RelayedTransport> {
transport: T,
}
impl<T: RelayedTransport> RelayedTransportMethod<T> {
pub fn new(transport: T) -> Self {
RelayedTransportMethod { transport }
}
}
#[async_trait]
impl<T: RelayedTransport> TraversalMethod for RelayedTransportMethod<T> {
fn kind(&self) -> TraversalKind {
TraversalKind::Relayed
}
async fn attempt(&self, peer: &PeerTarget) -> Result<MethodOutcome, MethodError> {
let relay_addr = self
.transport
.open_relayed(&peer.peer_id.to_hex(), &peer.network_id)
.await
.map_err(|e| MethodError::failed(TraversalKind::Relayed, e))?;
Ok(MethodOutcome::single(TraversalKind::Relayed, relay_addr))
}
}
pub struct ReservationRelayedTransport {
status: Arc<RelayStatus>,
relay_endpoint: SocketAddr,
}
impl ReservationRelayedTransport {
pub fn new(status: Arc<RelayStatus>, relay_endpoint: SocketAddr) -> Self {
ReservationRelayedTransport {
status,
relay_endpoint,
}
}
pub fn open_tunnel(&self, target_peer: &str, network_id: &str) -> Result<RelayTunnel, String> {
self.status.open_tunnel(target_peer, network_id)
}
}
#[async_trait]
impl RelayedTransport for ReservationRelayedTransport {
async fn open_relayed(
&self,
target_peer: &str,
network_id: &str,
) -> Result<SocketAddr, String> {
let _probe = self.status.open_tunnel(target_peer, network_id)?;
Ok(self.relay_endpoint)
}
}