use anyhow::{Context, Result};
use super::Client;
impl Client {
pub async fn configure_sparse_fanout(
&self,
capability: &str,
revision: u64,
local_device_id: &str,
local_device_key_x: &str,
peers_json: &str,
sparse: bool,
) -> Result<(String, crate::sparse_fanout::SparseFanoutProjection)> {
anyhow::ensure!(
peers_json.len() <= 256 * 1024,
"sparse fanout roster exceeds 256 KiB"
);
let peers = serde_json::from_str::<Vec<serde_json::Value>>(peers_json)
.context("decode sparse fanout roster")?;
anyhow::ensure!(peers.len() <= 100, "sparse fanout roster exceeds 100 peers");
let local_node_id = self.sparse_fanout_node_id().await?;
let (projected, diagnostics) = self.sparse_fanout.lock().await.configure(
capability,
revision,
local_device_id,
&local_node_id,
local_device_key_x,
peers,
sparse,
)?;
Ok((serde_json::to_string(&projected)?, diagnostics))
}
pub async fn prepare_sparse_fanout_message(
&self,
capability: &str,
payload: &[u8],
) -> Result<crate::sparse_fanout::SparseFanoutSigningRequest> {
self.sparse_fanout
.lock()
.await
.prepare(capability, payload, sparse_fanout_now_ms())
}
pub async fn finalize_sparse_fanout_message(
&self,
request_id: &str,
signature: &str,
) -> Result<Vec<u8>> {
self.sparse_fanout
.lock()
.await
.finalize(request_id, signature, sparse_fanout_now_ms())
}
pub async fn accept_sparse_fanout_message(
&self,
capability: &str,
source_peer_id: &str,
encoded: &[u8],
) -> Result<crate::sparse_fanout::SparseFanoutDecision> {
self.sparse_fanout.lock().await.accept(
capability,
source_peer_id,
encoded,
sparse_fanout_now_ms(),
)
}
pub async fn sparse_fanout_diagnostics(
&self,
capability: &str,
) -> crate::sparse_fanout::SparseFanoutDiagnostics {
self.sparse_fanout.lock().await.diagnostics(capability)
}
pub async fn record_sparse_fanout_forward_queue_drop(
&self,
capability: &str,
count: u64,
) -> Result<()> {
self.sparse_fanout
.lock()
.await
.record_forward_queue_drop(capability, count)
}
async fn sparse_fanout_node_id(&self) -> Result<String> {
let node = self.iroh_node.read().await;
let node = node
.as_ref()
.ok_or_else(|| anyhow::anyhow!("Iroh node is not initialized"))?;
Ok(node.endpoint().id().to_string())
}
}
fn sparse_fanout_now_ms() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis()
.min(u128::from(u64::MAX)) as u64
}