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;
}
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,
bootstrap_hnd: Mutex<Option<kitsune2_bootstrap_srv::BootstrapSrv>>,
bootstrap_addr: SocketAddr,
}
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));
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}"),
bootstrap_hnd,
bootstrap_addr,
})
}
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()
}
}