use std::net::SocketAddr;
use std::sync::{Arc, Mutex};
pub trait SweetRendezvous: 'static + Send + Sync {
fn bootstrap_addr(&self) -> &str;
fn sig_addr(&self) -> &str;
fn relay_addr(&self) -> &str {
self.sig_addr()
}
}
pub type DynSweetRendezvous = Arc<dyn SweetRendezvous>;
pub struct SweetLocalRendezvous {
bs_addr: String,
#[cfg(any(feature = "transport-tx5-backend-go-pion", feature = "transport-iroh"))]
sig_addr: String,
#[cfg(all(
feature = "transport-iroh",
not(feature = "transport-tx5-backend-go-pion")
))]
relay_addr: String,
bootstrap_hnd: Mutex<Option<kitsune2_bootstrap_srv::BootstrapSrv>>,
bootstrap_addr: SocketAddr,
#[cfg(all(
feature = "transport-iroh",
not(feature = "transport-tx5-backend-go-pion")
))]
_relay_server: iroh_relay::server::Server,
}
impl Drop for SweetLocalRendezvous {
fn drop(&mut self) {
if let Some(mut s) = self.bootstrap_hnd.lock().unwrap().take() {
if let Err(err) = s.shutdown() {
tracing::error!(?err, "failed to shutdown bootstrap server");
}
}
}
}
async fn spawn_test_bootstrap(
bind_addr: Option<SocketAddr>,
) -> std::io::Result<(kitsune2_bootstrap_srv::BootstrapSrv, SocketAddr)> {
#[cfg(feature = "transport-iroh")]
let _ = rustls::crypto::ring::default_provider().install_default();
let mut config = kitsune2_bootstrap_srv::Config::testing();
#[cfg(feature = "transport-tx5-backend-go-pion")]
{
config.sbd.limit_clients = 100;
config.sbd.disable_rate_limiting = true;
}
if let Some(bind_addr) = bind_addr {
config.listen_address_list = vec![bind_addr];
}
let bootstrap = tokio::task::spawn_blocking(|| {
tracing::info!("Starting bootstrap server");
kitsune2_bootstrap_srv::BootstrapSrv::new(config)
})
.await
.unwrap()?;
tracing::info!("Bootstrap server started");
let addr = *bootstrap.listen_addrs().first().unwrap();
Ok((bootstrap, addr))
}
impl SweetLocalRendezvous {
#[allow(clippy::new_ret_no_self)]
pub async fn new() -> DynSweetRendezvous {
Self::new_raw().await
}
pub async fn new_raw() -> Arc<Self> {
let (bootstrap, bootstrap_addr) = spawn_test_bootstrap(None).await.unwrap();
let bootstrap_hnd = Mutex::new(Some(bootstrap));
#[cfg(all(
feature = "transport-iroh",
not(feature = "transport-tx5-backend-go-pion")
))]
let (_relay_server, relay_addr) = {
let mut relay_config = iroh_relay::server::testing::server_config();
if let Some(ref mut relay) = relay_config.relay {
relay.tls = None;
}
relay_config.quic = None;
let relay = iroh_relay::server::Server::spawn(relay_config)
.await
.expect("failed to spawn relay server");
let addr = relay.http_addr().expect("relay has no http address");
(relay, addr)
};
Arc::new(Self {
bs_addr: format!("http://{bootstrap_addr}"),
#[cfg(feature = "transport-tx5-backend-go-pion")]
sig_addr: format!("ws://{bootstrap_addr}"),
#[cfg(all(
feature = "transport-iroh",
not(feature = "transport-tx5-backend-go-pion")
))]
sig_addr: format!("http://{bootstrap_addr}"),
#[cfg(all(
feature = "transport-iroh",
not(feature = "transport-tx5-backend-go-pion")
))]
relay_addr: format!("http://{relay_addr}"),
bootstrap_hnd,
bootstrap_addr,
#[cfg(all(
feature = "transport-iroh",
not(feature = "transport-tx5-backend-go-pion")
))]
_relay_server,
})
}
pub async fn drop_sig(&self) {
self.bootstrap_hnd.lock().unwrap().take();
for _ in 0..100 {
tokio::time::sleep(std::time::Duration::from_millis(10)).await;
match tokio::net::TcpStream::connect(self.bootstrap_addr).await {
Ok(_) => (),
Err(_) => break,
}
}
}
pub async fn start_sig(&self) {
self.drop_sig().await;
let (bootstrap, _) = spawn_test_bootstrap(Some(self.bootstrap_addr))
.await
.unwrap();
*self.bootstrap_hnd.lock().unwrap() = Some(bootstrap);
}
}
impl SweetRendezvous for SweetLocalRendezvous {
fn bootstrap_addr(&self) -> &str {
self.bs_addr.as_str()
}
fn sig_addr(&self) -> &str {
self.sig_addr.as_str()
}
fn relay_addr(&self) -> &str {
#[cfg(all(
feature = "transport-iroh",
not(feature = "transport-tx5-backend-go-pion")
))]
{
self.relay_addr.as_str()
}
#[cfg(not(all(
feature = "transport-iroh",
not(feature = "transport-tx5-backend-go-pion")
)))]
{
self.sig_addr.as_str()
}
}
}