use std::path::Path;
use std::sync::Arc;
use crate::protocol::WireMessage;
use crate::state::AppState;
#[async_trait::async_trait]
pub trait Transport: Send + Sync {
fn as_any(&self) -> &dyn std::any::Any;
async fn broadcast(&self, msg: &WireMessage) -> bool;
async fn connect(&self, ticket: &str, state: Arc<AppState>, wait: bool) -> anyhow::Result<()>;
async fn ticket_string(&self) -> Option<String>;
async fn regenerate(&self, config_dir: &Path, data_dir: &Path) -> anyhow::Result<String>;
async fn deauthorize_peer(&self, _peer_id: &str) {}
fn endpoint_id(&self) -> Option<String>;
fn is_ready(&self) -> bool;
fn transport_name(&self) -> &'static str;
}
pub async fn handle_incoming(state: &Arc<AppState>, content: &[u8], sender_npub: Option<&str>) {
let msg: WireMessage = match serde_json::from_slice(content) {
Ok(m) => m,
Err(e) => {
tracing::warn!("failed to decode incoming message: {e}");
return;
}
};
state
.apply_and_execute(crate::daemon_protocol::Event::IncomingWire {
msg,
sender_npub: sender_npub.map(String::from),
})
.await;
}
pub async fn broadcast_local_sessions(state: &AppState) {
let proto = state.protocol.read().await;
let local_infos: Vec<crate::protocol::SessionInfo> = proto
.sessions
.values()
.filter(|s| {
matches!(s.origin, crate::daemon_protocol::Origin::Local) && s.metadata.networked
})
.map(|s| crate::protocol::SessionInfo {
id: s.id.clone(),
metadata: None,
})
.collect();
let aliases = proto.exportable_local_aliases();
let seq = proto.wire_seq;
drop(proto);
let msg = WireMessage::SessionList {
sessions: local_infos,
daemon_id: state.config.npub.clone(),
daemon_name: state.config.name.clone(),
aliases,
seq,
};
broadcast(state, &msg).await;
}
pub async fn broadcast(state: &AppState, msg: &WireMessage) -> bool {
let transports = state.transports().await;
let mut any_sent = false;
for t in transports.values() {
if t.broadcast(msg).await {
any_sent = true;
}
}
any_sent
}