Skip to main content

openrtc/
protocol_config.rs

1//! Pre-bind ALPN composition shared by native and WASM runtimes.
2
3use std::collections::HashSet;
4
5pub const OPENRTC_ALPN: &[u8] = b"plutonium/p2p/1";
6pub const MAX_ROUTER_PROTOCOLS: usize = 32;
7pub const MAX_ALPN_BYTES: usize = 255;
8
9pub fn router_alpns(
10    extra_alpns: Vec<Vec<u8>>,
11    include_standard_protocols: bool,
12) -> anyhow::Result<Vec<Vec<u8>>> {
13    let mut alpns = extra_alpns;
14    alpns.push(OPENRTC_ALPN.to_vec());
15    if include_standard_protocols {
16        #[cfg(feature = "iroh-protocols-wasm")]
17        alpns.extend([
18            iroh_blobs::ALPN.to_vec(),
19            iroh_gossip::ALPN.to_vec(),
20            iroh_docs::ALPN.to_vec(),
21        ]);
22        #[cfg(not(feature = "iroh-protocols-wasm"))]
23        anyhow::bail!("standard Iroh protocols are not compiled into this runtime");
24    }
25    anyhow::ensure!(
26        alpns.len() <= MAX_ROUTER_PROTOCOLS,
27        "Iroh router protocol count exceeds {MAX_ROUTER_PROTOCOLS}"
28    );
29    let mut seen = HashSet::with_capacity(alpns.len());
30    for alpn in &alpns {
31        anyhow::ensure!(!alpn.is_empty(), "Iroh ALPN must not be empty");
32        anyhow::ensure!(
33            alpn.len() <= MAX_ALPN_BYTES,
34            "Iroh ALPN exceeds {MAX_ALPN_BYTES} bytes"
35        );
36        anyhow::ensure!(seen.insert(alpn.clone()), "duplicate Iroh ALPN");
37    }
38    Ok(alpns)
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    #[test]
46    fn router_alpns_rejects_duplicate_and_invalid_values() {
47        assert!(router_alpns(vec![OPENRTC_ALPN.to_vec()], false).is_err());
48        assert!(router_alpns(vec![Vec::new()], false).is_err());
49        assert!(router_alpns(vec![vec![1; MAX_ALPN_BYTES + 1]], false).is_err());
50    }
51
52    #[test]
53    fn router_alpns_preserves_declared_order_and_adds_openrtc() {
54        assert_eq!(
55            router_alpns(vec![b"example/custom/1".to_vec()], false).unwrap(),
56            vec![b"example/custom/1".to_vec(), OPENRTC_ALPN.to_vec()]
57        );
58    }
59
60    #[cfg(feature = "iroh-protocols-wasm")]
61    #[test]
62    fn standard_protocols_are_declared_once() {
63        let alpns = router_alpns(Vec::new(), true).unwrap();
64        assert_eq!(alpns.len(), 4);
65        assert!(alpns.contains(&iroh_docs::ALPN.to_vec()));
66        assert!(alpns.contains(&iroh_blobs::ALPN.to_vec()));
67        assert!(alpns.contains(&iroh_gossip::ALPN.to_vec()));
68    }
69}