openrtc/client/
sparse_fanout_impl.rs1use anyhow::{Context, Result};
2
3use super::Client;
4
5impl Client {
6 pub async fn configure_sparse_fanout(
10 &self,
11 capability: &str,
12 revision: u64,
13 local_device_id: &str,
14 local_device_key_x: &str,
15 peers_json: &str,
16 sparse: bool,
17 ) -> Result<(String, crate::sparse_fanout::SparseFanoutProjection)> {
18 anyhow::ensure!(
19 peers_json.len() <= 256 * 1024,
20 "sparse fanout roster exceeds 256 KiB"
21 );
22 let peers = serde_json::from_str::<Vec<serde_json::Value>>(peers_json)
23 .context("decode sparse fanout roster")?;
24 anyhow::ensure!(peers.len() <= 100, "sparse fanout roster exceeds 100 peers");
25 let local_node_id = self.sparse_fanout_node_id().await?;
26 let (projected, diagnostics) = self.sparse_fanout.lock().await.configure(
27 capability,
28 revision,
29 local_device_id,
30 &local_node_id,
31 local_device_key_x,
32 peers,
33 sparse,
34 )?;
35 Ok((serde_json::to_string(&projected)?, diagnostics))
36 }
37
38 pub async fn prepare_sparse_fanout_message(
41 &self,
42 capability: &str,
43 payload: &[u8],
44 ) -> Result<crate::sparse_fanout::SparseFanoutSigningRequest> {
45 self.sparse_fanout
46 .lock()
47 .await
48 .prepare(capability, payload, sparse_fanout_now_ms())
49 }
50
51 pub async fn finalize_sparse_fanout_message(
55 &self,
56 request_id: &str,
57 signature: &str,
58 ) -> Result<Vec<u8>> {
59 self.sparse_fanout
60 .lock()
61 .await
62 .finalize(request_id, signature, sparse_fanout_now_ms())
63 }
64
65 pub async fn accept_sparse_fanout_message(
68 &self,
69 capability: &str,
70 source_peer_id: &str,
71 encoded: &[u8],
72 ) -> Result<crate::sparse_fanout::SparseFanoutDecision> {
73 self.sparse_fanout.lock().await.accept(
74 capability,
75 source_peer_id,
76 encoded,
77 sparse_fanout_now_ms(),
78 )
79 }
80
81 pub async fn sparse_fanout_diagnostics(
82 &self,
83 capability: &str,
84 ) -> crate::sparse_fanout::SparseFanoutDiagnostics {
85 self.sparse_fanout.lock().await.diagnostics(capability)
86 }
87
88 pub async fn record_sparse_fanout_forward_queue_drop(
89 &self,
90 capability: &str,
91 count: u64,
92 ) -> Result<()> {
93 self.sparse_fanout
94 .lock()
95 .await
96 .record_forward_queue_drop(capability, count)
97 }
98
99 async fn sparse_fanout_node_id(&self) -> Result<String> {
100 let node = self.iroh_node.read().await;
101 let node = node
102 .as_ref()
103 .ok_or_else(|| anyhow::anyhow!("Iroh node is not initialized"))?;
104 Ok(node.endpoint().id().to_string())
105 }
106}
107
108fn sparse_fanout_now_ms() -> u64 {
109 std::time::SystemTime::now()
110 .duration_since(std::time::UNIX_EPOCH)
111 .unwrap_or_default()
112 .as_millis()
113 .min(u128::from(u64::MAX)) as u64
114}