use std::sync::Arc;
use std::time::Duration;
use sculk::tunnel::{HostConfig, IrohTunnel, JoinConfig, Ticket, TunnelEvent};
use tokio::sync::mpsc;
use tokio::task::JoinHandle;
use super::events::AppEvent;
pub fn spawn_host(
port: u16,
secret_key: sculk::SecretKey,
relay_url: Option<sculk::RelayUrl>,
password: Option<String>,
tx: mpsc::UnboundedSender<AppEvent>,
) -> JoinHandle<()> {
tokio::spawn(async move {
let config = HostConfig::new()
.event_delay(Duration::ZERO)
.password(password);
match IrohTunnel::host(port, Some(secret_key), relay_url, config).await {
Ok((tunnel, ticket, events)) => {
let _ = tx.send(AppEvent::HostStarted {
tunnel: Arc::new(tunnel),
ticket: ticket.to_string(),
events,
});
}
Err(e) => {
let _ = tx.send(AppEvent::StartFailed(format!("host 启动失败: {e}")));
}
}
})
}
pub fn spawn_join(
ticket_str: &str,
port: u16,
password: Option<String>,
tx: mpsc::UnboundedSender<AppEvent>,
) -> JoinHandle<()> {
let ticket_str = ticket_str.trim().to_owned();
tokio::spawn(async move {
let ticket: Ticket = match ticket_str.parse() {
Ok(t) => t,
Err(e) => {
let _ = tx.send(AppEvent::StartFailed(format!("票据解析失败: {e}")));
return;
}
};
let config = JoinConfig::new()
.event_delay(Duration::ZERO)
.password(password);
match IrohTunnel::join(&ticket, port, config).await {
Ok((tunnel, events)) => {
let _ = tx.send(AppEvent::JoinConnected {
tunnel: Arc::new(tunnel),
events,
});
}
Err(e) => {
let _ = tx.send(AppEvent::StartFailed(format!("join 失败: {e}")));
}
}
})
}
pub fn spawn_close(tunnel: Arc<IrohTunnel>, tx: mpsc::UnboundedSender<AppEvent>) {
tokio::spawn(async move {
match tokio::time::timeout(Duration::from_secs(5), tunnel.close()).await {
Ok(()) => {
let _ = tx.send(AppEvent::Closed);
}
Err(_) => {
let _ = tx.send(AppEvent::CloseFailed("关闭隧道超时 (5s)".to_string()));
}
}
});
}
pub fn spawn_event_forwarder(
mut events: mpsc::Receiver<TunnelEvent>,
tx: mpsc::UnboundedSender<AppEvent>,
) -> JoinHandle<()> {
tokio::spawn(async move {
while let Some(event) = events.recv().await {
if tx.send(AppEvent::Tunnel(event)).is_err() {
break;
}
}
})
}