ng_net/
types.rs

1// Copyright (c) 2022-2025 Niko Bonnieure, Par le Peuple, NextGraph.org developers
2// All rights reserved.
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
5// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
6// at your option. All files in the project carrying such
7// notice may not be copied, modified, or distributed except
8// according to those terms.
9
10//! NextGraph network protocol types
11//!
12//! Corresponds to the BARE schema
13
14use core::fmt;
15use std::collections::HashSet;
16use std::{
17    any::{Any, TypeId},
18    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
19};
20
21use serde::{Deserialize, Serialize};
22use web_time::SystemTime;
23
24use ng_repo::errors::*;
25use ng_repo::log::*;
26use ng_repo::store::Store;
27use ng_repo::types::*;
28use ng_repo::utils::{sign, verify};
29
30use crate::app_protocol::*;
31use crate::utils::{
32    get_domain_without_port_443, is_ipv4_private, is_ipv6_private, is_private_ip, is_public_ip,
33    is_public_ipv4, is_public_ipv6,
34};
35use crate::WS_PORT_ALTERNATE;
36use crate::{actor::EActor, actors::admin::*, actors::*};
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
39/// used to initiate a session at a local broker V0
40pub struct Credentials {
41    pub user_key: PrivKey,
42    pub read_cap: ReadCap,
43    pub private_store: RepoId,
44    pub protected_store: RepoId,
45    pub public_store: RepoId,
46    pub user_master_key: SymKey,
47    pub peer_priv_key: PrivKey,
48}
49
50impl Credentials {
51    pub fn new_partial(user_priv_key: &PrivKey) -> Self {
52        Credentials {
53            user_key: user_priv_key.clone(),
54            read_cap: ReadCap::nil(),
55            private_store: RepoId::nil(),
56            protected_store: RepoId::nil(),
57            public_store: RepoId::nil(),
58            user_master_key: SymKey::random(),
59            peer_priv_key: PrivKey::random_ed(),
60        }
61    }
62}
63
64//
65//  Network common types
66//
67
68#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
69pub enum InterfaceType {
70    Loopback,
71    Private,
72    Public,
73    Invalid,
74}
75
76impl InterfaceType {
77    pub fn is_ip_valid_for_type(&self, ip: &IP) -> bool {
78        self.is_ipaddr_valid_for_type(&ip.into())
79    }
80    pub fn is_ipaddr_valid_for_type(&self, ip: &IpAddr) -> bool {
81        match ip {
82            IpAddr::V4(v4) => self.is_ipv4_valid_for_type(v4),
83            IpAddr::V6(v6) => self.is_ipv6_valid_for_type(v6),
84        }
85    }
86
87    pub fn is_ipv4_valid_for_type(&self, ip: &Ipv4Addr) -> bool {
88        match self {
89            InterfaceType::Loopback => ip.is_loopback(),
90            InterfaceType::Public => is_public_ipv4(ip),
91            // we allow to bind to link-local for IPv4
92            InterfaceType::Private => is_ipv4_private(ip),
93            _ => false,
94        }
95    }
96    pub fn is_ipv6_valid_for_type(&self, ip: &Ipv6Addr) -> bool {
97        match self {
98            InterfaceType::Loopback => ip.is_loopback(),
99            InterfaceType::Public => is_public_ipv6(ip),
100            // we do NOT allow to bind to link-local for IPv6
101            InterfaceType::Private => is_ipv6_private(ip),
102            _ => false,
103        }
104    }
105}
106
107#[cfg(not(target_arch = "wasm32"))]
108#[derive(Clone, Debug)]
109pub struct Interface {
110    pub if_type: InterfaceType,
111    pub name: String,
112    pub mac_addr: Option<netdev::mac::MacAddr>,
113    /// List of Ipv4Net for the network interface
114    pub ipv4: Vec<netdev::ip::Ipv4Net>,
115    /// List of Ipv6Net for the network interface
116    pub ipv6: Vec<netdev::ip::Ipv6Net>,
117}
118
119/// Bind address
120#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
121pub struct BindAddress {
122    pub port: u16,
123    pub ip: IP,
124}
125
126impl BindAddress {
127    pub fn to_ws_url(&self) -> String {
128        format!(
129            "ws://{}:{}",
130            self.ip,
131            if self.port == 0 { 80 } else { self.port }
132        )
133    }
134    pub fn new_localhost_with_port(port: u16) -> Self {
135        BindAddress {
136            ip: LOOPBACK_IPV4.clone(),
137            port,
138        }
139    }
140}
141
142impl From<&SocketAddr> for BindAddress {
143    #[inline]
144    fn from(addr: &SocketAddr) -> BindAddress {
145        let ip_addr = addr.ip();
146        let ip = IP::try_from(&ip_addr).unwrap();
147        let port = addr.port();
148        BindAddress { ip, port }
149    }
150}
151
152//
153// BROKER common types
154//
155
156/// Core Broker connection details Version 0
157#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
158pub struct BrokerCoreV0 {
159    /// peerId of the server
160    pub peer_id: PubKey,
161
162    /// network addresses of the broker, typically an IpV4 and an optional IPV6 addr. core broker should not be multi-homed.
163    pub addrs: Vec<BindAddress>,
164}
165
166/// Core Broker connection details
167#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Hash)]
168pub enum BrokerCore {
169    V0(BrokerCoreV0),
170}
171
172/// BrokerServerTypeV0 type
173#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
174pub enum BrokerServerTypeV0 {
175    Localhost(u16), // optional port number
176    BoxPrivate(Vec<BindAddress>),
177    Public(Vec<BindAddress>),
178    BoxPublicDyn(Vec<BindAddress>), // can be empty
179    Domain(String),                 // accepts an optional trailing ":port" number
180                                    //Core(Vec<BindAddress>),
181}
182
183/// BrokerServer details Version 0
184#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
185pub struct BrokerServerV0 {
186    /// Network addresses
187    pub server_type: BrokerServerTypeV0,
188
189    /// is this server capable of running a verifier
190    pub can_verify: bool,
191
192    /// is this server capable of forwarding client connections to another broker
193    pub can_forward: bool,
194
195    /// peerId of the server
196    pub peer_id: PubKey,
197}
198
199#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
200pub struct BrokerServerContentV0 {
201    pub servers: Vec<BrokerServerTypeV0>,
202
203    pub version: u32,
204}
205
206#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
207pub struct BrokerServer {
208    pub content: BrokerServerContentV0,
209
210    /// peerId of the server
211    pub peer_id: PubKey,
212
213    /// optional signature over content by peer_id
214    pub sig: Option<Sig>,
215}
216
217pub type LocatorV0 = Vec<BrokerServer>;
218
219#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
220pub enum Locator {
221    V0(LocatorV0),
222}
223
224impl fmt::Display for Locator {
225    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226        let ser = serde_bare::to_vec(&self).unwrap();
227        write!(f, "{}", base64_url::encode(&ser))
228    }
229}
230
231impl Locator {
232    pub fn empty() -> Self {
233        Self::V0(vec![])
234    }
235    pub fn first_broker_server(&self) -> Result<BrokerServerV0, NgError> {
236        match self {
237            Self::V0(v0) => {
238                let bs = v0.get(0).ok_or(NgError::BrokerNotFound)?;
239                Ok(BrokerServerV0 {
240                    server_type: bs
241                        .content
242                        .servers
243                        .get(0)
244                        .ok_or(NgError::BrokerNotFound)?
245                        .clone(),
246                    can_verify: false,
247                    can_forward: false,
248                    peer_id: bs.peer_id,
249                })
250            }
251        }
252    }
253    pub fn add(&mut self, bs: BrokerServerV0) {
254        match self {
255            Self::V0(v0) => {
256                for b in v0.iter_mut() {
257                    if b.peer_id == bs.peer_id {
258                        b.content.servers.push(bs.server_type);
259                        return;
260                    }
261                }
262                v0.push(BrokerServer {
263                    peer_id: bs.peer_id,
264                    sig: None,
265                    content: BrokerServerContentV0 {
266                        version: 0,
267                        servers: vec![bs.server_type],
268                    },
269                });
270            }
271        }
272    }
273}
274
275impl TryFrom<&str> for Locator {
276    type Error = NgError;
277    fn try_from(string: &str) -> Result<Self, NgError> {
278        let vec = base64_url::decode(string).map_err(|_| NgError::InvalidKey)?;
279        Ok(serde_bare::from_slice(&vec).map_err(|_| NgError::InvalidKey)?)
280    }
281}
282
283impl From<BrokerServerV0> for Locator {
284    fn from(bs: BrokerServerV0) -> Self {
285        Locator::V0(vec![BrokerServer {
286            peer_id: bs.peer_id,
287            content: BrokerServerContentV0 {
288                version: 0,
289                servers: vec![bs.server_type],
290            },
291            sig: None,
292        }])
293    }
294}
295
296#[doc(hidden)]
297pub const APP_ACCOUNT_REGISTERED_SUFFIX: &str = "/#/user/registered";
298
299#[doc(hidden)]
300pub const NG_NET_URL: &str = "https://nextgraph.net";
301
302#[doc(hidden)]
303pub const NG_APP_URL: &str = "https://nextgraph.app";
304
305#[doc(hidden)]
306pub const APP_NG_WS_URL: &str = "wss://nextgraph.app";
307
308#[allow(dead_code)]
309fn api_dyn_peer_url(peer_id: &PubKey) -> String {
310    format!("https://nextgraph.net/api/v1/dynpeer/{}", peer_id)
311}
312
313#[doc(hidden)]
314pub const LOCAL_HOSTS: [&str; 3] = ["localhost", "127.0.0.1", "[::1]"];
315
316fn local_ws_url(port: &u16) -> String {
317    format!("ws://localhost:{}", if *port == 0 { 80 } else { *port })
318}
319#[doc(hidden)]
320pub(crate) fn local_http_url(port: &u16) -> String {
321    format!("http://localhost:{}", if *port == 0 { 80 } else { *port })
322}
323
324#[doc(hidden)]
325pub const LOCAL_URLS: [&str; 3] = ["http://localhost", "http://127.0.0.1", "http://[::1]"];
326use url::{Host, Url};
327
328impl BrokerServerTypeV0 {
329    pub fn find_first_ipv4(&self) -> Option<&BindAddress> {
330        match self {
331            Self::BoxPrivate(addrs) => {
332                for addr in addrs {
333                    if addr.ip.is_v4() {
334                        return Some(addr);
335                    }
336                }
337                return None;
338            }
339            _ => None,
340        }
341    }
342    pub fn find_first_ipv6(&self) -> Option<&BindAddress> {
343        match self {
344            Self::BoxPrivate(addrs) => {
345                for addr in addrs {
346                    if addr.ip.is_v6() {
347                        return Some(addr);
348                    }
349                }
350                return None;
351            }
352            _ => None,
353        }
354    }
355}
356
357impl BrokerServerV0 {
358    pub fn new_localhost(peer_id: PubKey) -> Self {
359        BrokerServerV0 {
360            server_type: BrokerServerTypeV0::Localhost(WS_PORT_ALTERNATE[0]),
361            can_verify: false,
362            can_forward: true,
363            peer_id,
364        }
365    }
366
367    fn first_ipv4(&self) -> Option<(String, Vec<BindAddress>)> {
368        self.server_type.find_first_ipv4().map_or(None, |bindaddr| {
369            Some((format!("ws://{}:{}", bindaddr.ip, bindaddr.port), vec![]))
370        })
371    }
372
373    fn first_ipv6(&self) -> Option<(String, Vec<BindAddress>)> {
374        self.server_type.find_first_ipv6().map_or(None, |bindaddr| {
375            Some((format!("ws://{}:{}", bindaddr.ip, bindaddr.port), vec![]))
376        })
377    }
378
379    pub fn first_ipv4_http(&self) -> Option<String> {
380        self.server_type.find_first_ipv4().map_or(None, |bindaddr| {
381            Some(format!("http://{}:{}", bindaddr.ip, bindaddr.port))
382        })
383    }
384
385    pub fn first_ipv6_http(&self) -> Option<String> {
386        self.server_type.find_first_ipv6().map_or(None, |bindaddr| {
387            Some(format!("http://{}:{}", bindaddr.ip, bindaddr.port))
388        })
389    }
390
391    fn first_ipv6_or_ipv4(
392        ipv4: bool,
393        ipv6: bool,
394        addrs: &Vec<BindAddress>,
395    ) -> Option<&BindAddress> {
396        if ipv6 {
397            for addr in addrs {
398                if addr.ip.is_v6() {
399                    return Some(addr);
400                }
401            }
402        }
403        if ipv4 {
404            for addr in addrs {
405                if addr.ip.is_v4() {
406                    return Some(addr);
407                }
408            }
409        }
410        return None;
411    }
412
413    fn ng_app_bootstrap_url(addr: &BindAddress, key: PubKey) -> Option<String> {
414        let payload = (addr, key);
415        let payload_ser = serde_bare::to_vec(&payload).ok();
416        if payload_ser.is_none() {
417            return None;
418        }
419        Some(format!(
420            "{}?b={}",
421            NG_APP_URL,
422            base64_url::encode(&payload_ser.unwrap())
423        ))
424    }
425
426    fn ng_app_bootstrap_url_with_first_ipv6_or_ipv4(
427        ipv4: bool,
428        ipv6: bool,
429        addrs: &Vec<BindAddress>,
430        key: PubKey,
431    ) -> Option<String> {
432        if let Some(addr) = Self::first_ipv6_or_ipv4(ipv4, ipv6, addrs) {
433            return Self::ng_app_bootstrap_url(addr, key);
434        }
435        None
436    }
437
438    /// set ipv6 only if the browser connected with a remote IPV6. always set ipv4 as a fallback (for now).
439    pub async fn get_url_for_ngnet(&self, ipv4: bool, ipv6: bool) -> Option<String> {
440        match &self.server_type {
441            BrokerServerTypeV0::Public(addrs) => {
442                Self::ng_app_bootstrap_url_with_first_ipv6_or_ipv4(
443                    ipv4,
444                    ipv6,
445                    addrs,
446                    self.peer_id,
447                )
448            }
449            BrokerServerTypeV0::BoxPublicDyn(addrs) => {
450                // let resp = reqwest::get(api_dyn_peer_url(&self.peer_id)).await;
451                // if resp.is_ok() {
452                //     let resp = resp.unwrap().json::<Vec<BindAddress>>().await;
453                //     if resp.is_ok() {
454                //         return Self::ng_app_bootstrap_url_with_first_ipv6_or_ipv4(
455                //             ipv4,
456                //             ipv6,
457                //             &resp.unwrap(),
458                //             self.peer_id,
459                //         );
460                //     }
461                // }
462                if addrs.len() > 0 {
463                    Self::ng_app_bootstrap_url_with_first_ipv6_or_ipv4(
464                        ipv4,
465                        ipv6,
466                        &addrs,
467                        self.peer_id,
468                    )
469                } else {
470                    None
471                }
472            }
473            BrokerServerTypeV0::Domain(domain) => Some(format!("https://{}", domain)),
474            BrokerServerTypeV0::Localhost(port) => Some(local_http_url(&port)),
475            BrokerServerTypeV0::BoxPrivate(_) => {
476                if ipv6 {
477                    let v6 = self.server_type.find_first_ipv6().map_or(None, |bindaddr| {
478                        Some(format!("http://{}:{}", bindaddr.ip, bindaddr.port))
479                    });
480                    if v6.is_some() {
481                        return v6;
482                    }
483                }
484                if ipv4 {
485                    self.server_type.find_first_ipv4().map_or(None, |bindaddr| {
486                        Some(format!("http://{}:{}", bindaddr.ip, bindaddr.port))
487                    })
488                } else {
489                    None
490                }
491            }
492        }
493    }
494
495    pub fn is_public_server(&self) -> bool {
496        match &self.server_type {
497            BrokerServerTypeV0::Localhost(_) => false,
498            BrokerServerTypeV0::BoxPrivate(_) => false,
499            BrokerServerTypeV0::Public(_) => true,
500            BrokerServerTypeV0::BoxPublicDyn(_) => true,
501            BrokerServerTypeV0::Domain(_) => true,
502        }
503    }
504
505    pub fn get_domain(&self) -> Option<String> {
506        if let BrokerServerTypeV0::Domain(domain) = &self.server_type {
507            Some(domain.clone())
508        } else {
509            None
510        }
511    }
512
513    /// on web browser, returns the connection URL and an optional list of BindAddress if a relay is needed
514    /// filtered by the current location url of the webpage
515    /// on native apps (do not pass a location), returns or the connection URL without optional BindAddress or an empty string with
516    /// several BindAddresses to try to connect to with .to_ws_url()
517    pub async fn get_ws_url(
518        &self,
519        location: &Option<String>,
520    ) -> Option<(String, Vec<BindAddress>)> {
521        if location.is_some() {
522            let location = location.as_ref().unwrap();
523            if location.starts_with(NG_APP_URL) {
524                match &self.server_type {
525                    BrokerServerTypeV0::Public(addrs) => {
526                        Some((APP_NG_WS_URL.to_string(), addrs.clone()))
527                    }
528                    BrokerServerTypeV0::BoxPublicDyn(addrs) => {
529                        // let resp = reqwest::get(api_dyn_peer_url(&self.peer_id)).await;
530                        // if resp.is_ok() {
531                        //     let resp = resp.unwrap().json::<Vec<BindAddress>>().await;
532                        //     if resp.is_ok() {
533                        //         return Some((APP_NG_WS_URL.to_string(), resp.unwrap()));
534                        //     }
535                        // }
536                        if addrs.len() > 0 {
537                            Some((APP_NG_WS_URL.to_string(), addrs.clone()))
538                        } else {
539                            None
540                        }
541                    }
542                    _ => None,
543                }
544            } else if let BrokerServerTypeV0::Domain(domain) = &self.server_type {
545                let url = format!("https://{}", domain);
546                if location.starts_with(&url) {
547                    let wss_url = format!("wss://{}", domain);
548                    Some((wss_url, vec![]))
549                } else {
550                    None
551                }
552            } else {
553                // localhost
554                if location.starts_with(LOCAL_URLS[0])
555                    || location.starts_with(LOCAL_URLS[1])
556                    || location.starts_with(LOCAL_URLS[2])
557                {
558                    if let BrokerServerTypeV0::Localhost(port) = self.server_type {
559                        Some((local_ws_url(&port), vec![]))
560                    } else {
561                        None
562                    }
563                }
564                // a private address
565                else if location.starts_with("http://") {
566                    let url = Url::parse(&location).unwrap();
567                    match url.host() {
568                        Some(Host::Ipv4(ip)) => {
569                            if is_ipv4_private(&ip) {
570                                self.first_ipv4()
571                            } else {
572                                None
573                            }
574                        }
575                        Some(Host::Ipv6(ip)) => {
576                            if is_ipv6_private(&ip) {
577                                self.first_ipv6()
578                            } else {
579                                None
580                            }
581                        }
582                        _ => None,
583                    }
584                } else {
585                    None
586                }
587            }
588        } else {
589            // From native / tauri app
590            match &self.server_type {
591                //BrokerServerTypeV0::Core(_) => None,
592                BrokerServerTypeV0::Localhost(port) => Some((local_ws_url(port), vec![])),
593                BrokerServerTypeV0::BoxPrivate(addrs) => Some((String::new(), addrs.clone())),
594                BrokerServerTypeV0::Public(addrs) => Some((String::new(), addrs.clone())),
595                BrokerServerTypeV0::BoxPublicDyn(addrs) => {
596                    // let resp = reqwest::get(api_dyn_peer_url(&self.peer_id)).await;
597                    // if resp.is_ok() {
598                    //     let resp = resp.unwrap().json::<Vec<BindAddress>>().await;
599                    //     if resp.is_ok() {
600                    //         return Some((String::new(), resp.unwrap()));
601                    //     }
602                    // }
603                    if addrs.len() > 0 {
604                        Some((String::new(), addrs.clone()))
605                    } else {
606                        None
607                    }
608                }
609                BrokerServerTypeV0::Domain(domain) => Some((format!("wss://{}", domain), vec![])),
610            }
611        }
612    }
613
614    pub fn to_iframe_msg(&self) -> BootstrapIframeMsg {
615
616        match &self.server_type {
617            BrokerServerTypeV0::Domain(domain) => BootstrapIframeMsg::domain(domain.clone()),
618            BrokerServerTypeV0::Localhost(port) => BootstrapIframeMsg::local(*port, self.peer_id),
619            BrokerServerTypeV0::BoxPrivate(addrs) => BootstrapIframeMsg::private(addrs.to_vec(), self.peer_id),
620            BrokerServerTypeV0::Public(_) | BrokerServerTypeV0::BoxPublicDyn(_) => BootstrapIframeMsg::ngbox(),
621        }
622    }
623}
624
625#[derive(Clone, Debug, Serialize, Deserialize)]
626pub struct BootstrapIframeMsg {
627
628    pub peer_id: Option<String>,
629
630    pub private: Option<Vec<BindAddress>>,
631
632    pub ngbox: Option<bool>,
633
634    pub domain: Option<String>,
635
636    pub localhost: Option<u16>,
637
638}
639
640impl BootstrapIframeMsg {
641    fn new() -> Self {
642        Self {
643            peer_id:None,
644            private:None,
645            ngbox:None,
646            domain:None,
647            localhost:None
648        }
649    }
650
651    fn domain(domain: String) -> Self {
652        let mut s = Self::new();
653        s.domain = Some(domain);
654        s
655    }
656
657    fn ngbox() -> Self {
658        let mut s = Self::new();
659        s.ngbox = Some(true);
660        s
661    }
662
663    fn private(addrs: Vec<BindAddress>, peer_id: PubKey) -> Self {
664        let mut s = Self::new();
665        s.peer_id = Some(peer_id.to_string());
666        s.private = Some(addrs);
667        s
668    }
669
670    fn local(port: u16, peer_id: PubKey) -> Self {
671        let mut s = Self::new();
672        s.peer_id = Some(peer_id.to_string());
673        s.localhost = Some(port);
674        s
675    }
676}
677
678/// Bootstrap content Version 0
679#[derive(Clone, Debug, Serialize, Deserialize)]
680pub struct BootstrapContentV0 {
681    /// list of servers, in order of preference
682    pub servers: Vec<BrokerServerV0>,
683}
684
685impl BootstrapContentV0 {
686    pub fn new_localhost(peer_id: PubKey) -> Self {
687        BootstrapContentV0 {
688            servers: vec![BrokerServerV0::new_localhost(peer_id)],
689        }
690    }
691    pub fn new_empty() -> Self {
692        BootstrapContentV0 { servers: vec![] }
693    }
694    pub fn merge(&mut self, with: &BootstrapContentV0) {
695        'outer: for server2 in &with.servers {
696            for server1 in &self.servers {
697                if *server1 == *server2 {
698                    continue 'outer;
699                }
700            }
701            self.servers.push(server2.clone());
702        }
703    }
704    pub fn get_first_peer_id(&self) -> Option<PubKey> {
705        self.servers.first().map(|s| s.peer_id)
706    }
707
708    pub fn get_domain(&self) -> Option<String> {
709        for server in self.servers.iter() {
710            if let BrokerServerTypeV0::Domain(name) = &server.server_type {
711                return Some(name.clone());
712            }
713        }
714        None
715    }
716
717    pub fn to_iframe_msgs(&self) -> Vec<BootstrapIframeMsg> {
718        self.servers.iter().map(|server| server.to_iframe_msg()).collect()
719    }
720}
721
722#[derive(Clone, Debug, Serialize, Deserialize)]
723pub enum BootstrapContent {
724    V0(BootstrapContentV0),
725}
726
727impl BootstrapContent {
728    pub fn servers(&self) -> &Vec<BrokerServerV0> {
729        match self {
730            Self::V0(v0) => &v0.servers,
731        }
732    }
733}
734
735/// Local Bootstrap info Version 0, served at /.ng_bootstrap
736#[derive(Clone, Debug, Serialize, Deserialize)]
737pub struct LocalBootstrapInfoV0 {
738    /// list of servers, in order of preference
739    pub bootstrap: BootstrapContentV0,
740
741    /// optional registration_url for public server that accept to be BSP for new clients
742    pub registration_url: Option<String>,
743}
744
745#[derive(Clone, Debug, Serialize, Deserialize)]
746pub enum LocalBootstrapInfo {
747    V0(LocalBootstrapInfoV0),
748}
749
750impl LocalBootstrapInfo {
751    pub fn servers(&self) -> &Vec<BrokerServerV0> {
752        match self {
753            Self::V0(v0) => &v0.bootstrap.servers,
754        }
755    }
756}
757
758impl From<LocalBootstrapInfo> for Invitation {
759    fn from(value: LocalBootstrapInfo) -> Self {
760        let LocalBootstrapInfo::V0(info) = value;
761        let name = info.bootstrap.get_domain();
762        let url = info.registration_url.clone();
763        Invitation::V0(InvitationV0 {
764            bootstrap: info.bootstrap,
765            code: None,
766            name,
767            url,
768        })
769    }
770}
771
772#[derive(Clone, Debug, Serialize, Deserialize)]
773pub enum InvitationCode {
774    Unique(SymKey),
775    Admin(SymKey),
776    Multi(SymKey),
777    Setup(SymKey),
778}
779
780impl InvitationCode {
781    pub fn get_symkey(&self) -> SymKey {
782        match self {
783            Self::Unique(s) | Self::Admin(s) | Self::Multi(s) | Self::Setup(s) => s.clone(),
784        }
785    }
786}
787
788impl fmt::Display for InvitationCode {
789    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
790        match self {
791            Self::Unique(k) => write!(f, "unique {}", k),
792            Self::Admin(k) => write!(f, "admin {}", k),
793            Self::Multi(k) => write!(f, "multi {}", k),
794            Self::Setup(k) => write!(f, "setup {}", k),
795        }
796    }
797}
798
799/// Invitation to create an account at a broker. Version 0
800#[derive(Clone, Debug, Serialize, Deserialize)]
801pub struct InvitationV0 {
802    /// list of servers, in order of preference
803    pub bootstrap: BootstrapContentV0,
804
805    pub code: Option<SymKey>,
806
807    /// an optional name to display to the invitee
808    pub name: Option<String>,
809
810    // an optional url to redirect the user to, for accepting ToS and making payment, if any.
811    pub url: Option<String>,
812}
813
814impl InvitationV0 {
815    pub fn set_bootstrap(&mut self, content: BootstrapContent) {
816        match content {
817            BootstrapContent::V0(v0) => self.bootstrap = v0,
818        }
819    }
820    pub fn empty(name: Option<String>) -> Self {
821        InvitationV0 {
822            bootstrap: BootstrapContentV0::new_empty(),
823            code: None,
824            name,
825            url: None,
826        }
827    }
828    pub fn new(
829        bootstrap_content: BootstrapContent,
830        code: Option<SymKey>,
831        name: Option<String>,
832        url: Option<String>,
833    ) -> Self {
834        match bootstrap_content {
835            BootstrapContent::V0(v0) => InvitationV0 {
836                bootstrap: v0,
837                code,
838                name,
839                url,
840            },
841        }
842    }
843    pub fn append_bootstraps(&mut self, add: &mut Option<BootstrapContentV0>) {
844        if add.is_some() {
845            let add = add.as_mut().unwrap();
846            self.bootstrap.servers.append(&mut add.servers);
847        }
848    }
849}
850
851impl Invitation {
852    pub fn new_v0(
853        bootstrap: BootstrapContentV0,
854        name: Option<String>,
855        url: Option<String>,
856    ) -> Self {
857        Invitation::V0(InvitationV0 {
858            bootstrap,
859            code: Some(SymKey::random()),
860            name,
861            url,
862        })
863    }
864
865    pub fn new_v0_free(
866        bootstrap: BootstrapContentV0,
867        name: Option<String>,
868        url: Option<String>,
869    ) -> Self {
870        Invitation::V0(InvitationV0 {
871            bootstrap,
872            code: None,
873            name,
874            url,
875        })
876    }
877
878    pub fn intersects(&self, invite2: Invitation) -> Invitation {
879        let Invitation::V0(v0) = self;
880        let mut new_invite = InvitationV0 {
881            bootstrap: BootstrapContentV0::new_empty(),
882            code: v0.code.clone(),
883            name: v0.name.clone(),
884            url: v0.url.clone(),
885        };
886        for server2 in invite2.get_servers() {
887            for server1 in &v0.bootstrap.servers {
888                if *server1 == *server2 {
889                    new_invite.bootstrap.servers.push(server2.clone());
890                    break;
891                }
892            }
893        }
894        Invitation::V0(new_invite)
895    }
896
897    pub fn get_servers(&self) -> &Vec<BrokerServerV0> {
898        match self {
899            Invitation::V0(v0) => &v0.bootstrap.servers,
900        }
901    }
902    pub fn get_domain(&self) -> Option<String> {
903        for bootstrap in self.get_servers() {
904            let res = bootstrap.get_domain();
905            if res.is_some() {
906                return res;
907            }
908        }
909        None
910    }
911
912    pub fn set_name(&mut self, name: Option<String>) {
913        if name.is_some() {
914            match self {
915                Invitation::V0(v0) => v0.name = Some(name.unwrap()),
916            }
917        }
918    }
919
920    pub fn set_url(&mut self, url: Option<&String>) {
921        if url.is_some() {
922            match self {
923                Invitation::V0(v0) => v0.url = Some(url.unwrap().clone()),
924            }
925        }
926    }
927
928    /// first URL in the list is the ngnet one
929    pub fn get_urls(&self) -> Vec<String> {
930        match self {
931            Invitation::V0(v0) => {
932                let mut res = vec![];
933                let ser = serde_bare::to_vec(&self).unwrap();
934                let url_param = base64_url::encode(&ser);
935                res.push(format!("{}/#/i/{}", NG_NET_URL, url_param));
936                for server in &v0.bootstrap.servers {
937                    match &server.server_type {
938                        BrokerServerTypeV0::Domain(domain) => {
939                            res.push(format!("https://{}/#/i/{}", domain, url_param));
940                        }
941                        BrokerServerTypeV0::BoxPrivate(addrs) => {
942                            for bindaddr in addrs {
943                                res.push(format!(
944                                    "http://{}:{}/#/i/{}",
945                                    bindaddr.ip, bindaddr.port, url_param
946                                ));
947                            }
948                        }
949                        BrokerServerTypeV0::Localhost(port) => {
950                            res.push(format!("{}/#/i/{}", local_http_url(&port), url_param));
951                        }
952                        _ => {}
953                    }
954                }
955                res
956            }
957        }
958    }
959}
960
961impl fmt::Display for Invitation {
962    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
963        let ser = serde_bare::to_vec(&self).unwrap();
964        let string = base64_url::encode(&ser);
965        write!(f, "{}", string)
966    }
967}
968
969impl TryFrom<String> for Invitation {
970    type Error = NgError;
971    fn try_from(value: String) -> Result<Self, NgError> {
972        let ser = base64_url::decode(&value).map_err(|_| NgError::InvalidInvitation)?;
973        let invite: Invitation =
974            serde_bare::from_slice(&ser).map_err(|_| NgError::InvalidInvitation)?;
975        Ok(invite)
976    }
977}
978
979/// Invitation to create an account at a broker.
980#[derive(Clone, Debug, Serialize, Deserialize)]
981pub enum Invitation {
982    V0(InvitationV0),
983}
984
985// impl From<BootstrapContent> for Invitation {
986//     fn from(value: BootstrapContent) -> Self {
987//         let BootstrapContent::V0(boot) = value;
988//         let name = boot.get_domain();
989//         Invitation::V0(InvitationV0 {
990//             bootstrap: boot,
991//             code: None,
992//             name,
993//             url: None,
994//         })
995//     }
996// }
997
998/// Create an account at a Broker Service Provider (BSP).
999#[derive(Clone, Debug, Serialize, Deserialize)]
1000pub enum CreateAccountBSP {
1001    V0(CreateAccountBSPV0),
1002}
1003
1004impl TryFrom<String> for CreateAccountBSP {
1005    type Error = NgError;
1006    fn try_from(value: String) -> Result<Self, NgError> {
1007        let ser = base64_url::decode(&value).map_err(|_| NgError::InvalidCreateAccount)?;
1008        let invite: CreateAccountBSP =
1009            serde_bare::from_slice(&ser).map_err(|_| NgError::InvalidCreateAccount)?;
1010        Ok(invite)
1011    }
1012}
1013
1014impl CreateAccountBSP {
1015    pub fn encode(&self) -> Option<String> {
1016        let payload_ser = serde_bare::to_vec(self).ok();
1017        if payload_ser.is_none() {
1018            return None;
1019        }
1020        Some(base64_url::encode(&payload_ser.unwrap()))
1021    }
1022    // pub fn user(&self) -> PubKey {
1023    //     match self {
1024    //         Self::V0(v0) => v0.user,
1025    //     }
1026    // }
1027    pub fn redirect_url(&self) -> &Option<String> {
1028        match self {
1029            Self::V0(v0) => &v0.redirect_url,
1030        }
1031    }
1032    // pub fn invitation(&self) -> &Option<InvitationV0> {
1033    //     match self {
1034    //         Self::V0(v0) => &v0.invitation,
1035    //     }
1036    // }
1037    // pub fn additional_bootstrap(&mut self) -> &mut Option<BootstrapContentV0> {
1038    //     match self {
1039    //         Self::V0(v0) => &mut v0.additional_bootstrap,
1040    //     }
1041    // }
1042}
1043
1044/// Create an account at a Broker Service Provider (BSP). Version 0
1045#[derive(Clone, Debug, Serialize, Deserialize)]
1046pub struct CreateAccountBSPV0 {
1047    //pub invitation: Option<InvitationV0>,
1048
1049    //pub additional_bootstrap: Option<BootstrapContentV0>,
1050    /// the user asking to create an account
1051    //pub user: PubKey,
1052
1053    /// signature over serialized invitation code, with user key
1054    // pub sig: Sig,
1055
1056    /// for web access, will redirect after successful signup. if left empty, it means user was on native app.
1057    pub redirect_url: Option<String>,
1058}
1059
1060/// ListenerInfo
1061#[cfg(not(target_arch = "wasm32"))]
1062#[derive(Clone, Debug, Serialize, Deserialize)]
1063pub struct ListenerInfo {
1064    pub config: ListenerV0,
1065
1066    /// list of BindAddresses
1067    pub addrs: Vec<BindAddress>,
1068}
1069
1070/// AcceptForwardForV0 type
1071///
1072/// allow answers to connection requests originating from a client behind a reverse proxy
1073/// Format of last param in the tuple is a list of comma separated hosts or CIDR subnetworks IPv4 and/or IPv6 addresses accepted as X-Forwarded-For
1074/// Empty string means all addresses are accepted
1075#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
1076pub enum AcceptForwardForV0 {
1077    /// X-Forwarded-For not allowed
1078    No,
1079
1080    /// X-Forwarded-For accepted only for clients with private LAN addresses. First param is the domain of the proxy server
1081    PrivateDomain((String, String)),
1082
1083    /// X-Forwarded-For accepted only for clients with public addresses. First param is the domain of the proxy server
1084    /// domain can take an option port (trailing `:port`)
1085    PublicDomain((String, String)),
1086
1087    /// X-Forwarded-For accepted only for clients with public addresses. First param is the domain of the proxy server
1088    /// domain can take an optional port (trailing `:port`)
1089    /// second param is the privKey of the PeerId of the proxy server, useful when the proxy server is load balancing to several daemons
1090    /// that should all use the same PeerId to answer requests
1091    PublicDomainPeer((String, PrivKey, String)),
1092
1093    /// accepts only clients with public addresses that arrive on a LAN address binding. This is used for DMZ and port forwarding configs
1094    /// first param is the port, second param in tuple is the interval for periodic probe of the external IP
1095    PublicDyn((u16, u32, String)),
1096
1097    /// accepts only clients with public addresses that arrive on a LAN address binding. This is used for DMZ and port forwarding configs
1098    /// First param is the IPv4 bind address of the reverse NAT server (DMZ, port forwarding)
1099    /// Second param is an optional IPv6 bind address of the reverse NAT server (DMZ, port forwarding)
1100    PublicStatic((BindAddress, Option<BindAddress>, String)),
1101}
1102
1103impl AcceptForwardForV0 {
1104    pub fn get_public_bind_addresses(&self) -> Vec<BindAddress> {
1105        match self {
1106            AcceptForwardForV0::PublicStatic((ipv4, ipv6, _)) => {
1107                let mut res = vec![ipv4.clone()];
1108                if ipv6.is_some() {
1109                    res.push(ipv6.unwrap().clone())
1110                }
1111                res
1112            }
1113            AcceptForwardForV0::PublicDyn(_) => {
1114                todo!();
1115            }
1116            _ => panic!("cannot call get_public_bind_addresses"),
1117        }
1118    }
1119
1120    pub fn get_public_bind_ipv6_address(&self) -> Option<IP> {
1121        match self {
1122            AcceptForwardForV0::PublicStatic((_ipv4, ipv6, _)) => {
1123                //let _res = vec![ipv4.clone()];
1124                if ipv6.is_some() {
1125                    return Some(ipv6.unwrap().ip.clone());
1126                } else {
1127                    return None;
1128                }
1129            }
1130            AcceptForwardForV0::PublicDyn(_) => {
1131                todo!();
1132            }
1133            _ => None,
1134        }
1135    }
1136
1137    pub fn is_public_domain(&self) -> bool {
1138        match self {
1139            AcceptForwardForV0::PublicDomainPeer(_) => true,
1140            AcceptForwardForV0::PublicDomain(_) => true,
1141            _ => false,
1142        }
1143    }
1144    pub fn is_public_static(&self) -> bool {
1145        match self {
1146            AcceptForwardForV0::PublicStatic(_) => true,
1147            _ => false,
1148        }
1149    }
1150    pub fn is_no(&self) -> bool {
1151        match self {
1152            AcceptForwardForV0::No => true,
1153            _ => false,
1154        }
1155    }
1156    pub fn is_public_dyn(&self) -> bool {
1157        match self {
1158            AcceptForwardForV0::PublicDyn(_) => true,
1159            _ => false,
1160        }
1161    }
1162    pub fn is_private_domain(&self) -> bool {
1163        match self {
1164            AcceptForwardForV0::PrivateDomain(_) => true,
1165            _ => false,
1166        }
1167    }
1168    pub fn domain_with_common_peer_id(&self) -> Option<PubKey> {
1169        match self {
1170            AcceptForwardForV0::PublicDomainPeer((_, privkey, _)) => Some(privkey.to_pub()),
1171            _ => None,
1172        }
1173    }
1174    pub fn get_domain(&self) -> &str {
1175        let domain = get_domain_without_port_443(match self {
1176            AcceptForwardForV0::PrivateDomain((d, _)) => d,
1177            AcceptForwardForV0::PublicDomain((d, _)) => d,
1178            AcceptForwardForV0::PublicDomainPeer((d, _, _)) => d,
1179            _ => panic!("cannot call get_domain if AcceptForwardForV0 is not a domain"),
1180        });
1181        //let mut url = "https://".to_string();
1182        //url.push_str(domain);
1183        domain
1184    }
1185}
1186
1187#[cfg(not(target_arch = "wasm32"))]
1188/// DaemonConfig Listener Version 0
1189#[derive(Clone, Debug, Serialize, Deserialize)]
1190pub struct ListenerV0 {
1191    /// local interface name to bind to
1192    /// names of interfaces can be retrieved with the --list-interfaces option
1193    pub interface_name: String,
1194
1195    pub if_type: InterfaceType,
1196
1197    /// optional number of seconds for an interval of periodic refresh
1198    /// of the actual IP(s) of the interface. Used for dynamic IP interfaces (DHCP)
1199    pub interface_refresh: u32,
1200
1201    // if to bind to the ipv6 address of the interface
1202    pub ipv6: bool,
1203
1204    /// local port to listen on
1205    pub port: u16,
1206
1207    /// force a private or localhost interface to be accepted as a core interface
1208    pub private_core: bool,
1209
1210    /// should the server serve the app files in HTTP mode (not WS). this setting will be discarded and app will not be served anyway if remote IP is public or listener is public
1211    pub serve_app: bool,
1212
1213    /// when the box is behind a DMZ, and ipv6 is enabled, the private interface will get the external public IpV6. with this option we allow binding to it
1214    pub bind_public_ipv6: bool,
1215
1216    /// default to false. Set to true by --core (use --core-with-clients to override to false). only useful for a public IP listener, if the clients should use another listener like --domain or --domain-private.
1217    /// do not set it on a --domain or --domain-private, as this will enable the relay_websocket feature, which should not be used except by nextgraph.app
1218    pub refuse_clients: bool,
1219
1220    // will answer a probe coming from private LAN and if is_private, with its own peerId, so that guests on the network will be able to connect.
1221    pub discoverable: bool,
1222
1223    /// Answers to connection requests originating from a direct client, without X-Forwarded-For headers
1224    /// Can be used in combination with a accept_forward_for config, when a local daemon is behind a proxy, and also serves as broker for local apps/webbrowsers
1225    pub accept_direct: bool,
1226
1227    /// X-Forwarded-For config. only valid if IP/interface is localhost or private
1228    pub accept_forward_for: AcceptForwardForV0,
1229    // impl fn is_private()
1230    // returns false if public IP in interface, or if PublicDyn, PublicStatic
1231
1232    // an interface with no accept_forward_for and no accept_direct, is de facto, disabled
1233}
1234
1235#[cfg(not(target_arch = "wasm32"))]
1236impl ListenerV0 {
1237    pub fn should_bind_public_ipv6_to_private_interface(&self, ip: Ipv6Addr) -> bool {
1238        let public_ip = self.accept_forward_for.get_public_bind_ipv6_address();
1239        if public_ip.is_none() {
1240            return false;
1241        }
1242        let public_ipv6addr: IpAddr = public_ip.as_ref().unwrap().into();
1243        return if let IpAddr::V6(v6) = public_ipv6addr {
1244            self.bind_public_ipv6 && self.if_type == InterfaceType::Private && ip == v6
1245        } else {
1246            false
1247        };
1248    }
1249
1250    pub fn new_direct(interface: Interface, ipv6: bool, port: u16) -> Self {
1251        Self {
1252            interface_name: interface.name,
1253            if_type: interface.if_type,
1254            interface_refresh: 0,
1255            ipv6,
1256            port,
1257            private_core: false,
1258            discoverable: false,
1259            accept_direct: true,
1260            refuse_clients: false,
1261            serve_app: true,
1262            bind_public_ipv6: false,
1263            accept_forward_for: AcceptForwardForV0::No,
1264        }
1265    }
1266
1267    pub fn is_core(&self) -> bool {
1268        match self.accept_forward_for {
1269            AcceptForwardForV0::PublicStatic(_) => true,
1270            AcceptForwardForV0::PublicDyn(_) => true,
1271            AcceptForwardForV0::PublicDomain(_) | AcceptForwardForV0::PublicDomainPeer(_) => false,
1272            AcceptForwardForV0::PrivateDomain(_) => false,
1273            AcceptForwardForV0::No => {
1274                self.if_type == InterfaceType::Public
1275                    || (self.private_core && self.if_type != InterfaceType::Invalid)
1276            }
1277        }
1278    }
1279
1280    pub fn accepts_client(&self) -> bool {
1281        match self.accept_forward_for {
1282            AcceptForwardForV0::PublicStatic(_)
1283            | AcceptForwardForV0::PublicDyn(_)
1284            | AcceptForwardForV0::PublicDomain(_)
1285            | AcceptForwardForV0::PublicDomainPeer(_) => self.accept_direct || !self.refuse_clients,
1286            AcceptForwardForV0::PrivateDomain(_) => true,
1287            AcceptForwardForV0::No => {
1288                self.if_type == InterfaceType::Public && !self.refuse_clients
1289                    || self.if_type != InterfaceType::Public
1290            }
1291        }
1292    }
1293
1294    pub fn get_bootstraps(&self, addrs: Vec<BindAddress>) -> Vec<BrokerServerTypeV0> {
1295        let mut res: Vec<BrokerServerTypeV0> = vec![];
1296        match self.accept_forward_for {
1297            AcceptForwardForV0::PublicStatic(_) => {
1298                let pub_addrs = self.accept_forward_for.get_public_bind_addresses();
1299                //res.push(BrokerServerTypeV0::Core(pub_addrs.clone()));
1300                if !self.refuse_clients {
1301                    res.push(BrokerServerTypeV0::Public(pub_addrs));
1302                }
1303                if self.accept_direct {
1304                    res.push(BrokerServerTypeV0::BoxPrivate(addrs));
1305                }
1306            }
1307            AcceptForwardForV0::PublicDyn(_) => {
1308                let pub_addrs = self.accept_forward_for.get_public_bind_addresses();
1309                //res.push(BrokerServerTypeV0::Core(pub_addrs.clone()));
1310                if !self.refuse_clients {
1311                    res.push(BrokerServerTypeV0::BoxPublicDyn(pub_addrs));
1312                }
1313                if self.accept_direct {
1314                    res.push(BrokerServerTypeV0::BoxPrivate(addrs));
1315                }
1316            }
1317            AcceptForwardForV0::PublicDomain(_) | AcceptForwardForV0::PublicDomainPeer(_) => {
1318                if !self.refuse_clients {
1319                    res.push(BrokerServerTypeV0::Domain(
1320                        self.accept_forward_for.get_domain().to_string(),
1321                    ));
1322                }
1323                //// this is removed since a server serving domain requests often needs a local interface too (for ngaccount), but does not want to expose this local interface to clients.
1324                // if self.accept_direct {
1325                //     if self.if_type == InterfaceType::Private {
1326                //         res.push(BrokerServerTypeV0::BoxPrivate(addrs));
1327                //     } else if self.if_type == InterfaceType::Loopback {
1328                //         res.push(BrokerServerTypeV0::Localhost(addrs[0].port));
1329                //     }
1330                // }
1331            }
1332            AcceptForwardForV0::PrivateDomain(_) => {
1333                res.push(BrokerServerTypeV0::Domain(
1334                    self.accept_forward_for.get_domain().to_string(),
1335                ));
1336            }
1337            AcceptForwardForV0::No => {
1338                if self.if_type == InterfaceType::Loopback {
1339                    res.push(BrokerServerTypeV0::Localhost(addrs[0].port));
1340                } else if self.if_type == InterfaceType::Public {
1341                    //res.push(BrokerServerTypeV0::Core(addrs.clone()));
1342                    if !self.refuse_clients {
1343                        res.push(BrokerServerTypeV0::Public(addrs));
1344                    }
1345                } else if self.if_type == InterfaceType::Private {
1346                    res.push(BrokerServerTypeV0::BoxPrivate(addrs));
1347                }
1348            }
1349        }
1350        res
1351    }
1352}
1353#[cfg(not(target_arch = "wasm32"))]
1354impl fmt::Display for ListenerV0 {
1355    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1356        let mut id = self.interface_name.clone();
1357        id.push('@');
1358        id.push_str(&self.port.to_string());
1359        write!(f, "{}", id)
1360    }
1361}
1362
1363/// Broker Overlay Permission
1364#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
1365pub enum BrokerOverlayPermission {
1366    Nobody,
1367    Anybody,
1368    AllRegisteredUser,
1369    UsersList(Vec<UserId>),
1370}
1371
1372/// Broker Overlay Config
1373#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
1374pub struct BrokerOverlayConfigV0 {
1375    // list of overlays this config applies to. empty array means applying to all
1376    pub overlays: Vec<OverlayId>,
1377    // Who can ask to join an overlay on the core
1378    pub core: BrokerOverlayPermission,
1379    // Who can connect as a client to this server
1380    pub server: BrokerOverlayPermission,
1381    // if core == Nobody and server == Nobody then the listeners will not be started
1382
1383    // are ExtRequest allowed on the server? this requires the core to be ON.
1384    pub allow_read: bool,
1385
1386    /// an empty list means to forward to the peer known for each overlay.
1387    /// forward and core are mutually exclusive. forward becomes the default when core is disabled (set to Nobody).
1388    /// core always takes precedence.
1389    pub forward: Vec<BrokerServerV0>,
1390}
1391
1392impl BrokerOverlayConfigV0 {
1393    pub fn new() -> Self {
1394        BrokerOverlayConfigV0 {
1395            overlays: vec![],
1396            core: BrokerOverlayPermission::Nobody,
1397            server: BrokerOverlayPermission::Nobody,
1398            allow_read: false,
1399            forward: vec![],
1400        }
1401    }
1402}
1403
1404/// Registration config
1405#[derive(Clone, Debug, Serialize, Deserialize)]
1406pub enum RegistrationConfig {
1407    Closed,
1408    Invitation,
1409    Open,
1410}
1411
1412/// Overlay Access
1413///
1414/// Used by the Client when opening or pinning a repo.
1415#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
1416pub enum OverlayAccess {
1417    /// The repo will be accessed on the Outer Overlay in Read Only mode
1418    /// This can be used for Public, Protected or Group overlays
1419    /// Value should be an OverlayId::Outer
1420    ReadOnly(OverlayId),
1421    /// The repo will be accessed on the Inner Overlay in Write mode, and the associated Outer overlay is also given
1422    /// This is used for Public, Protected and Group overlays
1423    /// First value in tuple should be the OverlayId::Inner, second the OverlayId::Outer
1424    ReadWrite((OverlayId, OverlayId)),
1425    /// The repo will be accessed on the Inner Overlay in Write mode, and it doesn't have an Outer overlay
1426    /// This is used for Private and Dialog overlays
1427    /// Value should be an OverlayId::Inner
1428    WriteOnly(OverlayId),
1429}
1430
1431impl OverlayAccess {
1432    pub fn is_read_only(&self) -> bool {
1433        match self {
1434            Self::ReadOnly(_) => true,
1435            _ => false,
1436        }
1437    }
1438    pub fn new_write_access_from_store(store: &Store) -> OverlayAccess {
1439        match store.get_store_repo() {
1440            StoreRepo::V0(StoreRepoV0::PrivateStore(_)) | StoreRepo::V0(StoreRepoV0::Dialog(_)) => {
1441                OverlayAccess::WriteOnly(store.inner_overlay())
1442            }
1443            StoreRepo::V0(StoreRepoV0::ProtectedStore(_))
1444            | StoreRepo::V0(StoreRepoV0::Group(_))
1445            | StoreRepo::V0(StoreRepoV0::PublicStore(_)) => {
1446                OverlayAccess::ReadWrite((store.inner_overlay(), store.outer_overlay()))
1447            }
1448        }
1449    }
1450
1451    pub fn new_read_access_from_store(store: &Store) -> OverlayAccess {
1452        match store.get_store_repo() {
1453            StoreRepo::V0(StoreRepoV0::PrivateStore(_)) | StoreRepo::V0(StoreRepoV0::Dialog(_)) => {
1454                panic!("cannot get read access to a private or dialog store");
1455            }
1456            StoreRepo::V0(StoreRepoV0::ProtectedStore(_))
1457            | StoreRepo::V0(StoreRepoV0::Group(_))
1458            | StoreRepo::V0(StoreRepoV0::PublicStore(_)) => {
1459                OverlayAccess::ReadOnly(store.outer_overlay())
1460            }
1461        }
1462    }
1463
1464    pub fn new_ro(outer_overlay: OverlayId) -> Result<Self, NgError> {
1465        if let OverlayId::Outer(_digest) = outer_overlay {
1466            Ok(OverlayAccess::ReadOnly(outer_overlay))
1467        } else {
1468            Err(NgError::InvalidArgument)
1469        }
1470    }
1471    pub fn new_rw(inner_overlay: OverlayId, outer_overlay: OverlayId) -> Result<Self, NgError> {
1472        if let OverlayId::Inner(_digest) = inner_overlay {
1473            if let OverlayId::Outer(_digest) = outer_overlay {
1474                Ok(OverlayAccess::ReadWrite((inner_overlay, outer_overlay)))
1475            } else {
1476                Err(NgError::InvalidArgument)
1477            }
1478        } else {
1479            Err(NgError::InvalidArgument)
1480        }
1481    }
1482    pub fn new_wo(inner_overlay: OverlayId) -> Result<Self, NgError> {
1483        if let OverlayId::Inner(_digest) = inner_overlay {
1484            Ok(OverlayAccess::WriteOnly(inner_overlay))
1485        } else {
1486            Err(NgError::InvalidArgument)
1487        }
1488    }
1489    pub fn overlay_id_for_client_protocol_purpose(&self) -> &OverlayId {
1490        match self {
1491            Self::ReadOnly(ro) => ro,
1492            Self::ReadWrite((inner, _outer)) => inner,
1493            Self::WriteOnly(wo) => wo,
1494        }
1495    }
1496}
1497
1498/// Inner Overlay Link
1499///
1500/// Details of the inner overlay of an NgLink
1501#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
1502pub struct InnerOverlayLink {
1503    /// overlay public key ID
1504    pub id: StoreOverlay,
1505
1506    /// The store has a special branch called `overlay` that is used to manage access to the InnerOverlay
1507    /// only the ReadCapSecret is needed to access the InnerOverlay
1508    /// the full readcap of this branch is needed in order to subscribe to the topic and decrypt the events. The branchId can be found in the branch Definition
1509    /// it can be useful to subscribe to this topic if the user is a member of the store's repo, so it will be notified of BranchCapRefresh on the overlay
1510    /// if the user is an external user to the store, it will lose access to the InnerOverlay after a BranchCapRefresh of the overlay branch of the store.
1511    pub store_overlay_readcap: ReadCap,
1512}
1513
1514/// Overlay Link
1515///
1516/// Details of the overlay of an NgLink
1517#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
1518pub enum OverlayLink {
1519    Outer(Digest),
1520    InnerLink(InnerOverlayLink),
1521    Inner(Digest),
1522    Inherit,
1523    Public(PubKey),
1524    Global,
1525}
1526
1527impl OverlayLink {
1528    pub fn is_outer(&self) -> bool {
1529        match self {
1530            Self::Outer(_) => true,
1531            _ => false,
1532        }
1533    }
1534    pub fn outer(&self) -> &Digest {
1535        match self {
1536            Self::Outer(o) => o,
1537            _ => panic!("not an outer overlay ID"),
1538        }
1539    }
1540}
1541
1542impl TryFrom<OverlayLink> for OverlayId {
1543    type Error = NgError;
1544    fn try_from(link: OverlayLink) -> Result<Self, Self::Error> {
1545        Ok(match link {
1546            OverlayLink::Inner(Digest::Blake3Digest32(i)) => OverlayId::Inner(i),
1547            OverlayLink::Outer(Digest::Blake3Digest32(i)) => OverlayId::Outer(i),
1548            OverlayLink::Global => OverlayId::Global,
1549            _ => return Err(NgError::InvalidArgument),
1550        })
1551    }
1552}
1553
1554impl From<OverlayId> for OverlayLink {
1555    fn from(id: OverlayId) -> Self {
1556        match id {
1557            OverlayId::Inner(i) => OverlayLink::Inner(Digest::from_slice(i)),
1558            OverlayId::Outer(o) => OverlayLink::Outer(Digest::from_slice(o)),
1559            OverlayId::Global => OverlayLink::Global,
1560        }
1561    }
1562}
1563
1564/// Overlay session ID
1565///
1566/// It is a pubkey used for signing all OverlayMessage sent by the peer.
1567/// Each peer generates it randomly when (re)joining the overlay network.
1568pub type SessionId = PubKey;
1569
1570/// Client ID: client of a user
1571pub type ClientId = PubKey;
1572
1573/// IPv4 address
1574pub type IPv4 = [u8; 4];
1575
1576const LOOPBACK_IPV4: IP = IP::IPv4([127, 0, 0, 1]);
1577
1578/// IPv6 address
1579pub type IPv6 = [u8; 16];
1580
1581/// IP address
1582#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
1583pub enum IP {
1584    IPv4(IPv4),
1585    IPv6(IPv6),
1586}
1587
1588impl IP {
1589    pub fn is_public(&self) -> bool {
1590        is_public_ip(&self.into())
1591    }
1592    pub fn is_private(&self) -> bool {
1593        is_private_ip(&self.into())
1594    }
1595    pub fn is_loopback(&self) -> bool {
1596        let t: &IpAddr = &self.into();
1597        t.is_loopback()
1598    }
1599    pub fn is_v6(&self) -> bool {
1600        if let Self::IPv6(_) = self {
1601            true
1602        } else {
1603            false
1604        }
1605    }
1606    pub fn is_v4(&self) -> bool {
1607        if let Self::IPv4(_) = self {
1608            true
1609        } else {
1610            false
1611        }
1612    }
1613}
1614
1615impl fmt::Display for IP {
1616    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1617        let t: IpAddr = self.try_into().unwrap();
1618        match self {
1619            IP::IPv4(_) => write!(f, "{}", t),
1620            IP::IPv6(_) => write!(f, "[{}]", t),
1621        }
1622    }
1623}
1624
1625impl From<&IpAddr> for IP {
1626    #[inline]
1627    fn from(ip: &IpAddr) -> IP {
1628        match ip {
1629            IpAddr::V4(v4) => IP::IPv4(v4.octets()),
1630            IpAddr::V6(v6) => IP::IPv6(v6.octets()),
1631        }
1632    }
1633}
1634
1635impl From<&IP> for IpAddr {
1636    #[inline]
1637    fn from(ip: &IP) -> IpAddr {
1638        match ip {
1639            IP::IPv4(v4) => IpAddr::from(*v4),
1640            IP::IPv6(v6) => IpAddr::from(*v6),
1641        }
1642    }
1643}
1644
1645/// IP transport protocol
1646#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
1647pub enum TransportProtocol {
1648    WS,
1649    QUIC,
1650    Local,
1651}
1652
1653/// IP transport address
1654#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
1655pub struct IPTransportAddr {
1656    pub ip: IP,
1657    pub port: u16,
1658    pub protocol: TransportProtocol,
1659}
1660
1661/// Network address
1662#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
1663pub enum NetAddr {
1664    IPTransport(IPTransportAddr),
1665}
1666
1667/**
1668* info : {
1669     type : WEB | NATIVE-IOS | NATIVE-ANDROID | NATIVE-MACOS | NATIVE-LINUX | NATIVE-WIN
1670            NATIVE-SERVICE | NODE-SERVICE | VERIFIER | CLIENT-BROKER | CLI
1671     vendor : (UA, node version, tauri webview, rust version)
1672     os : operating system string
1673     version : version of client
1674     date_install
1675     date_updated : last update
1676   }
1677*/
1678
1679/// Client Type
1680#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
1681pub enum ClientType {
1682    Web,
1683    NativeIos,
1684    NativeAndroid,
1685    NativeMacOS,
1686    NativeLinux,
1687    NativeWin,
1688    NativeService,
1689    NodeService,
1690    Verifier,
1691    VerifierLocal,
1692    Box,   // VerifierBox
1693    Stick, // VerifierStick
1694    WalletMaster,
1695    ClientBroker,
1696    Cli,
1697}
1698
1699#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
1700pub struct ClientInfoV0 {
1701    pub client_type: ClientType,
1702    pub details: String,
1703    pub version: String,
1704    pub timestamp_install: u64,
1705    pub timestamp_updated: u64,
1706}
1707
1708/// Client Info
1709#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
1710pub enum ClientInfo {
1711    V0(ClientInfoV0),
1712}
1713
1714impl ClientInfo {
1715    pub fn new(client_type: ClientType, details: String, version: String) -> ClientInfo {
1716        let timestamp_install = SystemTime::now()
1717            .duration_since(SystemTime::UNIX_EPOCH)
1718            .unwrap()
1719            .as_secs();
1720        ClientInfo::V0(ClientInfoV0 {
1721            details,
1722            version,
1723            client_type,
1724            timestamp_install,
1725            timestamp_updated: timestamp_install,
1726        })
1727    }
1728}
1729
1730//
1731// OVERLAY MESSAGES
1732//
1733
1734/// Overlay leave request
1735///
1736/// In outerOverlay: informs the broker that the overlay is not needed anymore
1737/// In innerOverlay: Sent to all connected overlay participants to terminate a session
1738#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
1739pub enum OverlayLeave {
1740    V0(),
1741}
1742
1743/// Content of PublisherAdvertV0
1744///
1745/// the peer is matched with the InnerOverlayMessageV0.Session -> peerId.
1746#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
1747pub struct PublisherAdvertContentV0 {
1748    /// Topic public key
1749    pub topic: TopicId,
1750
1751    /// Peer public key
1752    pub peer: DirectPeerId,
1753}
1754
1755/// Topic advertisement by a publisher
1756///
1757/// Flooded to all peers in overlay
1758/// Creates subscription routing table entries
1759#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
1760pub struct PublisherAdvertV0 {
1761    pub content: PublisherAdvertContentV0,
1762
1763    /// Signature over content by topic key
1764    pub sig: Sig,
1765}
1766
1767/// Topic advertisement by a publisher
1768#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
1769pub enum PublisherAdvert {
1770    V0(PublisherAdvertV0),
1771}
1772
1773impl PublisherAdvert {
1774    pub fn new(
1775        topic_id: TopicId,
1776        topic_key: BranchWriteCapSecret,
1777        broker_peer: DirectPeerId,
1778    ) -> PublisherAdvert {
1779        let content = PublisherAdvertContentV0 {
1780            peer: broker_peer,
1781            topic: topic_id,
1782        };
1783        let content_ser = serde_bare::to_vec(&content).unwrap();
1784        let sig = sign(&topic_key, &topic_id, &content_ser).unwrap();
1785        PublisherAdvert::V0(PublisherAdvertV0 { content, sig })
1786    }
1787    pub fn topic_id(&self) -> &TopicId {
1788        match self {
1789            Self::V0(v0) => &v0.content.topic,
1790        }
1791    }
1792
1793    pub fn verify(&self) -> Result<(), NgError> {
1794        match self {
1795            Self::V0(v0) => verify(
1796                &serde_bare::to_vec(&v0.content).unwrap(),
1797                v0.sig,
1798                v0.content.topic,
1799            ),
1800        }
1801    }
1802
1803    pub fn verify_for_broker(&self, peer_id: &DirectPeerId) -> Result<(), ProtocolError> {
1804        match self {
1805            Self::V0(v0) => {
1806                if v0.content.peer != *peer_id {
1807                    return Err(ProtocolError::InvalidPublisherAdvert);
1808                }
1809            }
1810        }
1811        Ok(self.verify()?)
1812    }
1813}
1814
1815/// Topic subscription request by a peer
1816///
1817/// Forwarded towards all publishers along subscription routing table entries
1818/// that are created by PublisherAdverts
1819/// Creates event routing table entries along the path
1820#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
1821pub struct SubReqV0 {
1822    /// Topic public key
1823    pub topic: TopicId,
1824
1825    /// For initial subscription, should be None,
1826    /// When updating a subscription after a new publisher has joined (with a PublisherAdvert),
1827    /// then the target publisher should be entered here.
1828    /// The brokers will only forward the SubscriptionRequest to that publisher (on all available paths)
1829    pub publisher: Option<DirectPeerId>,
1830}
1831
1832/// Topic subscription request by a peer
1833#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
1834pub enum SubReq {
1835    V0(SubReqV0),
1836}
1837
1838/// Topic subscription marker sent by all publishers, back to subscriber
1839///
1840/// Forwarded to all subscribers.
1841#[derive(Clone, Debug, Serialize, Deserialize)]
1842pub struct SubMarkerV0 {
1843    /// The publisher broker that marks its starting cut
1844    /// TODO: that could be omitted, because we can retrieve it with the SessionId
1845    pub publisher: DirectPeerId,
1846
1847    /// The subscribed topic
1848    pub topic: TopicId,
1849
1850    /// The subscriber
1851    pub subscriber: DirectPeerId,
1852
1853    /// Current heads at the broker when receiving the SubReq. Can be used to safely do a CoreTopicSyncReq
1854    pub known_heads: Vec<ObjectId>,
1855}
1856
1857/// Topic subscription acknowledgement by a publisher
1858#[derive(Clone, Debug, Serialize, Deserialize)]
1859pub enum SubMarker {
1860    V0(SubMarkerV0),
1861}
1862
1863/// Topic unsubscription request by a subscriber
1864///
1865/// A broker unsubscribes from all publisher brokers in the overlay
1866/// when it has no more local subscribers left
1867#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
1868pub struct UnsubReqV0 {
1869    /// Topic public key
1870    pub topic: TopicId,
1871}
1872
1873/// Topic unsubscription request by a subscriber
1874#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
1875pub enum UnsubReq {
1876    V0(UnsubReqV0),
1877}
1878
1879/// Object search in a pub/sub topic
1880///
1881/// Sent along the reverse path of a pub/sub topic
1882/// from a subscriber to one publisher at a time.
1883/// fanout is always 1
1884/// if result is none, tries another path if several paths available locally
1885/// answered with a stream of BlockResult
1886#[derive(Clone, Debug, Serialize, Deserialize)]
1887pub struct BlockSearchTopicV0 {
1888    /// Topic to forward the request in
1889    pub topic: TopicId,
1890
1891    /// Also search in subscribers
1892    pub search_in_subs: bool,
1893
1894    /// List of Object IDs to request
1895    pub ids: Vec<ObjectId>,
1896
1897    /// Whether or not to include all children recursively in the response
1898    pub include_children: bool,
1899
1900    /// List of Peer IDs the request traversed so far
1901    pub path: Vec<PeerId>,
1902}
1903
1904/// Object request by ID to publishers
1905#[derive(Clone, Debug, Serialize, Deserialize)]
1906pub enum BlockSearchTopic {
1907    V0(BlockSearchTopicV0),
1908}
1909
1910/// Block search along a random walk in the overlay
1911///
1912/// fanout is always 1
1913/// if result is none, tries another path if several paths available locally
1914/// answered with a stream BlockResult
1915#[derive(Clone, Debug, Serialize, Deserialize)]
1916pub struct BlockSearchRandomV0 {
1917    /// List of Block IDs to request
1918    pub ids: Vec<BlockId>,
1919
1920    /// Whether or not to include all children recursively in the response
1921    pub include_children: bool,
1922
1923    /// Number of random nodes to forward the request to at each step
1924    // pub fanout: u8,
1925    // for now fanout is always 1
1926
1927    /// List of Broker Peer IDs the request traversed so far
1928    pub path: Vec<DirectPeerId>,
1929}
1930
1931/// Block request by ID using a random walk in the overlay
1932#[derive(Clone, Debug, Serialize, Deserialize)]
1933pub enum BlockSearchRandom {
1934    V0(BlockSearchRandomV0),
1935}
1936
1937/// Response to a BlockSearch* request
1938///
1939/// can be a stream
1940#[derive(Clone, Debug, Serialize, Deserialize)]
1941pub struct BlockResultV0 {
1942    /// Resulting Blocks(s)
1943    pub payload: Vec<Block>,
1944}
1945
1946/// Response to a BlockSearch* request
1947///
1948/// can be a stream
1949#[derive(Clone, Debug, Serialize, Deserialize)]
1950pub enum BlockResult {
1951    V0(BlockResultV0),
1952}
1953
1954/// Topic synchronization request
1955///
1956/// In response a stream of `TopicSyncRes`s containing the missing Commits or events are sent
1957#[derive(Clone, Debug, Serialize, Deserialize)]
1958pub struct TopicSyncReqV0 {
1959    /// Topic public key
1960    pub topic: TopicId,
1961
1962    /// Fully synchronized until these commits
1963    pub known_heads: Vec<ObjectId>,
1964
1965    /// Stop synchronizing when these commits are met.
1966    /// if empty, the local HEAD at the responder is used instead
1967    pub target_heads: Vec<ObjectId>,
1968
1969    /// optional Bloom filter of all the commit IDs present locally (used in case of detected fork)
1970    pub known_commits: Option<BloomFilter>,
1971
1972    #[serde(skip)]
1973    pub overlay: Option<OverlayId>,
1974}
1975
1976/// Topic synchronization request
1977#[derive(Clone, Debug, Serialize, Deserialize)]
1978pub enum TopicSyncReq {
1979    V0(TopicSyncReqV0),
1980}
1981
1982impl TopicSyncReq {
1983    pub fn overlay(&self) -> &OverlayId {
1984        match self {
1985            Self::V0(v0) => v0.overlay.as_ref().unwrap(),
1986        }
1987    }
1988    pub fn set_overlay(&mut self, overlay: OverlayId) {
1989        match self {
1990            Self::V0(v0) => v0.overlay = Some(overlay),
1991        }
1992    }
1993    pub fn topic(&self) -> &TopicId {
1994        match self {
1995            TopicSyncReq::V0(o) => &o.topic,
1996        }
1997    }
1998    pub fn known_heads(&self) -> &Vec<ObjectId> {
1999        match self {
2000            TopicSyncReq::V0(o) => &o.known_heads,
2001        }
2002    }
2003    pub fn target_heads(&self) -> &Vec<ObjectId> {
2004        match self {
2005            TopicSyncReq::V0(o) => &o.target_heads,
2006        }
2007    }
2008    pub fn known_commits(&self) -> &Option<BloomFilter> {
2009        match self {
2010            TopicSyncReq::V0(o) => &o.known_commits,
2011        }
2012    }
2013}
2014
2015/// Status of a Forwarded Peer, sent in the Advert
2016#[derive(Clone, Debug, Serialize, Deserialize)]
2017pub enum PeerStatus {
2018    Connected,
2019    Disconnected,
2020}
2021
2022/// ForwardedPeerAdvertV0
2023///
2024/// peer_advert.forwarded_by is matched with sessionid->peerid
2025#[derive(Clone, Debug, Serialize, Deserialize)]
2026pub struct ForwardedPeerAdvertV0 {
2027    /// PeerAdvert received from Client
2028    // TODO: this could be obfuscated when user doesnt want to recall events.
2029    pub peer_advert: PeerAdvertV0,
2030
2031    /// Hashed user Id, used to prevent concurrent connection from different brokers
2032    /// BLAKE3 keyed hash over the UserId
2033    ///   - key: BLAKE3 derive_key ("NextGraph UserId Hash Overlay Id ForwardedPeerAdvertV0 BLAKE3 key", overlayId) // will always be an Inner overlay
2034    pub user_hash: Digest,
2035
2036    /// whether the Advert is about connection or disconnection
2037    pub status: PeerStatus,
2038}
2039
2040/// Forwarded Peer advertisement
2041#[derive(Clone, Debug, Serialize, Deserialize)]
2042pub enum ForwardedPeerAdvert {
2043    V0(ForwardedPeerAdvertV0),
2044}
2045
2046/// ForwardedPeerConflictV0
2047///
2048/// peer_advert.forwarded_by is matched with sessionid->peerid
2049/// When the forwarding broker receives the conflict (or notices it), it sends a notification
2050/// In order to avoid conflicts, the highest version of PeerAdvert should win, when the Forwarding Broker is different.
2051/// Disconnect wins over connect, for the exact same peer, version and forwarding broker.
2052/// Conflict can occur when same user_hash, on 2 different Forwarding Broker
2053/// Or when same peerId appears on 2 different Forwarding Broker.
2054#[derive(Clone, Debug, Serialize, Deserialize)]
2055pub struct ForwardedPeerConflictV0 {
2056    /// First conflicting PeerAdvert
2057    pub advert_1: ForwardedPeerAdvertV0,
2058    /// Second conflicting PeerAdvert
2059    pub advert_2: ForwardedPeerAdvertV0,
2060
2061    pub error_code: u16,
2062}
2063
2064/// Forwarded Peer advertisement conflict
2065#[derive(Clone, Debug, Serialize, Deserialize)]
2066pub enum ForwardedPeerConflict {
2067    V0(ForwardedPeerConflictV0),
2068}
2069
2070/// Content of PeerAdvertV0
2071#[derive(Clone, Debug, Serialize, Deserialize)]
2072pub struct PeerAdvertContentV0 {
2073    /// Peer ID
2074    pub peer: PeerId,
2075
2076    /// Id of the broker that is forwarding the peer
2077    pub forwarded_by: Option<DirectPeerId>,
2078
2079    /// Topic subscriptions
2080    // pub subs: BloomFilter128,
2081
2082    /// Network addresses, must be empty for forwarded peers
2083    pub address: Vec<NetAddr>,
2084
2085    /// Version number
2086    pub version: u32,
2087
2088    /// App-specific metadata (profile, cryptographic material, etc)
2089    #[serde(with = "serde_bytes")]
2090    pub metadata: Vec<u8>,
2091}
2092
2093/// Peer advertisement
2094///
2095/// Sent when a peer joins an inner overlay.
2096/// Used only for forwardedPeer for now.
2097/// In the future, Core brokers could exchange PeerAdvert on the global overlay, and also do some PeerSearch to search for IPs/newer version of PeerAdvert
2098/// When the forwarding broker receives a client connection, it checks that the peer isn't
2099#[derive(Clone, Debug, Serialize, Deserialize)]
2100pub struct PeerAdvertV0 {
2101    /// Peer advertisement content
2102    pub content: PeerAdvertContentV0,
2103
2104    /// Signature over content by peer's private key
2105    pub sig: Sig,
2106}
2107
2108/// Peer advertisement
2109#[derive(Clone, Debug, Serialize, Deserialize)]
2110pub enum PeerAdvert {
2111    V0(PeerAdvertV0),
2112}
2113
2114impl PeerAdvert {
2115    pub fn version(&self) -> u32 {
2116        match self {
2117            PeerAdvert::V0(o) => o.content.version,
2118        }
2119    }
2120    pub fn peer(&self) -> &PeerId {
2121        match self {
2122            PeerAdvert::V0(o) => &o.content.peer,
2123        }
2124    }
2125}
2126
2127/// Content of InnerOverlayMessageV0
2128#[derive(Clone, Debug, Serialize, Deserialize)]
2129pub enum InnerOverlayMessageContentV0 {
2130    OverlayLeave(OverlayLeave),
2131    ForwardedPeerAdvert(ForwardedPeerAdvert),
2132    ForwardedPeerConflict(ForwardedPeerConflict),
2133    PublisherJoined(PublisherAdvert),
2134    PublisherLeft(PublisherAdvert),
2135    SubReq(SubReq),
2136    SubMarker(SubMarker),
2137    UnsubReq(UnsubReq),
2138    Event(Event),
2139    //PostInboxRequest(PostInboxRequest),
2140    //PostInboxResponse(PostInboxResponse),
2141}
2142
2143/// Inner Overlay message payload V0
2144#[derive(Clone, Debug, Serialize, Deserialize)]
2145pub struct InnerOverlayMessagePayloadV0 {
2146    /// Sequence number incremented by peer when sending every overlay message in a session
2147    /// Used to prevent replay attacks inside the overlay
2148    pub seq: u64,
2149
2150    pub content: InnerOverlayMessageContentV0,
2151}
2152
2153/// Inner Overlay message V0
2154#[derive(Clone, Debug, Serialize, Deserialize)]
2155pub struct InnerOverlayMessageV0 {
2156    /// Session ID
2157    pub session: SessionId,
2158
2159    pub payload: InnerOverlayMessagePayloadV0,
2160
2161    /// Signature with Session private key, over payload
2162    pub sig: Sig,
2163
2164    /// Optional padding
2165    #[serde(with = "serde_bytes")]
2166    pub padding: Vec<u8>,
2167}
2168
2169/// Inner Overlay message
2170#[derive(Clone, Debug, Serialize, Deserialize)]
2171pub enum InnerOverlayMessage {
2172    V0(InnerOverlayMessageV0),
2173}
2174
2175/// Overlay Advert Payload V0
2176#[derive(Clone, Debug, Serialize, Deserialize)]
2177pub struct OverlayAdvertPayloadV0 {
2178    /// the target Overlay ID (cannot be an Outer overlay)
2179    pub overlay: OverlayId,
2180
2181    /// the newly generated session ID the peer will use in this overlay
2182    /// All the revoked sessionIDs are kept locally by their initiator.
2183    pub session: SessionId,
2184
2185    /// Current sequence number. For a new session, must be zero.
2186    pub seq: u64,
2187
2188    /// list of publisher currently registered on the peer.
2189    /// flooded in overlay (with this overlayAdvert) when first joining an overlay, so that subscription routing tables can be updated
2190    /// or sent in an OverlayAdvertMarker, to a specific new peer that just joined the overlay (in the point of view of the emitter)
2191    /// it can be left empty when a CoreBrokerConnect is made on a broker that is known to be already part of the overlay.
2192    pub publishers: Vec<PublisherAdvert>,
2193
2194    /// the previous session ID the peer was using in this overlay. Used to cleanup seq counters maintained in each other peer
2195    /// if the previous session is empty (because it is the first time broker joins this overlay)
2196    /// or if a remote peer doesn't find this session kept locally, it is not an error.
2197    /// In the later case (if broker missed some intermediary sessions), the remote peer can ask the initiator peer if the last known
2198    /// session can be locally revoked with a ConfirmRevokedSession message (answered with yes or no)
2199    pub previous_session: Option<SessionId>,
2200
2201    /// peer ID of the broker issuing this Advert
2202    pub peer: DirectPeerId,
2203}
2204
2205/// Overlay Advert V0 : used by a broker peer every time it (re)joins an overlay
2206#[derive(Clone, Debug, Serialize, Deserialize)]
2207pub struct OverlayAdvertV0 {
2208    pub payload: OverlayAdvertPayloadV0,
2209
2210    /// Signature with peerId private key, over payload
2211    pub sig: Sig,
2212}
2213
2214/// Overlay Advert : used by a broker peer every time it (re)joins an overlay
2215#[derive(Clone, Debug, Serialize, Deserialize)]
2216pub enum OverlayAdvert {
2217    V0(OverlayAdvertV0),
2218}
2219
2220/// CoreBrokerJoinedAdvert V0
2221///
2222/// Each broker that is already part of an overlay, when receiving the CoreBrokerJoinedAdvert, should answer with one direct message
2223/// to the joining peer (found in OverlayAdvertPayloadV0.peer) for each overlay, containing an OverlayAdvertMarker containing their current sequence number.
2224/// This is sent for each path (in case multiple paths arrive to the same broker). Only the first sequence number received by joining peer is kept locally
2225#[derive(Clone, Debug, Serialize, Deserialize)]
2226pub struct CoreBrokerJoinedAdvertV0 {
2227    /// list of overlays joined by an initiator broker, and that the forwarding broker has also previously joined
2228    /// the forwarding broker keeps the ingress edge and all egress edges in the coreRoutingTable
2229    pub overlays: Vec<OverlayAdvertV0>,
2230}
2231
2232/// CoreBrokerLeftAdvert V0
2233///
2234/// A broker has disconnected from another broker, and the routes need to be updated
2235/// this is not used to leave one specific overlay. see OverlayLeave message for that purpose
2236#[derive(Clone, Debug, Serialize, Deserialize)]
2237pub struct CoreBrokerLeftAdvertV0 {
2238    /// The broker that disconnected from the one that is emitting this advert.
2239    pub disconnected: DirectPeerId,
2240}
2241
2242/// CoreOverlayJoinedAdvert V0
2243#[derive(Clone, Debug, Serialize, Deserialize)]
2244pub struct CoreOverlayJoinedAdvertV0 {
2245    /// One additional overlay joined by an initiator broker, and that the forwarding broker has also previously joined
2246    /// the forwarding broker keeps the ingress edge and all egress edges in the coreRoutingTable
2247    pub overlay: OverlayAdvertV0,
2248}
2249
2250#[derive(Clone, Debug, Serialize, Deserialize)]
2251pub enum CoreBrokerJoinedAdvert {
2252    V0(CoreBrokerJoinedAdvertV0),
2253}
2254
2255#[derive(Clone, Debug, Serialize, Deserialize)]
2256pub enum CoreBrokerLeftAdvert {
2257    V0(CoreBrokerLeftAdvertV0),
2258}
2259
2260#[derive(Clone, Debug, Serialize, Deserialize)]
2261pub enum CoreOverlayJoinedAdvert {
2262    V0(CoreOverlayJoinedAdvertV0),
2263}
2264
2265/// Content of CoreAdvert V0
2266#[derive(Clone, Debug, Serialize, Deserialize)]
2267pub enum CoreAdvertContentV0 {
2268    BrokerJoined(CoreBrokerJoinedAdvert),
2269    BrokerLeft(CoreBrokerLeftAdvert),
2270    OverlayJoined(CoreOverlayJoinedAdvert),
2271}
2272
2273/// CoreAdvert V0
2274#[derive(Clone, Debug, Serialize, Deserialize)]
2275pub struct CoreAdvertV0 {
2276    pub content: CoreAdvertContentV0,
2277
2278    /// list of brokers on the path that was followed to deliver this advert.
2279    /// new entry pushed each time a forward is happening in the core network
2280    pub path: Vec<DirectPeerId>,
2281
2282    /// content signed by the first broker in the path
2283    pub sig: Sig,
2284
2285    /// Optional padding
2286    #[serde(with = "serde_bytes")]
2287    pub padding: Vec<u8>,
2288}
2289
2290/// OverlayAdvertMarker V0
2291///
2292/// when receiving a marker, the broker saves the ingress edge and the corresponding remote peer and
2293/// overlay that can be reached (the OverlayAdvertPayloadV0.peer and .overlay) in the CoreRoutingTable
2294/// It also saves the sessionId and seq number
2295/// then a ReturnPathTimingAdvert is sent back
2296#[derive(Clone, Debug, Serialize, Deserialize)]
2297pub struct OverlayAdvertMarkerV0 {
2298    pub marker: OverlayAdvertV0,
2299
2300    /// New SessionId that triggered this marker (to avoid replay attacks in the core network)
2301    pub in_reply_to: SessionId,
2302
2303    /// path from the new broker who started a session, to the broker that is sending the marker
2304    pub path: Vec<DirectPeerId>,
2305
2306    /// randomly generated nonce used for the reply (a ReturnPathTimingMarker) that will be sent back after this marker has been received on the other end
2307    pub reply_nonce: u64,
2308}
2309
2310/// Core Block Get V0
2311#[derive(Clone, Debug, Serialize, Deserialize)]
2312pub struct CoreBlocksGetV0 {
2313    /// Block ID to request
2314    pub ids: Vec<BlockId>,
2315
2316    /// Whether or not to include all children recursively
2317    pub include_children: bool,
2318
2319    /// randomly generated number by requester, used for sending reply.
2320    /// the requester keeps track of req_nonce and requested peerid.
2321    /// used for handling the stream
2322    pub req_nonce: u64,
2323}
2324
2325/// Core Block Result V0
2326///
2327/// can be a stream
2328#[derive(Clone, Debug, Serialize, Deserialize)]
2329pub struct CoreBlockResultV0 {
2330    /// Resulting Object(s)
2331    pub payload: Vec<Block>,
2332
2333    /// randomly generated number by requester, as received in the request
2334    pub req_nonce: u64,
2335}
2336
2337/// ReturnPathTimingAdvertV0
2338#[derive(Clone, Debug, Serialize, Deserialize)]
2339pub struct ReturnPathTimingAdvertV0 {
2340    /// Signature over nonce, by sessionId
2341    pub sig: Sig,
2342
2343    /// randomly generated number as received in the OverlayAdvertMarker
2344    pub nonce: u64,
2345}
2346
2347#[derive(Clone, Debug, Serialize, Deserialize)]
2348pub enum OverlayAdvertMarker {
2349    V0(OverlayAdvertMarkerV0),
2350}
2351
2352#[derive(Clone, Debug, Serialize, Deserialize)]
2353pub enum ReturnPathTimingAdvert {
2354    V0(ReturnPathTimingAdvertV0),
2355}
2356
2357#[derive(Clone, Debug, Serialize, Deserialize)]
2358pub enum CoreBlocksGet {
2359    V0(CoreBlocksGetV0),
2360}
2361
2362#[derive(Clone, Debug, Serialize, Deserialize)]
2363pub enum CoreBlockResult {
2364    V0(CoreBlockResultV0),
2365}
2366
2367/// Content of CoreDirectMessage V0
2368#[derive(Clone, Debug, Serialize, Deserialize)]
2369pub enum CoreDirectMessageContentV0 {
2370    OverlayAdvertMarker(OverlayAdvertMarker),
2371    ReturnPathTimingAdvert(ReturnPathTimingAdvert),
2372    BlocksGet(CoreBlocksGet),
2373    BlockResult(CoreBlockResult),
2374    //PostInbox,
2375    //PartialSignature,
2376    //ClientDirectMessage //for messages between forwarded or direct peers
2377}
2378
2379/// CoreDirectMessage V0
2380#[derive(Clone, Debug, Serialize, Deserialize)]
2381pub struct CoreDirectMessageV0 {
2382    pub content: CoreDirectMessageContentV0,
2383
2384    /// list of brokers on the path that must be followed to deliver this message, next hop is at the bottom of the list.
2385    /// last entry on the list is popped each time a broker is forwarding upstream
2386    /// when list size is zero, the final destination is reached.
2387    /// if only one peer in list, and peer not found in local CoreRoutingTable, use the best route to reach it (without popping)
2388    pub reverse_path: Vec<DirectPeerId>,
2389
2390    /// The sender
2391    pub from: DirectPeerId,
2392
2393    /// content signed by the sender
2394    pub sig: Sig,
2395
2396    /// Optional padding
2397    #[serde(with = "serde_bytes")]
2398    pub padding: Vec<u8>,
2399}
2400
2401/// CoreBrokerConnect V0
2402///
2403/// replied with CoreBrokerConnectResponse
2404#[derive(Clone, Debug, Serialize, Deserialize)]
2405pub struct CoreBrokerConnectV0 {
2406    pub inner_overlays: Vec<OverlayAdvertV0>,
2407    pub outer_overlays: Vec<Digest>,
2408}
2409
2410/// CoreBrokerConnect
2411#[derive(Clone, Debug, Serialize, Deserialize)]
2412pub enum CoreBrokerConnect {
2413    V0(CoreBrokerConnectV0),
2414}
2415
2416/// CoreBrokerConnectResponse
2417#[derive(Clone, Debug, Serialize, Deserialize)]
2418pub enum CoreBrokerConnectResponse {
2419    V0(CoreBrokerConnectResponseV0),
2420}
2421
2422impl CoreBrokerConnect {
2423    pub fn core_message(&self, id: i64) -> CoreMessage {
2424        match self {
2425            CoreBrokerConnect::V0(v0) => {
2426                CoreMessage::V0(CoreMessageV0::Request(CoreRequest::V0(CoreRequestV0 {
2427                    padding: vec![],
2428                    id,
2429                    content: CoreRequestContentV0::BrokerConnect(CoreBrokerConnect::V0(v0.clone())),
2430                })))
2431            }
2432        }
2433    }
2434}
2435
2436/// sent to a direct peer just before closing the connection
2437pub type CoreBrokerDisconnectV0 = ();
2438
2439/// Content of CoreOverlayJoin V0
2440///
2441/// replied with an emptyResponse, and an error code if OverlayId not present on remote broker
2442#[derive(Clone, Debug, Serialize, Deserialize)]
2443pub enum CoreOverlayJoinV0 {
2444    Inner(OverlayAdvert),
2445    Outer(Digest),
2446}
2447
2448/// Content of OuterOverlayResponse V0
2449#[derive(Clone, Debug, Serialize, Deserialize)]
2450pub enum OuterOverlayResponseContentV0 {
2451    EmptyResponse(()),
2452    Block(Block),
2453    TopicSyncRes(TopicSyncRes),
2454    //PostInboxResponse(PostInboxResponse),
2455}
2456
2457/// Content of OuterOverlayRequest V0
2458#[derive(Clone, Debug, Serialize, Deserialize)]
2459pub enum OuterOverlayRequestContentV0 {
2460    TopicSyncReq(TopicSyncReq),
2461    OverlayLeave(OverlayLeave),
2462    TopicSub(PubKey),
2463    TopicUnsub(PubKey),
2464    BlocksGet(BlocksGet),
2465    //PostInboxRequest(PostInboxRequest),
2466}
2467
2468/// OuterOverlayRequestV0 V0
2469///
2470/// replied with OuterOverlayResponseV0
2471#[derive(Clone, Debug, Serialize, Deserialize)]
2472pub struct OuterOverlayRequestV0 {
2473    pub overlay: Digest,
2474    pub content: OuterOverlayRequestContentV0,
2475}
2476
2477/// OuterOverlayResponse V0
2478///
2479/// reply to an OuterOverlayRequest V0
2480#[derive(Clone, Debug, Serialize, Deserialize)]
2481pub struct OuterOverlayResponseV0 {
2482    pub overlay: Digest,
2483    pub content: OuterOverlayResponseContentV0,
2484}
2485
2486/// Core Topic synchronization request
2487///
2488/// behaves like BlockSearchTopic (primarily searches among the publishers, except if search_in_subs is set to true)
2489/// fanout is 1 for now
2490///
2491/// If some target_heads are not found locally, all successors of known_heads are sent anyway,
2492/// and then this temporary HEAD is used to propagate/fanout the CoreTopicSyncReq to upstream brokers
2493///
2494/// Answered with one or many TopicSyncRes a stream of `Block`s or Event of the commits
2495/// If the responder has an Event for the commit(s) in its HEAD, it will send the event instead of the plain commit's blocks.
2496#[derive(Clone, Debug, Serialize, Deserialize)]
2497pub struct CoreTopicSyncReqV0 {
2498    /// Topic public key
2499    pub topic: TopicId,
2500
2501    /// Also search in subscribers, in addition to publishers
2502    pub search_in_subs: bool,
2503
2504    /// Fully synchronized until these commits
2505    pub known_heads: Vec<ObjectId>,
2506
2507    /// Stop synchronizing when these commits are met.
2508    /// if empty, the local HEAD at the responder is used instead
2509    pub target_heads: Vec<ObjectId>,
2510}
2511
2512/// Topic synchronization request
2513#[derive(Clone, Debug, Serialize, Deserialize)]
2514pub enum CoreTopicSyncReq {
2515    V0(CoreTopicSyncReqV0),
2516}
2517
2518/// Topic synchronization response V0
2519#[derive(Clone, Debug, Serialize, Deserialize)]
2520pub enum TopicSyncResV0 {
2521    Event(Event),
2522    Block(Block),
2523}
2524
2525/// Topic synchronization response
2526///
2527/// it is a stream of blocks and or events.
2528#[derive(Clone, Debug, Serialize, Deserialize)]
2529pub enum TopicSyncRes {
2530    V0(TopicSyncResV0),
2531}
2532
2533impl TopicSyncRes {
2534    pub fn event(&self) -> &Event {
2535        match self {
2536            Self::V0(TopicSyncResV0::Event(e)) => e,
2537            _ => panic!("this TopicSyncResV0 is not an event"),
2538        }
2539    }
2540}
2541
2542impl fmt::Display for TopicSyncRes {
2543    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2544        match self {
2545            Self::V0(v0) => match v0 {
2546                TopicSyncResV0::Event(e) => writeln!(f, "====== Event ====== {e}"),
2547                TopicSyncResV0::Block(b) => writeln!(f, "====== Block ID ====== {}", b.id()),
2548            },
2549        }
2550    }
2551}
2552
2553#[derive(Clone, Debug, Serialize, Deserialize)]
2554pub enum CoreBrokerDisconnect {
2555    V0(CoreBrokerDisconnectV0),
2556}
2557
2558#[derive(Clone, Debug, Serialize, Deserialize)]
2559pub enum CoreOverlayJoin {
2560    V0(CoreOverlayJoinV0),
2561}
2562
2563#[derive(Clone, Debug, Serialize, Deserialize)]
2564pub enum OuterOverlayRequest {
2565    V0(OuterOverlayRequestV0),
2566}
2567
2568/// Content of CoreRequest V0
2569#[derive(Clone, Debug, Serialize, Deserialize)]
2570pub enum CoreRequestContentV0 {
2571    BrokerConnect(CoreBrokerConnect),
2572    BrokerDisconnect(CoreBrokerDisconnect),
2573    OverlayJoin(CoreOverlayJoin),
2574    BlockSearchTopic(BlockSearchTopic),
2575    BlockSearchRandom(BlockSearchRandom),
2576    TopicSyncReq(CoreTopicSyncReq),
2577    OuterOverlayRequest(OuterOverlayRequest),
2578}
2579
2580/// CoreRequest V0
2581///
2582/// replied with CoreResponse V0
2583#[derive(Clone, Debug, Serialize, Deserialize)]
2584pub struct CoreRequestV0 {
2585    /// Request ID
2586    pub id: i64,
2587    pub content: CoreRequestContentV0,
2588
2589    /// Optional padding
2590    #[serde(with = "serde_bytes")]
2591    pub padding: Vec<u8>,
2592}
2593
2594/// Request sent to a broker in the core network
2595#[derive(Clone, Debug, Serialize, Deserialize)]
2596pub enum CoreRequest {
2597    V0(CoreRequestV0),
2598}
2599
2600/// CoreBrokerConnectResponse V0
2601///
2602/// reply to a CoreBrokerConnect V0
2603#[derive(Clone, Debug, Serialize, Deserialize)]
2604pub struct CoreBrokerConnectResponseV0 {
2605    pub successes: Vec<OverlayId>,
2606    pub errors: Vec<OverlayId>,
2607}
2608
2609#[derive(Clone, Debug, Serialize, Deserialize)]
2610pub enum OuterOverlayResponse {
2611    V0(OuterOverlayResponseV0),
2612}
2613
2614/// Content CoreResponse V0
2615#[derive(Clone, Debug, Serialize, Deserialize)]
2616pub enum CoreResponseContentV0 {
2617    BrokerConnectResponse(CoreBrokerConnectResponse),
2618    BlockResult(BlockResult),
2619    TopicSyncRes(TopicSyncRes),
2620    OuterOverlayResponse(OuterOverlayResponse),
2621    EmptyResponse(()),
2622}
2623
2624/// CoreResponse V0
2625///
2626/// reply to a CoreRequest V0
2627#[derive(Clone, Debug, Serialize, Deserialize)]
2628pub struct CoreResponseV0 {
2629    /// Request ID
2630    pub id: i64,
2631
2632    /// Result
2633    pub result: u16,
2634    pub content: CoreResponseContentV0,
2635
2636    /// Optional padding
2637    #[serde(with = "serde_bytes")]
2638    pub padding: Vec<u8>,
2639}
2640
2641/// Response to a Request sent to a broker in the core network
2642#[derive(Clone, Debug, Serialize, Deserialize)]
2643pub enum CoreResponse {
2644    V0(CoreResponseV0),
2645}
2646
2647#[derive(Clone, Debug, Serialize, Deserialize)]
2648pub enum OuterOverlayMessageContentV0 {
2649    Event(Event),
2650}
2651
2652/// OuterOverlayMessage V0
2653#[derive(Clone, Debug, Serialize, Deserialize)]
2654pub struct OuterOverlayMessageV0 {
2655    pub overlay: Digest,
2656
2657    pub content: OuterOverlayMessageContentV0,
2658
2659    /// Optional padding
2660    #[serde(with = "serde_bytes")]
2661    pub padding: Vec<u8>,
2662}
2663
2664#[derive(Clone, Debug, Serialize, Deserialize)]
2665pub enum CoreAdvert {
2666    V0(CoreAdvertV0),
2667}
2668
2669#[derive(Clone, Debug, Serialize, Deserialize)]
2670pub enum CoreDirectMessage {
2671    V0(CoreDirectMessageV0),
2672}
2673
2674#[derive(Clone, Debug, Serialize, Deserialize)]
2675pub enum OuterOverlayMessage {
2676    V0(OuterOverlayMessageV0),
2677}
2678
2679/// CoreMessageV0
2680#[derive(Clone, Debug, Serialize, Deserialize)]
2681pub enum CoreMessageV0 {
2682    Request(CoreRequest),
2683    Response(CoreResponse),
2684    Advert(CoreAdvert),
2685    Direct(CoreDirectMessage),
2686    InnerOverlay(InnerOverlayMessage),
2687    OuterOverlay(OuterOverlayMessage),
2688}
2689
2690/// Core message
2691#[derive(Clone, Debug, Serialize, Deserialize)]
2692pub enum CoreMessage {
2693    V0(CoreMessageV0),
2694}
2695
2696/// AppMessageContentV0
2697#[derive(Clone, Debug, Serialize, Deserialize)]
2698pub enum AppMessageContentV0 {
2699    Request(AppRequest),
2700    Response(AppResponse),
2701    SessionStop(AppSessionStop),
2702    SessionStart(AppSessionStart),
2703    EmptyResponse,
2704}
2705
2706/// AppMessageV0
2707#[derive(Clone, Debug, Serialize, Deserialize)]
2708pub struct AppMessageV0 {
2709    pub content: AppMessageContentV0,
2710
2711    pub id: i64,
2712
2713    pub result: u16,
2714}
2715
2716/// App message
2717#[derive(Clone, Debug, Serialize, Deserialize)]
2718pub enum AppMessage {
2719    V0(AppMessageV0),
2720}
2721
2722impl IStreamable for AppMessage {
2723    fn result(&self) -> u16 {
2724        match self {
2725            AppMessage::V0(v0) => v0.result,
2726        }
2727    }
2728    fn set_result(&mut self, result: u16) {
2729        match self {
2730            AppMessage::V0(v0) => v0.result = result,
2731        }
2732    }
2733}
2734
2735impl AppMessage {
2736    pub fn get_actor(&self) -> Box<dyn EActor> {
2737        match self {
2738            AppMessage::V0(AppMessageV0 { content: o, id, .. }) => match o {
2739                AppMessageContentV0::Request(req) => req.get_actor(*id),
2740                AppMessageContentV0::SessionStop(req) => req.get_actor(*id),
2741                AppMessageContentV0::SessionStart(req) => req.get_actor(*id),
2742                AppMessageContentV0::Response(_) | AppMessageContentV0::EmptyResponse => {
2743                    panic!("it is not a request");
2744                }
2745            },
2746        }
2747    }
2748    pub fn id(&self) -> Option<i64> {
2749        match self {
2750            AppMessage::V0(v0) => Some(v0.id),
2751        }
2752    }
2753    pub fn set_id(&mut self, id: i64) {
2754        match self {
2755            AppMessage::V0(r) => r.id = id,
2756        }
2757    }
2758}
2759
2760impl From<AppMessage> for ProtocolMessage {
2761    fn from(msg: AppMessage) -> ProtocolMessage {
2762        ProtocolMessage::AppMessage(msg)
2763    }
2764}
2765
2766//
2767// ADMIN PROTOCOL
2768//
2769
2770/// Content of `AdminRequestV0`
2771#[derive(Clone, Debug, Serialize, Deserialize)]
2772pub enum AdminRequestContentV0 {
2773    AddUser(AddUser),
2774    DelUser(DelUser),
2775    ListUsers(ListUsers),
2776    ListInvitations(ListInvitations),
2777    AddInvitation(AddInvitation),
2778    #[doc(hidden)]
2779    CreateUser(CreateUser),
2780}
2781impl AdminRequestContentV0 {
2782    pub fn type_id(&self) -> TypeId {
2783        match self {
2784            Self::AddUser(a) => a.type_id(),
2785            Self::DelUser(a) => a.type_id(),
2786            Self::ListUsers(a) => a.type_id(),
2787            Self::ListInvitations(a) => a.type_id(),
2788            Self::AddInvitation(a) => a.type_id(),
2789            Self::CreateUser(a) => a.type_id(),
2790        }
2791    }
2792    pub fn get_actor(&self) -> Box<dyn EActor> {
2793        match self {
2794            Self::AddUser(a) => a.get_actor(),
2795            Self::DelUser(a) => a.get_actor(),
2796            Self::ListUsers(a) => a.get_actor(),
2797            Self::ListInvitations(a) => a.get_actor(),
2798            Self::AddInvitation(a) => a.get_actor(),
2799            Self::CreateUser(a) => a.get_actor(),
2800        }
2801    }
2802}
2803
2804/// Admin request
2805#[derive(Clone, Debug, Serialize, Deserialize)]
2806pub struct AdminRequestV0 {
2807    /// Request ID
2808    pub id: i64,
2809
2810    /// Request content
2811    pub content: AdminRequestContentV0,
2812
2813    /// Signature over content by admin key
2814    pub sig: Sig,
2815
2816    /// THe admin user requesting this operation
2817    pub admin_user: PubKey,
2818
2819    /// Optional padding
2820    #[serde(with = "serde_bytes")]
2821    pub padding: Vec<u8>,
2822}
2823
2824impl AdminRequestV0 {
2825    pub fn get_actor(&self) -> Box<dyn EActor> {
2826        self.content.get_actor()
2827    }
2828}
2829
2830/// Admin request
2831#[derive(Clone, Debug, Serialize, Deserialize)]
2832pub enum AdminRequest {
2833    V0(AdminRequestV0),
2834}
2835
2836impl AdminRequest {
2837    pub fn id(&self) -> i64 {
2838        match self {
2839            Self::V0(o) => o.id,
2840        }
2841    }
2842    pub fn set_id(&mut self, id: i64) {
2843        match self {
2844            Self::V0(v0) => {
2845                v0.id = id;
2846            }
2847        }
2848    }
2849    pub fn type_id(&self) -> TypeId {
2850        match self {
2851            Self::V0(o) => o.content.type_id(),
2852        }
2853    }
2854    pub fn sig(&self) -> Sig {
2855        match self {
2856            Self::V0(o) => o.sig,
2857        }
2858    }
2859    pub fn admin_user(&self) -> PubKey {
2860        match self {
2861            Self::V0(o) => o.admin_user,
2862        }
2863    }
2864    pub fn get_actor(&self) -> Box<dyn EActor> {
2865        match self {
2866            Self::V0(a) => a.get_actor(),
2867        }
2868    }
2869}
2870
2871impl From<AdminRequest> for ProtocolMessage {
2872    fn from(msg: AdminRequest) -> ProtocolMessage {
2873        ProtocolMessage::Start(StartProtocol::Admin(msg))
2874    }
2875}
2876
2877/// Content of `AdminResponseV0`
2878#[derive(Clone, Debug, Serialize, Deserialize)]
2879pub enum AdminResponseContentV0 {
2880    EmptyResponse,
2881    Users(Vec<PubKey>),
2882    Invitations(Vec<(InvitationCode, u32, Option<String>)>),
2883    Invitation(Invitation),
2884    UserId(UserId),
2885}
2886
2887/// Response to an `AdminRequest` V0
2888#[derive(Clone, Debug, Serialize, Deserialize)]
2889pub struct AdminResponseV0 {
2890    /// Request ID
2891    pub id: i64,
2892
2893    /// Result (including but not limited to Result)
2894    pub result: u16,
2895
2896    pub content: AdminResponseContentV0,
2897
2898    /// Optional padding
2899    #[serde(with = "serde_bytes")]
2900    pub padding: Vec<u8>,
2901}
2902
2903/// Response to an `AdminRequest`
2904#[derive(Clone, Debug, Serialize, Deserialize)]
2905pub enum AdminResponse {
2906    V0(AdminResponseV0),
2907}
2908
2909impl From<Result<(), ProtocolError>> for AdminResponseV0 {
2910    fn from(res: Result<(), ProtocolError>) -> AdminResponseV0 {
2911        AdminResponseV0 {
2912            id: 0,
2913            result: res.map(|_| 0).unwrap_or_else(|e| e.into()),
2914            content: AdminResponseContentV0::EmptyResponse,
2915            padding: vec![],
2916        }
2917    }
2918}
2919
2920impl From<Result<PubKey, ProtocolError>> for AdminResponseV0 {
2921    fn from(res: Result<PubKey, ProtocolError>) -> AdminResponseV0 {
2922        match res {
2923            Err(e) => AdminResponseV0 {
2924                id: 0,
2925                result: e.into(),
2926                content: AdminResponseContentV0::EmptyResponse,
2927                padding: vec![],
2928            },
2929            Ok(id) => AdminResponseV0 {
2930                id: 0,
2931                result: 0,
2932                content: AdminResponseContentV0::UserId(id),
2933                padding: vec![],
2934            },
2935        }
2936    }
2937}
2938
2939impl From<Result<Vec<PubKey>, ProtocolError>> for AdminResponseV0 {
2940    fn from(res: Result<Vec<PubKey>, ProtocolError>) -> AdminResponseV0 {
2941        match res {
2942            Err(e) => AdminResponseV0 {
2943                id: 0,
2944                result: e.into(),
2945                content: AdminResponseContentV0::EmptyResponse,
2946                padding: vec![],
2947            },
2948            Ok(vec) => AdminResponseV0 {
2949                id: 0,
2950                result: 0,
2951                content: AdminResponseContentV0::Users(vec),
2952                padding: vec![],
2953            },
2954        }
2955    }
2956}
2957
2958impl From<AdminResponseV0> for ProtocolMessage {
2959    fn from(msg: AdminResponseV0) -> ProtocolMessage {
2960        ProtocolMessage::AdminResponse(AdminResponse::V0(msg))
2961    }
2962}
2963
2964impl From<AdminResponse> for ProtocolMessage {
2965    fn from(msg: AdminResponse) -> ProtocolMessage {
2966        ProtocolMessage::AdminResponse(msg)
2967    }
2968}
2969
2970impl TryFrom<ProtocolMessage> for AdminResponse {
2971    type Error = ProtocolError;
2972    fn try_from(msg: ProtocolMessage) -> Result<Self, Self::Error> {
2973        if let ProtocolMessage::AdminResponse(res) = msg {
2974            Ok(res)
2975        } else {
2976            Err(ProtocolError::InvalidValue)
2977        }
2978    }
2979}
2980
2981impl AdminResponse {
2982    pub fn id(&self) -> i64 {
2983        match self {
2984            Self::V0(o) => o.id,
2985        }
2986    }
2987    pub fn set_id(&mut self, id: i64) {
2988        match self {
2989            Self::V0(v0) => {
2990                v0.id = id;
2991            }
2992        }
2993    }
2994    pub fn result(&self) -> u16 {
2995        match self {
2996            Self::V0(o) => o.result,
2997        }
2998    }
2999    pub fn content_v0(&self) -> AdminResponseContentV0 {
3000        match self {
3001            Self::V0(o) => o.content.clone(),
3002        }
3003    }
3004}
3005
3006//
3007// CLIENT PROTOCOL
3008//
3009
3010/// Request to open a repo in a non-durable way (without pinning it).
3011///
3012/// When client will disconnect, the subscriptions and publisherAdvert of the topics will be removed,
3013/// except if a PinRepo occurred before or after the OpenRepo
3014/// replied with a RepoOpened
3015#[derive(Clone, Debug, Serialize, Deserialize)]
3016pub struct OpenRepoV0 {
3017    /// Repo Hash
3018    pub hash: RepoHash,
3019
3020    // for RW overlay, the overlay that should be used in the clientmessage is the innerOverlay
3021    pub overlay: OverlayAccess,
3022
3023    /// Broker peers to connect to in order to join the overlay
3024    /// can be empty for private store (the broker will not connect to any other broker)
3025    /// but if the private repo is pinned in other brokers, those brokers should be entered here for syncing.
3026    /// can be empty also when we just created the repo, and there are no other brokers in the overlay
3027    pub peers: Vec<PeerAdvert>,
3028
3029    /// a list of core brokers that are allowed to connect to the overlay (only valid for an inner (RW/WO) overlay).
3030    /// an empty list means any core broker is allowed. this is the default behaviour.
3031    /// to restrict the overlay to only the current core, its DirectPeerId should be entered here.
3032    // pub allowed_peers: Vec<DirectPeerId>,
3033
3034    /// Maximum number of peers to connect to for this overlay (only valid for an inner (RW/WO) overlay)
3035    /// 0 means automatic/unlimited
3036    pub max_peer_count: u16,
3037
3038    /// list of topics that should be subscribed to
3039    pub ro_topics: Vec<TopicId>,
3040
3041    /// list of topics for which we will be a publisher
3042    /// only possible with inner (RW or WO) overlays.
3043    /// implies also subscribing to it (no need to put it also in ro_topics)
3044    pub rw_topics: Vec<PublisherAdvert>,
3045}
3046
3047/// Request to open a repo
3048#[derive(Clone, Debug, Serialize, Deserialize)]
3049pub enum OpenRepo {
3050    V0(OpenRepoV0),
3051}
3052
3053impl OpenRepo {
3054    pub fn peers(&self) -> &Vec<PeerAdvert> {
3055        match self {
3056            OpenRepo::V0(o) => &o.peers,
3057        }
3058    }
3059}
3060
3061/// Request to pin a repo on the broker.
3062///
3063/// When client will disconnect, the subscriptions and publisherAdvert of the topics will remain active on the broker.
3064/// replied with a RepoOpened
3065#[derive(Clone, Debug, Serialize, Deserialize)]
3066pub struct PinRepoV0 {
3067    /// Repo Hash
3068    pub hash: RepoHash,
3069
3070    /// for RW overlay, the overlay that should be used in the clientmessage is the innerOverlay
3071    pub overlay: OverlayAccess,
3072
3073    /// Root topic of the overlay, used to listen to overlay refreshes. Only used for inner (RW or WO) overlays
3074    pub overlay_root_topic: Option<TopicId>,
3075
3076    /// only possible for RW overlays. not allowed for private or dialog overlay
3077    pub expose_outer: bool,
3078
3079    /// Broker peers to connect to in order to join the overlay
3080    /// If the repo has previously been opened (during the same session) or if it is a private overlay, then peers info can be omitted.
3081    /// If there are no known peers in the overlay yet, vector is left empty (creation of a store, or repo in a store that is owned by user).
3082    pub peers: Vec<PeerAdvert>,
3083
3084    /// Maximum number of peers to connect to for this overlay (only valid for an inner (RW/WO) overlay)
3085    pub max_peer_count: u16,
3086
3087    // /// a list of core brokers that are allowed to connect to the overlay (only valid for an inner (RW/WO) overlay).
3088    // /// an empty list means any core broker is allowed. this is the default behaviour.
3089    // /// to restrict the overlay to only the current core, its DirectPeerId should be entered here.
3090    // /// not compatible with expose_outer
3091    // this is probably going to be a config in the server itself.
3092    // pub allowed_peers: Vec<DirectPeerId>,
3093    /// list of topics that should be subscribed to
3094    /// If the repo has previously been opened (during the same session) then ro_topics info can be omitted
3095    pub ro_topics: Vec<TopicId>,
3096
3097    /// list of topics for which we will be a publisher
3098    /// only possible with inner (RW or WO) overlays.
3099    /// If the repo has previously been opened (during the same session) then rw_topics info can be omitted
3100    pub rw_topics: Vec<PublisherAdvert>,
3101    // TODO pub inbox_proof
3102    // TODO pub signer_proof
3103}
3104
3105/// Request to pin a repo
3106#[derive(Clone, Debug, Serialize, Deserialize)]
3107pub enum PinRepo {
3108    V0(PinRepoV0),
3109}
3110
3111impl PinRepo {
3112    pub fn peers(&self) -> &Vec<PeerAdvert> {
3113        match self {
3114            PinRepo::V0(o) => &o.peers,
3115        }
3116    }
3117    pub fn hash(&self) -> &RepoHash {
3118        match self {
3119            PinRepo::V0(o) => &o.hash,
3120        }
3121    }
3122    pub fn ro_topics(&self) -> &Vec<TopicId> {
3123        match self {
3124            PinRepo::V0(o) => &o.ro_topics,
3125        }
3126    }
3127    pub fn rw_topics(&self) -> &Vec<PublisherAdvert> {
3128        match self {
3129            PinRepo::V0(o) => &o.rw_topics,
3130        }
3131    }
3132    pub fn overlay(&self) -> &OverlayId {
3133        match self {
3134            PinRepo::V0(o) => &o.overlay.overlay_id_for_client_protocol_purpose(),
3135        }
3136    }
3137    pub fn overlay_access(&self) -> &OverlayAccess {
3138        match self {
3139            PinRepo::V0(o) => &o.overlay,
3140        }
3141    }
3142
3143    pub fn overlay_root_topic(&self) -> &Option<TopicId> {
3144        match self {
3145            PinRepo::V0(o) => &o.overlay_root_topic,
3146        }
3147    }
3148
3149    pub fn expose_outer(&self) -> bool {
3150        match self {
3151            PinRepo::V0(o) => o.expose_outer,
3152        }
3153    }
3154}
3155
3156/// Request to refresh the Pinning of a previously pinned repo.
3157///
3158/// it can consist of updating the expose_outer, the list of ro_topics and/or rw_topics,
3159/// and in case of a ban_member, the broker will effectively flush the topics locally after all local members except the banned one, have refreshed
3160#[derive(Clone, Debug, Serialize, Deserialize)]
3161pub struct RefreshPinRepoV0 {
3162    /// The new PinRepo info
3163    pub pin: PinRepo,
3164
3165    /// optional hashed member ID that should be banned
3166    pub ban_member: Option<Digest>,
3167
3168    /// when banning, list of topics that are to be flushed (once all the local members have left, except the one to be banned)
3169    /// All the honest local members have to send this list in order for the banned one to be effectively banned
3170    /// for each Topic, a signature over the hashed UserId to ban, by the Topic private key.
3171    /// The banning process on the broker is meant to flush topics that would remain dangling if the malicious member would not unpin them after being removed from members of repo.
3172    /// The userId of banned user is revealed to the local broker where it was attached, which is a breach of privacy deemed acceptable
3173    /// as only a broker that already knew the userid will enforce it, and
3174    /// that broker might be interested to know that the offending user was banned from a repo, as only malicious users are banned.
3175    /// The broker might also discard this information, and just proceed with the flush without much ado.
3176    /// Of course, if the broker is controlled by the malicious user, it might not proceed with the ban/flush. But who cares. That broker will keep old data forever, but it is a malicious broker anyway.
3177    pub flush_topics: Vec<(TopicId, Sig)>,
3178}
3179
3180/// Request to pin a repo
3181#[derive(Clone, Debug, Serialize, Deserialize)]
3182pub enum RefreshPinRepo {
3183    V0(RefreshPinRepoV0),
3184}
3185
3186/// Request to unpin a repo on the broker.
3187///
3188/// When client will disconnect, the subscriptions and publisherAdvert of the topics will be removed on the broker
3189/// (for that user only. other users might continue to have the repo pinned)
3190
3191#[derive(Clone, Debug, Serialize, Deserialize)]
3192pub struct UnpinRepoV0 {
3193    /// Repo Hash
3194    pub hash: RepoHash,
3195}
3196
3197/// Request to unpin a repo
3198#[derive(Clone, Debug, Serialize, Deserialize)]
3199pub enum UnpinRepo {
3200    V0(UnpinRepoV0),
3201}
3202
3203impl UnpinRepo {
3204    pub fn hash(&self) -> &RepoHash {
3205        match self {
3206            UnpinRepo::V0(o) => &o.hash,
3207        }
3208    }
3209}
3210
3211/// Request the status of pinning for a repo on the broker. V0
3212///
3213/// returns an error code if not pinned, otherwise returns a RepoPinStatusV0
3214/// the overlay entered in ClientMessage is important. if it is the outer, only outer pinning will be checked.
3215/// if it is the inner overlay, only the inner pinning will be checked.
3216#[derive(Clone, Debug, Serialize, Deserialize)]
3217pub struct RepoPinStatusReqV0 {
3218    /// Repo Hash
3219    pub hash: RepoHash,
3220
3221    #[serde(skip)]
3222    pub overlay: Option<OverlayId>,
3223}
3224
3225/// Request the status of pinning for a repo on the broker.
3226#[derive(Clone, Debug, Serialize, Deserialize)]
3227pub enum RepoPinStatusReq {
3228    V0(RepoPinStatusReqV0),
3229}
3230
3231impl RepoPinStatusReq {
3232    pub fn hash(&self) -> &RepoHash {
3233        match self {
3234            RepoPinStatusReq::V0(o) => &o.hash,
3235        }
3236    }
3237    pub fn set_overlay(&mut self, overlay: OverlayId) {
3238        match self {
3239            Self::V0(v0) => v0.overlay = Some(overlay),
3240        }
3241    }
3242
3243    pub fn overlay(&self) -> &OverlayId {
3244        match self {
3245            Self::V0(v0) => v0.overlay.as_ref().unwrap(),
3246        }
3247    }
3248}
3249
3250/// Response with the status of pinning for a repo on the broker. V0
3251#[derive(Clone, Debug, Serialize, Deserialize)]
3252pub struct RepoPinStatusV0 {
3253    /// Repo Hash
3254    pub hash: RepoHash,
3255
3256    /// only possible for RW overlays
3257    pub expose_outer: bool,
3258
3259    /// list of topics that are subscribed to
3260    pub topics: Vec<TopicSubRes>,
3261    // TODO pub inbox_proof
3262
3263    // TODO pub signer_proof
3264}
3265
3266/// Response with the status of pinning for a repo on the broker.
3267#[derive(Clone, Debug, Serialize, Deserialize)]
3268pub enum RepoPinStatus {
3269    V0(RepoPinStatusV0),
3270}
3271
3272impl RepoPinStatus {
3273    pub fn hash(&self) -> &RepoHash {
3274        match self {
3275            RepoPinStatus::V0(o) => &o.hash,
3276        }
3277    }
3278    pub fn is_topic_subscribed_as_publisher(&self, topic: &TopicId) -> bool {
3279        match self {
3280            Self::V0(v0) => {
3281                for sub in &v0.topics {
3282                    if sub.topic_id() == topic {
3283                        return sub.is_publisher();
3284                    }
3285                }
3286                false
3287            }
3288        }
3289    }
3290    pub fn topics(&self) -> &Vec<TopicSubRes> {
3291        match self {
3292            Self::V0(v0) => &v0.topics,
3293        }
3294    }
3295}
3296
3297/// Request subscription to a `Topic` of an already opened or pinned Repo
3298///
3299/// replied with a TopicSubRes containing the current heads that should be used to do a TopicSync
3300#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
3301pub struct TopicSubV0 {
3302    /// Topic to subscribe
3303    pub topic: TopicId,
3304
3305    /// Hash of the repo that was previously opened or pinned
3306    pub repo_hash: RepoHash,
3307
3308    /// Publisher need to provide a signed `PublisherAdvert` for the PeerId of the broker
3309    pub publisher: Option<PublisherAdvert>,
3310
3311    #[serde(skip)]
3312    pub overlay: Option<OverlayId>,
3313}
3314
3315/// Request subscription to a `Topic` of an already opened or pinned Repo
3316#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
3317pub enum TopicSub {
3318    V0(TopicSubV0),
3319}
3320
3321impl TopicSub {
3322    pub fn hash(&self) -> &RepoHash {
3323        match self {
3324            Self::V0(o) => &o.repo_hash,
3325        }
3326    }
3327    pub fn topic(&self) -> &TopicId {
3328        match self {
3329            Self::V0(o) => &o.topic,
3330        }
3331    }
3332    pub fn publisher(&self) -> Option<&PublisherAdvert> {
3333        match self {
3334            Self::V0(o) => o.publisher.as_ref(),
3335        }
3336    }
3337    pub fn set_overlay(&mut self, overlay: OverlayId) {
3338        match self {
3339            Self::V0(v0) => v0.overlay = Some(overlay),
3340        }
3341    }
3342    pub fn overlay(&self) -> &OverlayId {
3343        match self {
3344            Self::V0(v0) => v0.overlay.as_ref().unwrap(),
3345        }
3346    }
3347}
3348
3349/// Request unsubscription from a `Topic` of an already opened or pinned Repo
3350#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
3351pub struct TopicUnsubV0 {
3352    /// Topic to unsubscribe
3353    pub topic: PubKey,
3354
3355    /// Hash of the repo that was previously opened or pinned
3356    pub repo_hash: RepoHash,
3357}
3358
3359/// Request unsubscription from a `Topic` of an already opened or pinned Repo
3360#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
3361pub enum TopicUnsub {
3362    V0(TopicUnsubV0),
3363}
3364
3365/// Request a Block by ID
3366///
3367/// commit_header_key is always set to None in the reply when request is made on OuterOverlay of protected or Group overlays
3368#[derive(Clone, Debug, Serialize, Deserialize)]
3369pub struct BlocksGetV0 {
3370    /// Block IDs to request
3371    pub ids: Vec<BlockId>,
3372
3373    /// Whether or not to include all children recursively
3374    pub include_children: bool,
3375
3376    /// Topic the object is referenced from, if it is known by the requester.
3377    /// can be used to do a BlockSearchTopic in the core overlay.
3378    pub topic: Option<TopicId>,
3379
3380    #[serde(skip)]
3381    pub overlay: Option<OverlayId>,
3382}
3383
3384/// Request an object by ID
3385#[derive(Clone, Debug, Serialize, Deserialize)]
3386pub enum BlocksGet {
3387    V0(BlocksGetV0),
3388}
3389
3390impl BlocksGet {
3391    pub fn ids(&self) -> &Vec<BlockId> {
3392        match self {
3393            BlocksGet::V0(o) => &o.ids,
3394        }
3395    }
3396    pub fn include_children(&self) -> bool {
3397        match self {
3398            BlocksGet::V0(o) => o.include_children,
3399        }
3400    }
3401    pub fn topic(&self) -> Option<PubKey> {
3402        match self {
3403            BlocksGet::V0(o) => o.topic,
3404        }
3405    }
3406}
3407
3408/// Request a Commit by ID
3409///
3410/// commit_header_key is always set to None in the reply when request is made on OuterOverlay of protected or Group overlays
3411/// The difference with BlocksGet is that the Broker will try to return all the commit blocks as they were sent in the Pub/Sub Event, if it has it.
3412/// This will help in having all the blocks (including the header and body blocks), while a BlocksGet would inevitably return only the blocks of the ObjectContent,
3413/// and not the header nor the body. And the load() would fail with CommitLoadError::MissingBlocks. That's what happens when the Commit is not present in the pubsub,
3414/// and we need to default to using BlocksGet instead.
3415#[derive(Clone, Debug, Serialize, Deserialize)]
3416pub struct CommitGetV0 {
3417    /// Commit ID to request
3418    pub id: ObjectId,
3419
3420    /// Topic the commit is referenced from, if it is known by the requester.
3421    /// can be used to do a BlockSearchTopic in the core overlay.
3422    pub topic: Option<TopicId>,
3423
3424    #[serde(skip)]
3425    pub overlay: Option<OverlayId>,
3426}
3427
3428/// Request a Commit by ID (see [CommitGetV0] for more details)
3429#[derive(Clone, Debug, Serialize, Deserialize)]
3430pub enum CommitGet {
3431    V0(CommitGetV0),
3432}
3433impl CommitGet {
3434    pub fn id(&self) -> &ObjectId {
3435        match self {
3436            CommitGet::V0(o) => &o.id,
3437        }
3438    }
3439}
3440
3441/// Request to store one or more blocks
3442#[derive(Clone, Debug, Serialize, Deserialize)]
3443pub struct WalletPutExportV0 {
3444    pub wallet: ExportedWallet,
3445    pub rendezvous_id: SymKey,
3446    pub is_rendezvous: bool,
3447}
3448
3449/// Request to store one or more blocks
3450#[derive(Clone, Debug, Serialize, Deserialize)]
3451pub enum WalletPutExport {
3452    V0(WalletPutExportV0),
3453}
3454
3455/// Request to store one or more blocks
3456#[derive(Clone, Debug, Serialize, Deserialize)]
3457pub struct BlocksPutV0 {
3458    /// Blocks to store
3459    pub blocks: Vec<Block>,
3460
3461    #[serde(skip)]
3462    pub overlay: Option<OverlayId>,
3463}
3464
3465/// Request to store one or more blocks
3466#[derive(Clone, Debug, Serialize, Deserialize)]
3467pub enum BlocksPut {
3468    V0(BlocksPutV0),
3469}
3470
3471impl BlocksPut {
3472    pub fn blocks(&self) -> &Vec<Block> {
3473        match self {
3474            BlocksPut::V0(o) => &o.blocks,
3475        }
3476    }
3477    pub fn overlay(&self) -> &OverlayId {
3478        match self {
3479            Self::V0(v0) => v0.overlay.as_ref().unwrap(),
3480        }
3481    }
3482    pub fn set_overlay(&mut self, overlay: OverlayId) {
3483        match self {
3484            Self::V0(v0) => v0.overlay = Some(overlay),
3485        }
3486    }
3487}
3488
3489/// Request to know if some blocks are present locally
3490///
3491/// used by client before publishing an event with files, to know what to push
3492#[derive(Clone, Debug, Serialize, Deserialize)]
3493pub struct BlocksExistV0 {
3494    /// Ids of Blocks to check
3495    pub blocks: Vec<BlockId>,
3496
3497    #[serde(skip)]
3498    pub overlay: Option<OverlayId>,
3499}
3500
3501/// Request to store one or more blocks
3502#[derive(Clone, Debug, Serialize, Deserialize)]
3503pub enum BlocksExist {
3504    V0(BlocksExistV0),
3505}
3506
3507impl BlocksExist {
3508    pub fn blocks(&self) -> &Vec<BlockId> {
3509        match self {
3510            BlocksExist::V0(o) => &o.blocks,
3511        }
3512    }
3513    pub fn overlay(&self) -> &OverlayId {
3514        match self {
3515            Self::V0(v0) => v0.overlay.as_ref().unwrap(),
3516        }
3517    }
3518    pub fn set_overlay(&mut self, overlay: OverlayId) {
3519        match self {
3520            Self::V0(v0) => v0.overlay = Some(overlay),
3521        }
3522    }
3523}
3524
3525/// Request to pin an object
3526///
3527/// Brokers maintain an LRU cache of objects,
3528/// where old, unused objects might get deleted to free up space for new ones.
3529/// Pinned objects are retained, regardless of last access.
3530#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
3531pub struct ObjectPinV0 {
3532    pub id: ObjectId,
3533}
3534
3535/// Request to pin an object
3536#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
3537pub enum ObjectPin {
3538    V0(ObjectPinV0),
3539}
3540
3541impl ObjectPin {
3542    pub fn id(&self) -> ObjectId {
3543        match self {
3544            ObjectPin::V0(o) => o.id,
3545        }
3546    }
3547}
3548
3549/// Request to unpin an object
3550#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
3551pub struct ObjectUnpinV0 {
3552    pub id: ObjectId,
3553}
3554
3555/// Request to unpin an object
3556#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
3557pub enum ObjectUnpin {
3558    V0(ObjectUnpinV0),
3559}
3560
3561impl ObjectUnpin {
3562    pub fn id(&self) -> ObjectId {
3563        match self {
3564            ObjectUnpin::V0(o) => o.id,
3565        }
3566    }
3567}
3568
3569/// Request to delete an object
3570///
3571/// only effective if the refcount for this object is zero (basically it removes it from LRU)
3572#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
3573pub struct ObjectDelV0 {
3574    pub id: ObjectId,
3575}
3576
3577/// Request to delete an object
3578#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
3579pub enum ObjectDel {
3580    V0(ObjectDelV0),
3581}
3582
3583impl ObjectDel {
3584    pub fn id(&self) -> ObjectId {
3585        match self {
3586            ObjectDel::V0(o) => o.id,
3587        }
3588    }
3589}
3590
3591/// Request to publish an event in pubsub
3592#[derive(Clone, Debug, Serialize, Deserialize)]
3593pub struct PublishEvent(pub Event, #[serde(skip)] pub Option<OverlayId>);
3594
3595/// Content of `ClientRequestV0`
3596#[derive(Clone, Debug, Serialize, Deserialize)]
3597pub enum ClientRequestContentV0 {
3598    OpenRepo(OpenRepo),
3599    PinRepo(PinRepo),
3600    UnpinRepo(UnpinRepo),
3601    RepoPinStatusReq(RepoPinStatusReq),
3602
3603    // once repo is opened or pinned:
3604    TopicSub(TopicSub),
3605    TopicUnsub(TopicUnsub),
3606
3607    BlocksExist(BlocksExist),
3608    BlocksGet(BlocksGet),
3609    CommitGet(CommitGet),
3610    TopicSyncReq(TopicSyncReq),
3611
3612    // For Pinned Repos only :
3613    ObjectPin(ObjectPin),
3614    ObjectUnpin(ObjectUnpin),
3615    ObjectDel(ObjectDel),
3616
3617    // For InnerOverlay's only :
3618    BlocksPut(BlocksPut),
3619    PublishEvent(PublishEvent),
3620
3621    WalletPutExport(WalletPutExport),
3622}
3623
3624impl ClientRequestContentV0 {
3625    pub fn set_overlay(&mut self, overlay: OverlayId) {
3626        match self {
3627            ClientRequestContentV0::RepoPinStatusReq(a) => a.set_overlay(overlay),
3628            ClientRequestContentV0::TopicSub(a) => a.set_overlay(overlay),
3629            ClientRequestContentV0::PinRepo(_a) => {}
3630            ClientRequestContentV0::PublishEvent(a) => a.set_overlay(overlay),
3631            ClientRequestContentV0::CommitGet(a) => a.set_overlay(overlay),
3632            ClientRequestContentV0::TopicSyncReq(a) => a.set_overlay(overlay),
3633            ClientRequestContentV0::BlocksPut(a) => a.set_overlay(overlay),
3634            ClientRequestContentV0::BlocksExist(a) => a.set_overlay(overlay),
3635            ClientRequestContentV0::BlocksGet(a) => a.set_overlay(overlay),
3636            ClientRequestContentV0::WalletPutExport(_a) => {}
3637            _ => unimplemented!(),
3638        }
3639    }
3640}
3641
3642/// Broker overlay request
3643#[derive(Clone, Debug, Serialize, Deserialize)]
3644pub struct ClientRequestV0 {
3645    /// Request ID
3646    pub id: i64,
3647
3648    /// Request content
3649    pub content: ClientRequestContentV0,
3650}
3651
3652/// Broker overlay request
3653#[derive(Clone, Debug, Serialize, Deserialize)]
3654pub enum ClientRequest {
3655    V0(ClientRequestV0),
3656}
3657
3658impl ClientRequest {
3659    pub fn id(&self) -> i64 {
3660        match self {
3661            ClientRequest::V0(o) => o.id,
3662        }
3663    }
3664    pub fn set_id(&mut self, id: i64) {
3665        match self {
3666            ClientRequest::V0(v0) => {
3667                v0.id = id;
3668            }
3669        }
3670    }
3671    pub fn content_v0(&self) -> &ClientRequestContentV0 {
3672        match self {
3673            ClientRequest::V0(o) => &o.content,
3674        }
3675    }
3676    pub fn get_actor(&self) -> Box<dyn EActor> {
3677        match self {
3678            Self::V0(ClientRequestV0 { content, .. }) => match content {
3679                ClientRequestContentV0::RepoPinStatusReq(r) => r.get_actor(self.id()),
3680                ClientRequestContentV0::PinRepo(r) => r.get_actor(self.id()),
3681                ClientRequestContentV0::TopicSub(r) => r.get_actor(self.id()),
3682                ClientRequestContentV0::PublishEvent(r) => r.get_actor(self.id()),
3683                ClientRequestContentV0::CommitGet(r) => r.get_actor(self.id()),
3684                ClientRequestContentV0::TopicSyncReq(r) => r.get_actor(self.id()),
3685                ClientRequestContentV0::BlocksPut(r) => r.get_actor(self.id()),
3686                ClientRequestContentV0::BlocksExist(r) => r.get_actor(self.id()),
3687                ClientRequestContentV0::BlocksGet(r) => r.get_actor(self.id()),
3688                ClientRequestContentV0::WalletPutExport(r) => r.get_actor(self.id()),
3689                _ => unimplemented!(),
3690            },
3691        }
3692    }
3693}
3694
3695impl TryFrom<ProtocolMessage> for ClientRequestContentV0 {
3696    type Error = ProtocolError;
3697    fn try_from(msg: ProtocolMessage) -> Result<Self, Self::Error> {
3698        if let ProtocolMessage::ClientMessage(ClientMessage::V0(ClientMessageV0 {
3699            overlay,
3700            content:
3701                ClientMessageContentV0::ClientRequest(ClientRequest::V0(ClientRequestV0 {
3702                    mut content,
3703                    ..
3704                })),
3705            ..
3706        })) = msg
3707        {
3708            content.set_overlay(overlay);
3709            Ok(content)
3710        } else {
3711            log_debug!("INVALID {:?}", msg);
3712            Err(ProtocolError::InvalidValue)
3713        }
3714    }
3715}
3716
3717/// Response which blocks have been found locally. V0
3718#[derive(Clone, Debug, Serialize, Deserialize)]
3719pub struct BlocksFoundV0 {
3720    /// Ids of Blocks that were found locally
3721    pub found: Vec<BlockId>,
3722
3723    /// Ids of Blocks that were missing locally
3724    pub missing: Vec<BlockId>,
3725}
3726
3727/// Response which blocks have been found locally.
3728#[derive(Clone, Debug, Serialize, Deserialize)]
3729pub enum BlocksFound {
3730    V0(BlocksFoundV0),
3731}
3732
3733impl BlocksFound {
3734    pub fn found(&self) -> &Vec<BlockId> {
3735        match self {
3736            BlocksFound::V0(o) => &o.found,
3737        }
3738    }
3739    pub fn missing(&self) -> &Vec<BlockId> {
3740        match self {
3741            BlocksFound::V0(o) => &o.missing,
3742        }
3743    }
3744}
3745
3746/// Topic subscription response V0
3747#[derive(Clone, Debug, Serialize, Deserialize)]
3748pub struct TopicSubResV0 {
3749    /// Topic subscribed
3750    pub topic: TopicId,
3751    pub known_heads: Vec<ObjectId>,
3752    pub publisher: bool,
3753    pub commits_nbr: u64,
3754}
3755
3756/// Topic subscription response
3757///
3758/// it is a stream of blocks and or events.
3759#[derive(Clone, Debug, Serialize, Deserialize)]
3760pub enum TopicSubRes {
3761    V0(TopicSubResV0),
3762}
3763
3764impl TopicSubRes {
3765    pub fn topic_id(&self) -> &TopicId {
3766        match self {
3767            Self::V0(v0) => &v0.topic,
3768        }
3769    }
3770    pub fn is_publisher(&self) -> bool {
3771        match self {
3772            Self::V0(v0) => v0.publisher,
3773        }
3774    }
3775    pub fn new_from_heads(
3776        topics: HashSet<ObjectId>,
3777        publisher: bool,
3778        topic: TopicId,
3779        commits_nbr: u64,
3780    ) -> Self {
3781        TopicSubRes::V0(TopicSubResV0 {
3782            topic,
3783            known_heads: topics.into_iter().collect(),
3784            publisher,
3785            commits_nbr,
3786        })
3787    }
3788    pub fn known_heads(&self) -> &Vec<ObjectId> {
3789        match self {
3790            Self::V0(v0) => &v0.known_heads,
3791        }
3792    }
3793    pub fn commits_nbr(&self) -> u64 {
3794        match self {
3795            Self::V0(v0) => v0.commits_nbr,
3796        }
3797    }
3798}
3799
3800impl From<TopicId> for TopicSubRes {
3801    fn from(topic: TopicId) -> Self {
3802        TopicSubRes::V0(TopicSubResV0 {
3803            topic,
3804            known_heads: vec![],
3805            publisher: false,
3806            commits_nbr: 0,
3807        })
3808    }
3809}
3810
3811impl From<PublisherAdvert> for TopicSubRes {
3812    fn from(topic: PublisherAdvert) -> Self {
3813        TopicSubRes::V0(TopicSubResV0 {
3814            topic: topic.topic_id().clone(),
3815            known_heads: vec![],
3816            publisher: true,
3817            commits_nbr: 0,
3818        })
3819    }
3820}
3821
3822pub type RepoOpened = Vec<TopicSubRes>;
3823
3824/// Content of `ClientResponseV0`
3825#[derive(Clone, Debug, Serialize, Deserialize)]
3826pub enum ClientResponseContentV0 {
3827    EmptyResponse,
3828    Block(Block),
3829    RepoOpened(RepoOpened),
3830    TopicSubRes(TopicSubRes),
3831    TopicSyncRes(TopicSyncRes),
3832    BlocksFound(BlocksFound),
3833    RepoPinStatus(RepoPinStatus),
3834}
3835
3836/// Response to a `ClientRequest`
3837#[derive(Clone, Debug, Serialize, Deserialize)]
3838pub struct ClientResponseV0 {
3839    /// Request ID
3840    pub id: i64,
3841
3842    /// Result (including but not limited to Result)
3843    pub result: u16,
3844
3845    /// Response content
3846    pub content: ClientResponseContentV0,
3847}
3848
3849impl ClientResponse {
3850    pub fn set_result(&mut self, res: u16) {
3851        match self {
3852            Self::V0(v0) => v0.result = res,
3853        }
3854    }
3855}
3856
3857/// Response to a `ClientRequest`
3858#[derive(Clone, Debug, Serialize, Deserialize)]
3859pub enum ClientResponse {
3860    V0(ClientResponseV0),
3861}
3862
3863impl From<ServerError> for ClientResponse {
3864    fn from(err: ServerError) -> ClientResponse {
3865        ClientResponse::V0(ClientResponseV0 {
3866            id: 0,
3867            result: err.into(),
3868            content: ClientResponseContentV0::EmptyResponse,
3869        })
3870    }
3871}
3872
3873#[derive(Debug)]
3874pub struct EmptyAppResponse(pub ());
3875
3876impl From<ServerError> for AppMessage {
3877    fn from(err: ServerError) -> AppMessage {
3878        AppMessage::V0(AppMessageV0 {
3879            id: 0,
3880            result: err.into(),
3881            content: AppMessageContentV0::EmptyResponse,
3882        })
3883    }
3884}
3885
3886impl<A> From<Result<A, ServerError>> for ProtocolMessage
3887where
3888    A: Into<ProtocolMessage> + std::fmt::Debug,
3889{
3890    fn from(res: Result<A, ServerError>) -> ProtocolMessage {
3891        match res {
3892            Ok(a) => a.into(),
3893            Err(e) => ProtocolMessage::from_client_response_err(e),
3894        }
3895    }
3896}
3897
3898impl From<()> for ProtocolMessage {
3899    fn from(_msg: ()) -> ProtocolMessage {
3900        let cm: ClientResponse = ServerError::Ok.into();
3901        cm.into()
3902    }
3903}
3904
3905impl ClientResponse {
3906    pub fn id(&self) -> i64 {
3907        match self {
3908            ClientResponse::V0(o) => o.id,
3909        }
3910    }
3911    pub fn set_id(&mut self, id: i64) {
3912        match self {
3913            ClientResponse::V0(v0) => {
3914                v0.id = id;
3915            }
3916        }
3917    }
3918    pub fn result(&self) -> u16 {
3919        match self {
3920            ClientResponse::V0(o) => o.result,
3921        }
3922    }
3923    pub fn block(&self) -> Option<&Block> {
3924        match self {
3925            ClientResponse::V0(o) => match &o.content {
3926                ClientResponseContentV0::Block(b) => Some(b),
3927                _ => panic!("this not a block response"),
3928            },
3929        }
3930    }
3931}
3932
3933impl TryFrom<ProtocolMessage> for ClientResponseContentV0 {
3934    type Error = ProtocolError;
3935    fn try_from(msg: ProtocolMessage) -> Result<Self, Self::Error> {
3936        if let ProtocolMessage::ClientMessage(ClientMessage::V0(ClientMessageV0 {
3937            content:
3938                ClientMessageContentV0::ClientResponse(ClientResponse::V0(ClientResponseV0 {
3939                    content,
3940                    result: res,
3941                    ..
3942                })),
3943            ..
3944        })) = msg
3945        {
3946            let err = ServerError::try_from(res).unwrap();
3947            if !err.is_err() {
3948                Ok(content)
3949            } else {
3950                Err(ProtocolError::ServerError)
3951            }
3952        } else {
3953            log_debug!("INVALID {:?}", msg);
3954            Err(ProtocolError::InvalidValue)
3955        }
3956    }
3957}
3958
3959/// Content of `ClientMessageV0`
3960#[derive(Clone, Debug, Serialize, Deserialize)]
3961pub enum ClientMessageContentV0 {
3962    ClientRequest(ClientRequest),
3963    ClientResponse(ClientResponse),
3964    ForwardedEvent(Event),
3965    ForwardedBlock(Block),
3966}
3967impl ClientMessageContentV0 {
3968    pub fn is_block(&self) -> bool {
3969        match self {
3970            Self::ClientRequest(ClientRequest::V0(ClientRequestV0 {
3971                content: ClientRequestContentV0::BlocksPut(_),
3972                ..
3973            })) => true,
3974            Self::ClientResponse(ClientResponse::V0(ClientResponseV0 {
3975                content: ClientResponseContentV0::Block(_),
3976                ..
3977            })) => true,
3978            _ => false,
3979        }
3980    }
3981}
3982
3983/// Broker message for an overlay
3984#[derive(Clone, Debug, Serialize, Deserialize)]
3985pub struct ClientMessageV0 {
3986    pub overlay: OverlayId,
3987    pub content: ClientMessageContentV0,
3988    /// Optional padding
3989    #[serde(with = "serde_bytes")]
3990    pub padding: Vec<u8>,
3991}
3992
3993pub trait IStreamable {
3994    fn result(&self) -> u16;
3995    fn set_result(&mut self, result: u16);
3996}
3997
3998/// Broker message for an overlay
3999#[derive(Clone, Debug, Serialize, Deserialize)]
4000pub enum ClientMessage {
4001    V0(ClientMessageV0),
4002}
4003
4004impl IStreamable for ClientMessage {
4005    fn result(&self) -> u16 {
4006        match self {
4007            ClientMessage::V0(o) => match &o.content {
4008                ClientMessageContentV0::ClientResponse(r) => r.result(),
4009                ClientMessageContentV0::ClientRequest(_)
4010                | ClientMessageContentV0::ForwardedEvent(_)
4011                | ClientMessageContentV0::ForwardedBlock(_) => {
4012                    panic!("it is not a response");
4013                }
4014            },
4015        }
4016    }
4017    fn set_result(&mut self, result: u16) {
4018        match self {
4019            ClientMessage::V0(o) => match &mut o.content {
4020                ClientMessageContentV0::ClientResponse(r) => r.set_result(result),
4021                ClientMessageContentV0::ClientRequest(_)
4022                | ClientMessageContentV0::ForwardedEvent(_)
4023                | ClientMessageContentV0::ForwardedBlock(_) => {
4024                    panic!("it is not a response");
4025                }
4026            },
4027        }
4028    }
4029}
4030
4031impl ClientMessage {
4032    pub fn content_v0(&self) -> &ClientMessageContentV0 {
4033        match self {
4034            ClientMessage::V0(o) => &o.content,
4035        }
4036    }
4037    pub fn overlay_request(&self) -> &ClientRequest {
4038        match self {
4039            ClientMessage::V0(o) => match &o.content {
4040                ClientMessageContentV0::ClientRequest(r) => &r,
4041                _ => panic!("not an overlay request"),
4042            },
4043        }
4044    }
4045
4046    pub fn forwarded_event(self) -> Option<(Event, OverlayId)> {
4047        let overlay = self.overlay_id();
4048        match self {
4049            ClientMessage::V0(o) => match o.content {
4050                ClientMessageContentV0::ForwardedEvent(e) => Some((e, overlay)),
4051                _ => None,
4052            },
4053        }
4054    }
4055    pub fn overlay_id(&self) -> OverlayId {
4056        match self {
4057            ClientMessage::V0(o) => o.overlay,
4058        }
4059    }
4060    pub fn is_request(&self) -> bool {
4061        match self {
4062            ClientMessage::V0(o) => {
4063                matches!(o.content, ClientMessageContentV0::ClientRequest { .. })
4064            }
4065        }
4066    }
4067    pub fn is_response(&self) -> bool {
4068        match self {
4069            ClientMessage::V0(o) => {
4070                matches!(o.content, ClientMessageContentV0::ClientResponse { .. })
4071            }
4072        }
4073    }
4074    pub fn id(&self) -> Option<i64> {
4075        match self {
4076            ClientMessage::V0(o) => match &o.content {
4077                ClientMessageContentV0::ClientResponse(r) => Some(r.id()),
4078                ClientMessageContentV0::ClientRequest(r) => Some(r.id()),
4079                ClientMessageContentV0::ForwardedEvent(_)
4080                | ClientMessageContentV0::ForwardedBlock(_) => None,
4081            },
4082        }
4083    }
4084    pub fn set_id(&mut self, id: i64) {
4085        match self {
4086            ClientMessage::V0(o) => match &mut o.content {
4087                ClientMessageContentV0::ClientResponse(ref mut r) => r.set_id(id),
4088                ClientMessageContentV0::ClientRequest(ref mut r) => r.set_id(id),
4089                ClientMessageContentV0::ForwardedEvent(_)
4090                | ClientMessageContentV0::ForwardedBlock(_) => {
4091                    panic!("it is an event")
4092                }
4093            },
4094        }
4095    }
4096
4097    pub fn block<'a>(&self) -> Option<&Block> {
4098        match self {
4099            ClientMessage::V0(o) => match &o.content {
4100                ClientMessageContentV0::ClientResponse(r) => r.block(),
4101                ClientMessageContentV0::ClientRequest(_)
4102                | ClientMessageContentV0::ForwardedEvent(_)
4103                | ClientMessageContentV0::ForwardedBlock(_) => {
4104                    panic!("it is not a response");
4105                }
4106            },
4107        }
4108    }
4109
4110    pub fn get_actor(&self) -> Box<dyn EActor> {
4111        match self {
4112            ClientMessage::V0(o) => match &o.content {
4113                ClientMessageContentV0::ClientRequest(req) => req.get_actor(),
4114                ClientMessageContentV0::ClientResponse(_)
4115                | ClientMessageContentV0::ForwardedEvent(_)
4116                | ClientMessageContentV0::ForwardedBlock(_) => {
4117                    panic!("it is not a request");
4118                }
4119            },
4120        }
4121    }
4122}
4123
4124//
4125// EXTERNAL REQUESTS
4126//
4127
4128/// Request object(s) by ID by non-members to a broker
4129///
4130/// The response includes the requested objects and all their children recursively,
4131/// and optionally all file object dependencies and their children recursively.
4132#[derive(Clone, Debug, Serialize, Deserialize)]
4133pub struct ExtObjectGetV0 {
4134    /// outer overlayId
4135    pub overlay: OverlayId,
4136
4137    /// List of Object IDs to request, including their children
4138    pub ids: Vec<ObjectId>,
4139
4140    /// Whether or not to include all files objects
4141    pub include_files: bool,
4142}
4143
4144/// Request object(s) by ID by non-members
4145#[derive(Clone, Debug, Serialize, Deserialize)]
4146pub enum ExtObjectGet {
4147    V0(ExtObjectGetV0),
4148}
4149
4150#[derive(Clone, Debug, Serialize, Deserialize)]
4151pub struct ExtWalletGetExportV0 {
4152    pub id: SymKey,
4153    pub is_rendezvous: bool,
4154}
4155
4156/// Topic synchronization request
4157pub type ExtTopicSyncReq = TopicSyncReq;
4158
4159/// Content of ExtRequestV0
4160#[derive(Clone, Debug, Serialize, Deserialize)]
4161pub enum ExtRequestContentV0 {
4162    WalletGetExport(ExtWalletGetExportV0),
4163    ExtObjectGet(ExtObjectGetV0),
4164    ExtTopicSyncReq(ExtTopicSyncReq),
4165    // TODO inbox requests
4166    // TODO subreq ?
4167}
4168
4169impl ExtRequestContentV0 {
4170    pub fn get_actor(&self) -> Box<dyn EActor> {
4171        match self {
4172            Self::WalletGetExport(a) => a.get_actor(),
4173            Self::ExtObjectGet(a) => a.get_actor(),
4174            _ => unimplemented!(), // Self::ExtTopicSyncReq(a) => a.get_actor(),
4175        }
4176    }
4177}
4178
4179/// External request with its request ID
4180#[derive(Clone, Debug, Serialize, Deserialize)]
4181pub struct ExtRequestV0 {
4182    /// Request ID
4183    pub id: i64,
4184
4185    /// Request content
4186    pub content: ExtRequestContentV0,
4187}
4188
4189/// External request are made by clients directly to a core broker of their choice.
4190///
4191/// They differ from OuterOverlayRequests in the sense that the broker where the client is attached, is not involved in the request.
4192/// It is a direct connection that is established between the client and the core broker that will give the response.
4193#[derive(Clone, Debug, Serialize, Deserialize)]
4194pub enum ExtRequest {
4195    V0(ExtRequestV0),
4196}
4197
4198impl ExtRequest {
4199    pub fn id(&self) -> i64 {
4200        match self {
4201            ExtRequest::V0(v0) => v0.id,
4202        }
4203    }
4204    pub fn set_id(&mut self, id: i64) {
4205        match self {
4206            ExtRequest::V0(v0) => {
4207                v0.id = id;
4208            }
4209        }
4210    }
4211    pub fn get_actor(&self) -> Box<dyn EActor> {
4212        match self {
4213            Self::V0(a) => a.content.get_actor(),
4214        }
4215    }
4216}
4217
4218#[derive(Clone, Debug, Serialize, Deserialize)]
4219pub struct ExportedWallet(pub serde_bytes::ByteBuf);
4220
4221/// Content of ExtResponseV0
4222#[derive(Clone, Debug, Serialize, Deserialize)]
4223pub enum ExtResponseContentV0 {
4224    EmptyResponse,
4225    Block(Block),
4226    Blocks(Vec<Block>),
4227    Wallet(ExportedWallet),
4228    // TODO  inbox related replies
4229    // TODO event ?
4230}
4231
4232impl TryFrom<ProtocolMessage> for ExtResponseContentV0 {
4233    type Error = ProtocolError;
4234    fn try_from(msg: ProtocolMessage) -> Result<Self, Self::Error> {
4235        if let ProtocolMessage::ExtResponse(ExtResponse::V0(ExtResponseV0 {
4236            content,
4237            result,
4238            ..
4239        })) = msg
4240        {
4241            let err = ServerError::try_from(result).unwrap();
4242            if !err.is_err() {
4243                Ok(content)
4244            } else {
4245                Err(ProtocolError::ServerError)
4246            }
4247        } else {
4248            log_debug!("INVALID {:?}", msg);
4249            Err(ProtocolError::InvalidValue)
4250        }
4251    }
4252}
4253
4254/// Response to an ExtRequest
4255#[derive(Clone, Debug, Serialize, Deserialize)]
4256pub struct ExtResponseV0 {
4257    /// Request ID
4258    pub id: i64,
4259
4260    /// Result code
4261    pub result: u16,
4262
4263    /// Response content
4264    pub content: ExtResponseContentV0,
4265}
4266
4267/// Response to an ExtRequest
4268#[derive(Clone, Debug, Serialize, Deserialize)]
4269pub enum ExtResponse {
4270    V0(ExtResponseV0),
4271}
4272
4273impl ExtResponse {
4274    pub fn id(&self) -> i64 {
4275        match self {
4276            ExtResponse::V0(v0) => v0.id,
4277        }
4278    }
4279    pub fn set_id(&mut self, id: i64) {
4280        match self {
4281            ExtResponse::V0(v0) => {
4282                v0.id = id;
4283            }
4284        }
4285    }
4286    pub fn result(&self) -> u16 {
4287        match self {
4288            Self::V0(o) => o.result,
4289        }
4290    }
4291    pub fn content_v0(&self) -> ExtResponseContentV0 {
4292        match self {
4293            Self::V0(o) => o.content.clone(),
4294        }
4295    }
4296}
4297
4298impl TryFrom<ProtocolMessage> for ExtResponse {
4299    type Error = ProtocolError;
4300    fn try_from(msg: ProtocolMessage) -> Result<Self, Self::Error> {
4301        if let ProtocolMessage::ExtResponse(ext_res) = msg {
4302            Ok(ext_res)
4303        } else {
4304            Err(ProtocolError::InvalidValue)
4305        }
4306    }
4307}
4308
4309impl From<Result<ExtResponseContentV0, ServerError>> for ExtResponseV0 {
4310    fn from(res: Result<ExtResponseContentV0, ServerError>) -> ExtResponseV0 {
4311        match res {
4312            Err(e) => ExtResponseV0 {
4313                id: 0,
4314                result: e.into(),
4315                content: ExtResponseContentV0::EmptyResponse,
4316            },
4317            Ok(content) => ExtResponseV0 {
4318                id: 0,
4319                result: 0,
4320                content,
4321            },
4322        }
4323    }
4324}
4325
4326impl From<ExtResponseV0> for ProtocolMessage {
4327    fn from(msg: ExtResponseV0) -> ProtocolMessage {
4328        ProtocolMessage::ExtResponse(ExtResponse::V0(msg))
4329    }
4330}
4331
4332//
4333// PROTOCOL MESSAGES
4334//
4335#[doc(hidden)]
4336pub static MAGIC_NG_REQUEST: [u8; 2] = [78u8, 71u8];
4337#[doc(hidden)]
4338pub static MAGIC_NG_RESPONSE: [u8; 4] = [89u8, 88u8, 78u8, 75u8];
4339
4340#[derive(Clone, Debug)]
4341pub enum Authorization {
4342    Discover,
4343    ExtMessage,
4344    Core,
4345    Client((PubKey, Option<Option<[u8; 32]>>)),
4346    OverlayJoin(PubKey),
4347    Admin(PubKey),
4348}
4349
4350/// ProbeResponse
4351#[derive(Clone, Debug, Serialize, Deserialize)]
4352pub struct ProbeResponse {
4353    /// Response Magic number
4354    #[serde(with = "serde_bytes")]
4355    pub magic: Vec<u8>,
4356
4357    /// Used for discovery of broker on private LAN
4358    /// see ListenerV0.discoverable
4359    pub peer_id: Option<PubKey>,
4360}
4361
4362/// RelayRequest
4363#[derive(Clone, Debug, Serialize, Deserialize)]
4364pub struct RelayRequest {
4365    /// The BindAddress of the broker to relay to should be of the same IP family than the TunnelRequest.remote_addr
4366    pub address: BindAddress,
4367}
4368
4369/// RelayResponse
4370#[derive(Clone, Debug, Serialize, Deserialize)]
4371pub struct RelayResponse {
4372    /// Response Magic number
4373    #[serde(with = "serde_bytes")]
4374    pub magic: Vec<u8>,
4375
4376    /// result to the relay request (accept, refuse)
4377    pub result: u16,
4378}
4379
4380/// Tunnel Request
4381#[derive(Clone, Debug, Serialize, Deserialize)]
4382pub struct TunnelRequest {
4383    /// Request Magic number
4384    #[serde(with = "serde_bytes")]
4385    pub magic: Vec<u8>,
4386
4387    // Bind address of client as connected to the relaying broker.
4388    pub remote_addr: BindAddress,
4389}
4390
4391/// Tunnel Response
4392#[derive(Clone, Debug, Serialize, Deserialize)]
4393pub struct TunnelResponse {
4394    /// Response Magic number
4395    #[serde(with = "serde_bytes")]
4396    pub magic: Vec<u8>,
4397
4398    /// result to the tunnel request (accept, refuse)
4399    pub result: u16,
4400}
4401
4402#[derive(Clone, Debug, Serialize, Deserialize)]
4403pub enum ProtocolMessage {
4404    Probe([u8; 2]),
4405    ProbeResponse(ProbeResponse),
4406    Relay(RelayRequest),
4407    RelayResponse(RelayResponse),
4408    Tunnel(TunnelRequest),
4409    TunnelResponse(TunnelResponse),
4410    Noise(Noise),
4411    Start(StartProtocol),
4412    ServerHello(ServerHello),
4413    ClientAuth(ClientAuth),
4414    AuthResult(AuthResult),
4415    ExtRequest(ExtRequest),
4416    ExtResponse(ExtResponse),
4417    //AdminRequest(AdminRequest),
4418    AdminResponse(AdminResponse),
4419    ClientMessage(ClientMessage),
4420    AppMessage(AppMessage),
4421    CoreMessage(CoreMessage),
4422}
4423
4424impl TryFrom<&ProtocolMessage> for ServerError {
4425    type Error = NgError;
4426    fn try_from(msg: &ProtocolMessage) -> Result<Self, NgError> {
4427        if let ProtocolMessage::ClientMessage(ref bm) = msg {
4428            let res = bm.result();
4429            if res != 0 {
4430                return Ok(ServerError::try_from(res).unwrap());
4431            }
4432        }
4433        if let ProtocolMessage::ExtResponse(ref bm) = msg {
4434            let res = bm.result();
4435            if res != 0 {
4436                return Ok(ServerError::try_from(res).unwrap());
4437            }
4438        }
4439        if let ProtocolMessage::AppMessage(ref bm) = msg {
4440            let res = bm.result();
4441            if res != 0 {
4442                return Ok(ServerError::try_from(res).unwrap());
4443            }
4444        }
4445        Err(NgError::NotAServerError)
4446    }
4447}
4448
4449impl ProtocolMessage {
4450    pub fn id(&self) -> Option<i64> {
4451        match self {
4452            ProtocolMessage::ExtRequest(ext_req) => Some(ext_req.id()),
4453            ProtocolMessage::ExtResponse(ext_res) => Some(ext_res.id()),
4454            ProtocolMessage::ClientMessage(client_msg) => client_msg.id(),
4455            ProtocolMessage::AppMessage(app_msg) => app_msg.id(),
4456            _ => None,
4457        }
4458    }
4459    pub fn set_id(&mut self, id: i64) {
4460        match self {
4461            ProtocolMessage::ExtRequest(ext_req) => ext_req.set_id(id),
4462            ProtocolMessage::ExtResponse(ext_res) => ext_res.set_id(id),
4463            ProtocolMessage::ClientMessage(client_msg) => client_msg.set_id(id),
4464            ProtocolMessage::AppMessage(app_msg) => app_msg.set_id(id),
4465            _ => panic!("cannot set ID"),
4466        }
4467    }
4468    pub fn type_id(&self) -> TypeId {
4469        match self {
4470            ProtocolMessage::Noise(a) => a.type_id(),
4471            ProtocolMessage::Start(a) => a.type_id(),
4472            ProtocolMessage::ServerHello(a) => a.type_id(),
4473            ProtocolMessage::ClientAuth(a) => a.type_id(),
4474            ProtocolMessage::AuthResult(a) => a.type_id(),
4475            ProtocolMessage::ExtRequest(a) => a.type_id(),
4476            ProtocolMessage::ExtResponse(a) => a.type_id(),
4477            ProtocolMessage::ClientMessage(a) => a.type_id(),
4478            ProtocolMessage::CoreMessage(a) => a.type_id(),
4479            ProtocolMessage::AppMessage(a) => a.type_id(),
4480            //ProtocolMessage::AdminRequest(a) => a.type_id(),
4481            ProtocolMessage::AdminResponse(a) => a.type_id(),
4482            ProtocolMessage::Probe(a) => a.type_id(),
4483            ProtocolMessage::ProbeResponse(a) => a.type_id(),
4484            ProtocolMessage::Relay(a) => a.type_id(),
4485            ProtocolMessage::RelayResponse(a) => a.type_id(),
4486            ProtocolMessage::Tunnel(a) => a.type_id(),
4487            ProtocolMessage::TunnelResponse(a) => a.type_id(),
4488        }
4489    }
4490
4491    pub(crate) fn is_streamable(&self) -> Option<&dyn IStreamable> {
4492        match self {
4493            ProtocolMessage::ClientMessage(s) => Some(s as &dyn IStreamable),
4494            ProtocolMessage::AppMessage(s) => Some(s as &dyn IStreamable),
4495            _ => None,
4496        }
4497    }
4498
4499    pub fn get_actor(&self) -> Box<dyn EActor> {
4500        match self {
4501            //ProtocolMessage::Noise(a) => a.get_actor(),
4502            ProtocolMessage::Start(a) => a.get_actor(),
4503            ProtocolMessage::ClientMessage(a) => a.get_actor(),
4504            ProtocolMessage::AppMessage(a) => a.get_actor(),
4505            // ProtocolMessage::ServerHello(a) => a.get_actor(),
4506            // ProtocolMessage::ClientAuth(a) => a.get_actor(),
4507            // ProtocolMessage::AuthResult(a) => a.get_actor(),
4508            //ProtocolMessage::ExtRequest(a) => a.get_actor(),
4509            //ProtocolMessage::ExtResponse(a) => a.get_actor(),
4510            // ProtocolMessage::BrokerMessage(a) => a.get_actor(),
4511            _ => unimplemented!(),
4512        }
4513    }
4514
4515    pub fn from_client_response_err(err: ServerError) -> ProtocolMessage {
4516        let res: ClientResponse = err.into();
4517        res.into()
4518    }
4519
4520    pub fn from_client_request_v0(
4521        req: ClientRequestContentV0,
4522        overlay: OverlayId,
4523    ) -> ProtocolMessage {
4524        ProtocolMessage::ClientMessage(ClientMessage::V0(ClientMessageV0 {
4525            overlay,
4526            content: ClientMessageContentV0::ClientRequest(ClientRequest::V0(ClientRequestV0 {
4527                id: 0,
4528                content: req,
4529            })),
4530            padding: vec![],
4531        }))
4532    }
4533
4534    pub fn is_block(&self) -> bool {
4535        match self {
4536            ProtocolMessage::ClientMessage(ClientMessage::V0(ClientMessageV0 {
4537                content: c,
4538                ..
4539            })) => c.is_block(),
4540            _ => false,
4541        }
4542    }
4543}
4544
4545impl From<ClientResponseContentV0> for ClientResponse {
4546    fn from(msg: ClientResponseContentV0) -> ClientResponse {
4547        ClientResponse::V0(ClientResponseV0 {
4548            id: 0,
4549            result: 0,
4550            content: msg,
4551        })
4552    }
4553}
4554
4555impl From<ClientResponseContentV0> for ProtocolMessage {
4556    fn from(msg: ClientResponseContentV0) -> ProtocolMessage {
4557        let client_res = ClientResponse::V0(ClientResponseV0 {
4558            id: 0,
4559            result: 0,
4560            content: msg,
4561        });
4562        client_res.into()
4563    }
4564}
4565
4566impl From<ClientResponse> for ProtocolMessage {
4567    fn from(msg: ClientResponse) -> ProtocolMessage {
4568        ProtocolMessage::ClientMessage(ClientMessage::V0(ClientMessageV0 {
4569            overlay: OverlayId::nil(),
4570            content: ClientMessageContentV0::ClientResponse(msg),
4571            padding: vec![],
4572        }))
4573    }
4574}
4575
4576//
4577// AUTHENTICATION MESSAGES
4578//
4579
4580/// Content of ClientAuthV0
4581#[derive(Clone, Debug, Serialize, Deserialize)]
4582pub struct ClientAuthContentV0 {
4583    /// User pub key
4584    pub user: PubKey,
4585
4586    /// Client pub key
4587    pub client: PubKey,
4588
4589    pub info: ClientInfoV0,
4590
4591    pub registration: Option<Option<[u8; 32]>>,
4592
4593    /// Nonce from ServerHello
4594    #[serde(with = "serde_bytes")]
4595    pub nonce: Vec<u8>,
4596}
4597
4598/// Client authentication
4599#[derive(Clone, Debug, Serialize, Deserialize)]
4600pub struct ClientAuthV0 {
4601    /// Authentication data
4602    pub content: ClientAuthContentV0,
4603
4604    /// Signature by user key
4605    pub sig: Sig,
4606
4607    /// Signature by client key
4608    pub client_sig: Sig,
4609}
4610
4611/// Client authentication
4612#[derive(Clone, Debug, Serialize, Deserialize)]
4613pub enum ClientAuth {
4614    V0(ClientAuthV0),
4615}
4616
4617impl ClientAuth {
4618    pub fn content_v0(&self) -> ClientAuthContentV0 {
4619        match self {
4620            ClientAuth::V0(o) => o.content.clone(),
4621        }
4622    }
4623    pub fn sig(&self) -> Sig {
4624        match self {
4625            ClientAuth::V0(o) => o.sig,
4626        }
4627    }
4628    pub fn user(&self) -> PubKey {
4629        match self {
4630            ClientAuth::V0(o) => o.content.user,
4631        }
4632    }
4633    pub fn client(&self) -> PubKey {
4634        match self {
4635            ClientAuth::V0(o) => o.content.client,
4636        }
4637    }
4638    pub fn nonce(&self) -> &Vec<u8> {
4639        match self {
4640            ClientAuth::V0(o) => &o.content.nonce,
4641        }
4642    }
4643    pub fn registration(&self) -> Option<Option<[u8; 32]>> {
4644        match self {
4645            ClientAuth::V0(o) => o.content.registration,
4646        }
4647    }
4648}
4649
4650impl From<ClientAuth> for ProtocolMessage {
4651    fn from(msg: ClientAuth) -> ProtocolMessage {
4652        ProtocolMessage::ClientAuth(msg)
4653    }
4654}
4655
4656/// Authentication result
4657#[derive(Clone, Debug, Serialize, Deserialize)]
4658pub struct AuthResultV0 {
4659    pub result: u16,
4660    #[serde(with = "serde_bytes")]
4661    pub metadata: Vec<u8>,
4662}
4663
4664/// Authentication result
4665#[derive(Clone, Debug, Serialize, Deserialize)]
4666pub enum AuthResult {
4667    V0(AuthResultV0),
4668}
4669
4670impl AuthResult {
4671    pub fn result(&self) -> u16 {
4672        match self {
4673            AuthResult::V0(o) => o.result,
4674        }
4675    }
4676    pub fn metadata(&self) -> &Vec<u8> {
4677        match self {
4678            AuthResult::V0(o) => &o.metadata,
4679        }
4680    }
4681}
4682
4683impl From<AuthResult> for ProtocolMessage {
4684    fn from(msg: AuthResult) -> ProtocolMessage {
4685        ProtocolMessage::AuthResult(msg)
4686    }
4687}
4688
4689//
4690// LINKS
4691//
4692
4693/// Link to a repository
4694///
4695/// Consists of an identifier (repoid), a ReadCap or WriteCap, and a locator (peers and overlayLink)
4696/// Those capabilities are not durable: They can be refreshed by the members and previously shared Caps will become obsolete/revoked.
4697/// As long as the user is a member of the repo and subscribes to the root topic (of the repo, and of the store if needed/applicable), they will receive the updated capabilities.
4698/// But if they don't subscribe, they will lose access after the refresh.
4699/// For durable capabilities, see PermaCap.
4700/// In most cases, the link is shared and then the recipient opens it and subscribes soon afterward, so there is no need for a PermaCap
4701/// Perma capabilities are needed only when the link is stored on disk and kept there unopened for a long period.
4702#[derive(Clone, Debug, Serialize, Deserialize)]
4703pub struct RepoLinkV0 {
4704    /// Repository ID
4705    pub id: RepoId,
4706
4707    /// read capability for the whole repo
4708    /// current (at the time of sharing the link) root branch definition commit
4709    pub read_cap: ReadCap,
4710
4711    /// Write capability secret. Only set for editors. in this case, overlay MUST be set to an InnerOverlay
4712    // pub write_cap_secret: Option<RepoWriteCapSecret>,
4713
4714    /// Current overlay link, used to join the overlay
4715    pub overlay: OverlayLink,
4716
4717    /// Peer brokers to connect to
4718    pub peers: Vec<PeerAdvert>,
4719}
4720
4721/// Link to a repository
4722#[derive(Clone, Debug, Serialize, Deserialize)]
4723pub enum RepoLink {
4724    V0(RepoLinkV0),
4725}
4726
4727impl RepoLink {
4728    pub fn id(&self) -> &RepoId {
4729        match self {
4730            RepoLink::V0(o) => &o.id,
4731        }
4732    }
4733    pub fn peers(&self) -> &Vec<PeerAdvert> {
4734        match self {
4735            RepoLink::V0(o) => &o.peers,
4736        }
4737    }
4738}
4739
4740/// Link for a Public Repo
4741///
4742/// The latest ReadCap of the branch (or main branch) will be downloaded from the outerOverlay, if the peer brokers listed below allow it.
4743/// The snapshot can be downloaded instead
4744/// This link is durable, because the public site are served differently by brokers.
4745#[derive(Clone, Debug, Serialize, Deserialize)]
4746pub struct PublicRepoLinkV0 {
4747    /// Repository ID
4748    pub repo: RepoId,
4749
4750    /// optional branchId to access. a specific public branch,
4751    /// if not set, the main branch of the repo will be used.
4752    pub branch: Option<BranchId>,
4753
4754    /// optional commits of head to access.
4755    /// if not set, the main branch of the repo will be used.
4756    pub heads: Vec<ObjectRef>,
4757
4758    /// optional snapshot to download, in order to display the content quicker to end-user.
4759    pub snapshot: Option<ObjectRef>,
4760
4761    /// The public site store
4762    pub public_store: PubKey,
4763
4764    /// Peer brokers to connect to
4765    pub peers: Vec<PeerAdvert>,
4766}
4767
4768/// Link to a public repository
4769#[derive(Clone, Debug, Serialize, Deserialize)]
4770pub enum PublicRepoLink {
4771    V0(PublicRepoLinkV0),
4772}
4773
4774/// Read access to a branch of a Public, Protected or Group store.
4775///
4776/// The overlay to join can be the outer or the inner, depending on what was offered in the link.
4777/// The difference between the two is that in the outer overlay, only one broker is contacted.
4778/// In the inner overlay, all the publisher's brokers are contacted, so subscription to the pub/sub is more reliable, less prone to outage.
4779/// This is not a durable link. If the topic has been refreshed, the pubsub won't be able to be subscribed to,
4780/// but TopicSyncReq will still work (answering the commits up until the moment the topic was refreshed)
4781/// and the optional heads will always be retrievable
4782#[derive(Clone, Debug, Serialize, Deserialize)]
4783pub struct ReadBranchLinkV0 {
4784    /// Repository ID
4785    pub repo: RepoId,
4786
4787    pub branch: BranchId, // must match the one in read_cap
4788
4789    pub topic: TopicId,
4790
4791    /// an optional list of heads that can be fetched in this branch
4792    /// useful if a specific head is to be shared
4793    pub heads: Vec<ObjectRef>,
4794
4795    /// read capability for the branch
4796    /// current (at the time of sharing the link) branch definition commit
4797    pub read_cap: ReadCap,
4798
4799    /// Current overlay link, used to join the overlay, most of the time, an outerOverlay is preferred
4800    pub overlay: OverlayLink,
4801
4802    /// Peer brokers to connect to
4803    pub peers: Vec<PeerAdvert>,
4804}
4805
4806/// Link to a repository
4807#[derive(Clone, Debug, Serialize, Deserialize)]
4808pub enum ReadBranchLink {
4809    V0(ReadBranchLinkV0),
4810}
4811
4812/// Obtains one or more objects of a repo (Commit, File) by their ID.
4813///
4814/// On an outerOverlay, the header is always emptied (no way to reconstruct the DAG of commits) except on public overlays or if a topicId is provided
4815/// If the intent is to share a whole DAG of commits at a definite CommitID/HEAD, then ReadBranchLink should be used instead (or PublicRepoLink if public site)
4816#[derive(Clone, Debug, Serialize, Deserialize)]
4817pub struct ObjectLinkV0 {
4818    /// Repository ID: not used to make the request. but useful for commits, to know which repo they are from without needing to fetch and open the full DAG of commits.
4819    /// (but the one here might be wrong. only when opening the DAG can the real repo be known. also note that on outerOverlay of non public stores, the DAG is not accessible)
4820    /// note that it could be omitted, specially if the objects are files. As files are content-addressable and belong to an overlay but not to a specific repo or topic.
4821    pub repo: Option<RepoId>,
4822
4823    /// An optional topic that will be used to retrieve the Certificate of a commit, if needed
4824    /// (topic has to be checked with the one inside the commit. the one here might be wrong. it is provided here as an optimization)
4825    /// or can be used to help with BlockSearchTopic.
4826    /// If the topic is provided, a TopicSyncReq can be performed, and the causal past of the commit will appear (by repeated tries while narrowing down on the ancestors),
4827    /// hence defeating the "emptied header" protection
4828    pub topic: Option<TopicId>,
4829
4830    pub objects: Vec<ObjectRef>,
4831
4832    /// Overlay to join
4833    pub overlay: OverlayLink,
4834
4835    /// Peer brokers to connect to
4836    pub peers: Vec<PeerAdvert>,
4837}
4838
4839/// Link to a specific commit, without its causal past
4840#[derive(Clone, Debug, Serialize, Deserialize)]
4841pub enum ObjectLink {
4842    V0(ObjectLinkV0),
4843}
4844
4845/// NextGraph Link V0
4846#[derive(Clone, Debug, Serialize, Deserialize)]
4847pub enum NgLinkV0 {
4848    Repo(RepoLink),
4849    PublicRepo(PublicRepoLink),
4850    Branch(ReadBranchLink),
4851    Object(ObjectLink),
4852}
4853
4854/// NextGraph Link
4855#[derive(Clone, Debug, Serialize, Deserialize)]
4856pub enum NgLink {
4857    V0(NgLinkV0),
4858}
4859
4860// TODO: PermaLinks and PostInbox (and ExtRequests)
4861
4862#[cfg(test)]
4863mod test {
4864
4865    use crate::types::{BootstrapContentV0, BrokerServerTypeV0, BrokerServerV0, Invitation};
4866    use ng_repo::types::PubKey;
4867
4868    #[test]
4869    pub fn invitation() {
4870        let inv = Invitation::new_v0(
4871            BootstrapContentV0 {
4872                servers: vec![BrokerServerV0 {
4873                    server_type: BrokerServerTypeV0::Localhost(14400),
4874                    can_verify: false,
4875                    can_forward: false,
4876                    peer_id: PubKey::Ed25519PubKey([
4877                        95, 73, 225, 250, 3, 147, 24, 164, 177, 211, 34, 244, 45, 130, 111, 136,
4878                        229, 145, 53, 167, 50, 168, 140, 227, 65, 111, 203, 41, 210, 186, 162, 149,
4879                    ]),
4880                }],
4881            },
4882            Some("test invitation".to_string()),
4883            None,
4884        );
4885
4886        println!("{:?}", inv.get_urls());
4887    }
4888}