forked from NextGraph/nextgraph-rs
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3699 lines
113 KiB
3699 lines
113 KiB
12 months ago
|
// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
|
||
2 years ago
|
// All rights reserved.
|
||
|
// Licensed under the Apache License, Version 2.0
|
||
2 years ago
|
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
|
||
2 years ago
|
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
||
|
// at your option. All files in the project carrying such
|
||
|
// notice may not be copied, modified, or distributed except
|
||
|
// according to those terms.
|
||
|
|
||
|
//! P2P network protocol types
|
||
|
//!
|
||
|
//! Corresponds to the BARE schema
|
||
|
|
||
2 years ago
|
use crate::utils::{
|
||
11 months ago
|
get_domain_without_port_443, is_ipv4_private, is_ipv6_private, is_private_ip, is_public_ip,
|
||
|
is_public_ipv4, is_public_ipv6,
|
||
2 years ago
|
};
|
||
|
use crate::{actor::EActor, actors::*, errors::ProtocolError};
|
||
2 years ago
|
use core::fmt;
|
||
10 months ago
|
use ng_repo::errors::NgError;
|
||
11 months ago
|
|
||
10 months ago
|
use ng_repo::types::*;
|
||
2 years ago
|
use serde::{Deserialize, Serialize};
|
||
2 years ago
|
use std::{
|
||
|
any::{Any, TypeId},
|
||
|
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
||
|
};
|
||
2 years ago
|
use web_time::SystemTime;
|
||
2 years ago
|
|
||
2 years ago
|
//
|
||
11 months ago
|
// Network common types
|
||
2 years ago
|
//
|
||
|
|
||
2 years ago
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||
|
pub enum InterfaceType {
|
||
|
Loopback,
|
||
|
Private,
|
||
|
Public,
|
||
|
Invalid,
|
||
|
}
|
||
|
|
||
|
impl InterfaceType {
|
||
|
pub fn is_ip_valid_for_type(&self, ip: &IP) -> bool {
|
||
|
self.is_ipaddr_valid_for_type(&ip.into())
|
||
|
}
|
||
|
pub fn is_ipaddr_valid_for_type(&self, ip: &IpAddr) -> bool {
|
||
|
match ip {
|
||
|
IpAddr::V4(v4) => self.is_ipv4_valid_for_type(v4),
|
||
|
IpAddr::V6(v6) => self.is_ipv6_valid_for_type(v6),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn is_ipv4_valid_for_type(&self, ip: &Ipv4Addr) -> bool {
|
||
|
match self {
|
||
|
InterfaceType::Loopback => ip.is_loopback(),
|
||
|
InterfaceType::Public => is_public_ipv4(ip),
|
||
|
// we allow to bind to link-local for IPv4
|
||
|
InterfaceType::Private => is_ipv4_private(ip),
|
||
|
_ => false,
|
||
|
}
|
||
|
}
|
||
|
pub fn is_ipv6_valid_for_type(&self, ip: &Ipv6Addr) -> bool {
|
||
|
match self {
|
||
|
InterfaceType::Loopback => ip.is_loopback(),
|
||
|
InterfaceType::Public => is_public_ipv6(ip),
|
||
|
// we do NOT allow to bind to link-local for IPv6
|
||
2 years ago
|
InterfaceType::Private => is_ipv6_private(ip),
|
||
2 years ago
|
_ => false,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[cfg(not(target_arch = "wasm32"))]
|
||
|
#[derive(Clone, Debug)]
|
||
|
pub struct Interface {
|
||
|
pub if_type: InterfaceType,
|
||
|
pub name: String,
|
||
|
pub mac_addr: Option<default_net::interface::MacAddr>,
|
||
|
/// List of Ipv4Net for the network interface
|
||
|
pub ipv4: Vec<default_net::ip::Ipv4Net>,
|
||
|
/// List of Ipv6Net for the network interface
|
||
|
pub ipv6: Vec<default_net::ip::Ipv6Net>,
|
||
|
}
|
||
|
|
||
2 years ago
|
/// Bind address
|
||
2 years ago
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||
2 years ago
|
pub struct BindAddress {
|
||
|
pub port: u16,
|
||
|
pub ip: IP,
|
||
|
}
|
||
|
|
||
2 years ago
|
impl BindAddress {
|
||
|
pub fn to_ws_url(&self) -> String {
|
||
|
format!(
|
||
|
"ws://{}:{}",
|
||
|
self.ip,
|
||
|
if self.port == 0 { 80 } else { self.port }
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
impl From<&SocketAddr> for BindAddress {
|
||
|
#[inline]
|
||
|
fn from(addr: &SocketAddr) -> BindAddress {
|
||
|
let ip_addr = addr.ip();
|
||
|
let ip = IP::try_from(&ip_addr).unwrap();
|
||
|
let port = addr.port();
|
||
|
BindAddress { ip, port }
|
||
|
}
|
||
|
}
|
||
|
|
||
11 months ago
|
/// BROKER common types
|
||
|
|
||
2 years ago
|
/// Core Broker connection details Version 0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||
|
pub struct BrokerCoreV0 {
|
||
|
/// peerId of the server
|
||
|
pub peer_id: PubKey,
|
||
|
|
||
|
/// network addresses of the broker, typically an IpV4 and an optional IPV6 addr. core broker should not be multi-homed.
|
||
|
pub addrs: Vec<BindAddress>,
|
||
|
}
|
||
|
|
||
|
/// Core Broker connection details
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Hash)]
|
||
|
pub enum BrokerCore {
|
||
|
V0(BrokerCoreV0),
|
||
|
}
|
||
|
|
||
2 years ago
|
/// BrokerServerTypeV0 type
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||
2 years ago
|
pub enum BrokerServerTypeV0 {
|
||
|
Localhost(u16), // optional port number
|
||
|
BoxPrivate(Vec<BindAddress>),
|
||
11 months ago
|
Public(Vec<BindAddress>),
|
||
2 years ago
|
BoxPublicDyn(Vec<BindAddress>), // can be empty
|
||
11 months ago
|
Domain(String), // accepts an optional trailing ":port" number
|
||
2 years ago
|
//Core(Vec<BindAddress>),
|
||
2 years ago
|
}
|
||
|
|
||
|
/// BrokerServer details Version 0
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||
2 years ago
|
pub struct BrokerServerV0 {
|
||
|
/// Network addresses
|
||
|
pub server_type: BrokerServerTypeV0,
|
||
|
|
||
|
/// peerId of the server
|
||
|
pub peer_id: PubKey,
|
||
|
}
|
||
|
|
||
2 years ago
|
pub const APP_ACCOUNT_REGISTERED_SUFFIX: &str = "/#/user/registered";
|
||
|
|
||
2 years ago
|
pub const NG_ONE_URL: &str = "https://nextgraph.one";
|
||
|
|
||
2 years ago
|
pub const APP_NG_ONE_URL: &str = "https://app.nextgraph.one";
|
||
|
|
||
|
pub const APP_NG_ONE_WS_URL: &str = "wss://app.nextgraph.one";
|
||
|
|
||
11 months ago
|
#[allow(dead_code)]
|
||
2 years ago
|
fn api_dyn_peer_url(peer_id: &PubKey) -> String {
|
||
|
format!("https://nextgraph.one/api/v1/dynpeer/{}", peer_id)
|
||
|
}
|
||
|
|
||
|
pub const LOCAL_HOSTS: [&str; 3] = ["localhost", "127.0.0.1", "[::1]"];
|
||
|
|
||
|
fn local_ws_url(port: &u16) -> String {
|
||
|
format!("ws://localhost:{}", if *port == 0 { 80 } else { *port })
|
||
|
}
|
||
|
|
||
2 years ago
|
pub fn local_http_url(port: &u16) -> String {
|
||
2 years ago
|
format!("http://localhost:{}", if *port == 0 { 80 } else { *port })
|
||
|
}
|
||
|
|
||
2 years ago
|
pub const LOCAL_URLS: [&str; 3] = ["http://localhost", "http://127.0.0.1", "http://[::1]"];
|
||
|
use url::{Host, Url};
|
||
|
|
||
|
impl BrokerServerTypeV0 {
|
||
|
pub fn find_first_ipv4(&self) -> Option<&BindAddress> {
|
||
|
match self {
|
||
|
Self::BoxPrivate(addrs) => {
|
||
|
for addr in addrs {
|
||
|
if addr.ip.is_v4() {
|
||
|
return Some(addr);
|
||
|
}
|
||
|
}
|
||
|
return None;
|
||
|
}
|
||
|
_ => None,
|
||
|
}
|
||
|
}
|
||
|
pub fn find_first_ipv6(&self) -> Option<&BindAddress> {
|
||
|
match self {
|
||
|
Self::BoxPrivate(addrs) => {
|
||
|
for addr in addrs {
|
||
|
if addr.ip.is_v6() {
|
||
|
return Some(addr);
|
||
|
}
|
||
|
}
|
||
|
return None;
|
||
|
}
|
||
|
_ => None,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
impl BrokerServerV0 {
|
||
|
fn first_ipv4(&self) -> Option<(String, Vec<BindAddress>)> {
|
||
|
self.server_type.find_first_ipv4().map_or(None, |bindaddr| {
|
||
|
Some((format!("ws://{}:{}", bindaddr.ip, bindaddr.port), vec![]))
|
||
|
})
|
||
|
}
|
||
|
|
||
|
fn first_ipv6(&self) -> Option<(String, Vec<BindAddress>)> {
|
||
|
self.server_type.find_first_ipv6().map_or(None, |bindaddr| {
|
||
|
Some((format!("ws://{}:{}", bindaddr.ip, bindaddr.port), vec![]))
|
||
|
})
|
||
|
}
|
||
|
|
||
2 years ago
|
pub fn first_ipv4_http(&self) -> Option<String> {
|
||
|
self.server_type.find_first_ipv4().map_or(None, |bindaddr| {
|
||
|
Some(format!("http://{}:{}", bindaddr.ip, bindaddr.port))
|
||
|
})
|
||
|
}
|
||
|
|
||
|
pub fn first_ipv6_http(&self) -> Option<String> {
|
||
|
self.server_type.find_first_ipv6().map_or(None, |bindaddr| {
|
||
|
Some(format!("http://{}:{}", bindaddr.ip, bindaddr.port))
|
||
|
})
|
||
|
}
|
||
|
|
||
2 years ago
|
fn first_ipv6_or_ipv4(
|
||
|
ipv4: bool,
|
||
|
ipv6: bool,
|
||
|
addrs: &Vec<BindAddress>,
|
||
|
) -> Option<&BindAddress> {
|
||
|
if ipv6 {
|
||
|
for addr in addrs {
|
||
|
if addr.ip.is_v6() {
|
||
|
return Some(addr);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ipv4 {
|
||
|
for addr in addrs {
|
||
|
if addr.ip.is_v4() {
|
||
|
return Some(addr);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return None;
|
||
|
}
|
||
|
|
||
|
fn app_ng_one_bootstrap_url(addr: &BindAddress, key: PubKey) -> Option<String> {
|
||
|
let payload = (addr, key);
|
||
|
let payload_ser = serde_bare::to_vec(&payload).ok();
|
||
|
if payload_ser.is_none() {
|
||
|
return None;
|
||
|
}
|
||
|
Some(format!(
|
||
|
"{}?b={}",
|
||
2 years ago
|
APP_NG_ONE_URL,
|
||
2 years ago
|
base64_url::encode(&payload_ser.unwrap())
|
||
|
))
|
||
|
}
|
||
|
|
||
|
fn app_ng_one_bootstrap_url_with_first_ipv6_or_ipv4(
|
||
|
ipv4: bool,
|
||
|
ipv6: bool,
|
||
|
addrs: &Vec<BindAddress>,
|
||
|
key: PubKey,
|
||
|
) -> Option<String> {
|
||
|
if let Some(addr) = Self::first_ipv6_or_ipv4(ipv4, ipv6, addrs) {
|
||
|
return Self::app_ng_one_bootstrap_url(addr, key);
|
||
|
}
|
||
|
None
|
||
|
}
|
||
|
|
||
|
/// set ipv6 only if the browser connected with a remote IPV6. always set ipv4 as a fallback (for now).
|
||
|
pub async fn get_url_for_ngone(&self, ipv4: bool, ipv6: bool) -> Option<String> {
|
||
|
match &self.server_type {
|
||
11 months ago
|
BrokerServerTypeV0::Public(addrs) => {
|
||
2 years ago
|
Self::app_ng_one_bootstrap_url_with_first_ipv6_or_ipv4(
|
||
|
ipv4,
|
||
|
ipv6,
|
||
|
addrs,
|
||
|
self.peer_id,
|
||
|
)
|
||
|
}
|
||
|
BrokerServerTypeV0::BoxPublicDyn(addrs) => {
|
||
1 year ago
|
// let resp = reqwest::get(api_dyn_peer_url(&self.peer_id)).await;
|
||
|
// if resp.is_ok() {
|
||
|
// let resp = resp.unwrap().json::<Vec<BindAddress>>().await;
|
||
|
// if resp.is_ok() {
|
||
|
// return Self::app_ng_one_bootstrap_url_with_first_ipv6_or_ipv4(
|
||
|
// ipv4,
|
||
|
// ipv6,
|
||
|
// &resp.unwrap(),
|
||
|
// self.peer_id,
|
||
|
// );
|
||
|
// }
|
||
|
// }
|
||
2 years ago
|
if addrs.len() > 0 {
|
||
|
Self::app_ng_one_bootstrap_url_with_first_ipv6_or_ipv4(
|
||
|
ipv4,
|
||
|
ipv6,
|
||
|
&addrs,
|
||
|
self.peer_id,
|
||
|
)
|
||
|
} else {
|
||
|
None
|
||
|
}
|
||
|
}
|
||
|
BrokerServerTypeV0::Domain(domain) => Some(format!("https://{}", domain)),
|
||
2 years ago
|
BrokerServerTypeV0::Localhost(port) => Some(local_http_url(&port)),
|
||
2 years ago
|
BrokerServerTypeV0::BoxPrivate(_) => {
|
||
|
if ipv6 {
|
||
2 years ago
|
let v6 = self.server_type.find_first_ipv6().map_or(None, |bindaddr| {
|
||
|
Some(format!("http://{}:{}", bindaddr.ip, bindaddr.port))
|
||
|
});
|
||
2 years ago
|
if v6.is_some() {
|
||
|
return v6;
|
||
|
}
|
||
|
}
|
||
|
if ipv4 {
|
||
2 years ago
|
self.server_type.find_first_ipv4().map_or(None, |bindaddr| {
|
||
|
Some(format!("http://{}:{}", bindaddr.ip, bindaddr.port))
|
||
|
})
|
||
2 years ago
|
} else {
|
||
|
None
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
pub fn is_public_server(&self) -> bool {
|
||
2 years ago
|
match &self.server_type {
|
||
|
BrokerServerTypeV0::Localhost(_) => false,
|
||
|
BrokerServerTypeV0::BoxPrivate(_) => false,
|
||
11 months ago
|
BrokerServerTypeV0::Public(_) => true,
|
||
2 years ago
|
BrokerServerTypeV0::BoxPublicDyn(_) => true,
|
||
|
BrokerServerTypeV0::Domain(_) => true,
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
/// on web browser, returns the connection URL and an optional list of BindAddress if a relay is needed
|
||
|
/// filtered by the current location url of the webpage
|
||
2 years ago
|
/// on native apps (do not pass a location), returns or the connection URL without optional BindAddress or an empty string with
|
||
2 years ago
|
/// several BindAddresses to try to connect to with .to_ws_url()
|
||
1 year ago
|
pub async fn get_ws_url(
|
||
|
&self,
|
||
|
location: &Option<String>,
|
||
|
) -> Option<(String, Vec<BindAddress>)> {
|
||
2 years ago
|
if location.is_some() {
|
||
1 year ago
|
let location = location.as_ref().unwrap();
|
||
2 years ago
|
if location.starts_with(APP_NG_ONE_URL) {
|
||
|
match &self.server_type {
|
||
11 months ago
|
BrokerServerTypeV0::Public(addrs) => {
|
||
2 years ago
|
Some((APP_NG_ONE_WS_URL.to_string(), addrs.clone()))
|
||
|
}
|
||
|
BrokerServerTypeV0::BoxPublicDyn(addrs) => {
|
||
1 year ago
|
// let resp = reqwest::get(api_dyn_peer_url(&self.peer_id)).await;
|
||
|
// if resp.is_ok() {
|
||
|
// let resp = resp.unwrap().json::<Vec<BindAddress>>().await;
|
||
|
// if resp.is_ok() {
|
||
|
// return Some((APP_NG_ONE_WS_URL.to_string(), resp.unwrap()));
|
||
|
// }
|
||
|
// }
|
||
2 years ago
|
if addrs.len() > 0 {
|
||
|
Some((APP_NG_ONE_WS_URL.to_string(), addrs.clone()))
|
||
|
} else {
|
||
|
None
|
||
|
}
|
||
|
}
|
||
|
_ => None,
|
||
|
}
|
||
|
} else if let BrokerServerTypeV0::Domain(domain) = &self.server_type {
|
||
|
let url = format!("https://{}", domain);
|
||
|
if location.starts_with(&url) {
|
||
|
let wss_url = format!("wss://{}", domain);
|
||
|
Some((wss_url, vec![]))
|
||
|
} else {
|
||
|
None
|
||
|
}
|
||
|
} else {
|
||
|
// localhost
|
||
|
if location.starts_with(LOCAL_URLS[0])
|
||
|
|| location.starts_with(LOCAL_URLS[1])
|
||
|
|| location.starts_with(LOCAL_URLS[2])
|
||
|
{
|
||
|
if let BrokerServerTypeV0::Localhost(port) = self.server_type {
|
||
|
Some((local_ws_url(&port), vec![]))
|
||
|
} else {
|
||
|
None
|
||
|
}
|
||
|
}
|
||
|
// a private address
|
||
|
else if location.starts_with("http://") {
|
||
|
let url = Url::parse(&location).unwrap();
|
||
|
match url.host() {
|
||
|
Some(Host::Ipv4(ip)) => {
|
||
|
if is_ipv4_private(&ip) {
|
||
|
self.first_ipv4()
|
||
|
} else {
|
||
|
None
|
||
|
}
|
||
|
}
|
||
|
Some(Host::Ipv6(ip)) => {
|
||
|
if is_ipv6_private(&ip) {
|
||
|
self.first_ipv6()
|
||
|
} else {
|
||
|
None
|
||
|
}
|
||
|
}
|
||
|
_ => None,
|
||
|
}
|
||
|
} else {
|
||
|
None
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
// From native / tauri app
|
||
|
match &self.server_type {
|
||
2 years ago
|
//BrokerServerTypeV0::Core(_) => None,
|
||
2 years ago
|
BrokerServerTypeV0::Localhost(port) => Some((local_ws_url(port), vec![])),
|
||
|
BrokerServerTypeV0::BoxPrivate(addrs) => Some((String::new(), addrs.clone())),
|
||
11 months ago
|
BrokerServerTypeV0::Public(addrs) => Some((String::new(), addrs.clone())),
|
||
2 years ago
|
BrokerServerTypeV0::BoxPublicDyn(addrs) => {
|
||
1 year ago
|
// let resp = reqwest::get(api_dyn_peer_url(&self.peer_id)).await;
|
||
|
// if resp.is_ok() {
|
||
|
// let resp = resp.unwrap().json::<Vec<BindAddress>>().await;
|
||
|
// if resp.is_ok() {
|
||
|
// return Some((String::new(), resp.unwrap()));
|
||
|
// }
|
||
|
// }
|
||
2 years ago
|
if addrs.len() > 0 {
|
||
|
Some((String::new(), addrs.clone()))
|
||
|
} else {
|
||
|
None
|
||
|
}
|
||
|
}
|
||
|
BrokerServerTypeV0::Domain(domain) => Some((format!("wss://{}", domain), vec![])),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
/// Bootstrap content Version 0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct BootstrapContentV0 {
|
||
|
/// list of servers, in order of preference
|
||
|
pub servers: Vec<BrokerServerV0>,
|
||
|
}
|
||
|
|
||
2 years ago
|
impl BootstrapContentV0 {
|
||
|
pub fn new() -> Self {
|
||
|
BootstrapContentV0 { servers: vec![] }
|
||
|
}
|
||
|
pub fn merge(&mut self, with: &BootstrapContentV0) {
|
||
|
'outer: for server2 in &with.servers {
|
||
|
for server1 in &self.servers {
|
||
|
if *server1 == *server2 {
|
||
|
continue 'outer;
|
||
|
}
|
||
|
}
|
||
|
self.servers.push(server2.clone());
|
||
|
}
|
||
|
}
|
||
|
pub fn get_first_peer_id(&self) -> Option<PubKey> {
|
||
|
self.servers.first().map(|s| s.peer_id)
|
||
|
}
|
||
1 year ago
|
|
||
|
pub fn get_domain(&self) -> Option<String> {
|
||
|
for server in self.servers.iter() {
|
||
|
if let BrokerServerTypeV0::Domain(name) = &server.server_type {
|
||
|
return Some(name.clone());
|
||
|
}
|
||
|
}
|
||
|
None
|
||
|
}
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum BootstrapContent {
|
||
|
V0(BootstrapContentV0),
|
||
|
}
|
||
|
|
||
2 years ago
|
impl BootstrapContent {
|
||
|
pub fn servers(&self) -> &Vec<BrokerServerV0> {
|
||
|
match self {
|
||
|
Self::V0(v0) => &v0.servers,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
1 year ago
|
/// Local Bootstrap info Version 0, served at /.ng_bootstrap
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct LocalBootstrapInfoV0 {
|
||
|
/// list of servers, in order of preference
|
||
|
pub bootstrap: BootstrapContentV0,
|
||
|
|
||
|
/// optional registration_url for public server that accept to be BSP for new clients
|
||
|
pub registration_url: Option<String>,
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum LocalBootstrapInfo {
|
||
|
V0(LocalBootstrapInfoV0),
|
||
|
}
|
||
|
|
||
|
impl LocalBootstrapInfo {
|
||
|
pub fn servers(&self) -> &Vec<BrokerServerV0> {
|
||
|
match self {
|
||
|
Self::V0(v0) => &v0.bootstrap.servers,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl From<LocalBootstrapInfo> for Invitation {
|
||
|
fn from(value: LocalBootstrapInfo) -> Self {
|
||
|
let LocalBootstrapInfo::V0(info) = value;
|
||
|
let name = info.bootstrap.get_domain();
|
||
|
let url = info.registration_url.clone();
|
||
|
Invitation::V0(InvitationV0 {
|
||
|
bootstrap: info.bootstrap,
|
||
|
code: None,
|
||
|
name,
|
||
|
url,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum InvitationCode {
|
||
|
Unique(SymKey),
|
||
|
Admin(SymKey),
|
||
|
Multi(SymKey),
|
||
|
}
|
||
|
|
||
2 years ago
|
impl InvitationCode {
|
||
|
pub fn get_symkey(&self) -> SymKey {
|
||
|
match self {
|
||
|
Self::Unique(s) | Self::Admin(s) | Self::Multi(s) => s.clone(),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl fmt::Display for InvitationCode {
|
||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
|
match self {
|
||
|
Self::Unique(k) => write!(f, "unique {}", k),
|
||
|
Self::Admin(k) => write!(f, "admin {}", k),
|
||
|
Self::Multi(k) => write!(f, "multi {}", k),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
/// Invitation to create an account at a broker. Version 0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct InvitationV0 {
|
||
|
/// list of servers, in order of preference
|
||
|
pub bootstrap: BootstrapContentV0,
|
||
|
|
||
|
pub code: Option<SymKey>,
|
||
|
|
||
|
/// an optional name to display to the invitee
|
||
|
pub name: Option<String>,
|
||
|
|
||
|
// an optional url to redirect the user to, for accepting ToS and making payment, if any.
|
||
|
pub url: Option<String>,
|
||
|
}
|
||
|
|
||
2 years ago
|
impl InvitationV0 {
|
||
|
pub fn set_bootstrap(&mut self, content: BootstrapContent) {
|
||
|
match content {
|
||
|
BootstrapContent::V0(v0) => self.bootstrap = v0,
|
||
|
}
|
||
|
}
|
||
2 years ago
|
pub fn empty(name: Option<String>) -> Self {
|
||
|
InvitationV0 {
|
||
1 year ago
|
bootstrap: BootstrapContentV0::new(),
|
||
2 years ago
|
code: None,
|
||
|
name,
|
||
|
url: None,
|
||
|
}
|
||
|
}
|
||
2 years ago
|
pub fn new(
|
||
|
bootstrap_content: BootstrapContent,
|
||
|
code: Option<SymKey>,
|
||
|
name: Option<String>,
|
||
|
url: Option<String>,
|
||
|
) -> Self {
|
||
|
match bootstrap_content {
|
||
|
BootstrapContent::V0(v0) => InvitationV0 {
|
||
|
bootstrap: v0,
|
||
|
code,
|
||
|
name,
|
||
|
url,
|
||
|
},
|
||
|
}
|
||
|
}
|
||
2 years ago
|
pub fn append_bootstraps(&mut self, add: &mut Option<BootstrapContentV0>) {
|
||
|
if add.is_some() {
|
||
|
let add = add.as_mut().unwrap();
|
||
|
self.bootstrap.servers.append(&mut add.servers);
|
||
|
}
|
||
|
}
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
impl Invitation {
|
||
|
pub fn new_v0(
|
||
|
bootstrap: BootstrapContentV0,
|
||
|
name: Option<String>,
|
||
|
url: Option<String>,
|
||
|
) -> Self {
|
||
|
Invitation::V0(InvitationV0 {
|
||
|
bootstrap,
|
||
|
code: Some(SymKey::random()),
|
||
|
name,
|
||
|
url,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
pub fn new_v0_free(
|
||
|
bootstrap: BootstrapContentV0,
|
||
|
name: Option<String>,
|
||
|
url: Option<String>,
|
||
|
) -> Self {
|
||
|
Invitation::V0(InvitationV0 {
|
||
|
bootstrap,
|
||
|
code: None,
|
||
|
name,
|
||
|
url,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
pub fn intersects(&self, invite2: Invitation) -> Invitation {
|
||
|
let Invitation::V0(v0) = self;
|
||
|
let mut new_invite = InvitationV0 {
|
||
1 year ago
|
bootstrap: BootstrapContentV0::new(),
|
||
2 years ago
|
code: v0.code.clone(),
|
||
|
name: v0.name.clone(),
|
||
|
url: v0.url.clone(),
|
||
|
};
|
||
|
for server2 in invite2.get_servers() {
|
||
|
for server1 in &v0.bootstrap.servers {
|
||
|
if *server1 == *server2 {
|
||
|
new_invite.bootstrap.servers.push(server2.clone());
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
Invitation::V0(new_invite)
|
||
|
}
|
||
|
|
||
|
pub fn get_servers(&self) -> &Vec<BrokerServerV0> {
|
||
|
match self {
|
||
|
Invitation::V0(v0) => &v0.bootstrap.servers,
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
pub fn set_name(&mut self, name: Option<String>) {
|
||
|
if name.is_some() {
|
||
|
match self {
|
||
|
Invitation::V0(v0) => v0.name = Some(name.unwrap()),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
pub fn set_url(&mut self, url: Option<&String>) {
|
||
|
if url.is_some() {
|
||
|
match self {
|
||
|
Invitation::V0(v0) => v0.url = Some(url.unwrap().clone()),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
/// first URL in the list is the ngone one
|
||
|
pub fn get_urls(&self) -> Vec<String> {
|
||
|
match self {
|
||
|
Invitation::V0(v0) => {
|
||
|
let mut res = vec![];
|
||
|
let ser = serde_bare::to_vec(&self).unwrap();
|
||
|
let url_param = base64_url::encode(&ser);
|
||
|
res.push(format!("{}/#/i/{}", NG_ONE_URL, url_param));
|
||
|
for server in &v0.bootstrap.servers {
|
||
|
match &server.server_type {
|
||
|
BrokerServerTypeV0::Domain(domain) => {
|
||
|
res.push(format!("https://{}/#/i/{}", domain, url_param));
|
||
|
}
|
||
|
BrokerServerTypeV0::BoxPrivate(addrs) => {
|
||
|
for bindaddr in addrs {
|
||
|
res.push(format!(
|
||
|
"http://{}:{}/#/i/{}",
|
||
|
bindaddr.ip, bindaddr.port, url_param
|
||
|
));
|
||
|
}
|
||
|
}
|
||
|
BrokerServerTypeV0::Localhost(port) => {
|
||
|
res.push(format!("{}/#/i/{}", local_http_url(&port), url_param));
|
||
|
}
|
||
|
_ => {}
|
||
|
}
|
||
|
}
|
||
|
res
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
impl fmt::Display for Invitation {
|
||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
|
let ser = serde_bare::to_vec(&self).unwrap();
|
||
|
let string = base64_url::encode(&ser);
|
||
|
write!(f, "{}", string)
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
impl TryFrom<String> for Invitation {
|
||
|
type Error = NgError;
|
||
|
fn try_from(value: String) -> Result<Self, NgError> {
|
||
|
let ser = base64_url::decode(&value).map_err(|_| NgError::InvalidInvitation)?;
|
||
|
let invite: Invitation =
|
||
|
serde_bare::from_slice(&ser).map_err(|_| NgError::InvalidInvitation)?;
|
||
|
Ok(invite)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Invitation to create an account at a broker.
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum Invitation {
|
||
|
V0(InvitationV0),
|
||
|
}
|
||
|
|
||
1 year ago
|
// impl From<BootstrapContent> for Invitation {
|
||
|
// fn from(value: BootstrapContent) -> Self {
|
||
|
// let BootstrapContent::V0(boot) = value;
|
||
|
// let name = boot.get_domain();
|
||
|
// Invitation::V0(InvitationV0 {
|
||
|
// bootstrap: boot,
|
||
|
// code: None,
|
||
|
// name,
|
||
|
// url: None,
|
||
|
// })
|
||
|
// }
|
||
|
// }
|
||
2 years ago
|
|
||
|
/// Create an account at a Broker Service Provider (BSP).
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CreateAccountBSP {
|
||
|
V0(CreateAccountBSPV0),
|
||
|
}
|
||
|
|
||
|
impl TryFrom<String> for CreateAccountBSP {
|
||
|
type Error = NgError;
|
||
|
fn try_from(value: String) -> Result<Self, NgError> {
|
||
|
let ser = base64_url::decode(&value).map_err(|_| NgError::InvalidCreateAccount)?;
|
||
|
let invite: CreateAccountBSP =
|
||
|
serde_bare::from_slice(&ser).map_err(|_| NgError::InvalidCreateAccount)?;
|
||
|
Ok(invite)
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
impl CreateAccountBSP {
|
||
|
pub fn encode(&self) -> Option<String> {
|
||
|
let payload_ser = serde_bare::to_vec(self).ok();
|
||
|
if payload_ser.is_none() {
|
||
|
return None;
|
||
|
}
|
||
|
Some(base64_url::encode(&payload_ser.unwrap()))
|
||
|
}
|
||
2 years ago
|
// pub fn user(&self) -> PubKey {
|
||
|
// match self {
|
||
|
// Self::V0(v0) => v0.user,
|
||
|
// }
|
||
|
// }
|
||
2 years ago
|
pub fn redirect_url(&self) -> &Option<String> {
|
||
|
match self {
|
||
|
Self::V0(v0) => &v0.redirect_url,
|
||
|
}
|
||
|
}
|
||
2 years ago
|
// pub fn invitation(&self) -> &Option<InvitationV0> {
|
||
|
// match self {
|
||
|
// Self::V0(v0) => &v0.invitation,
|
||
|
// }
|
||
|
// }
|
||
|
// pub fn additional_bootstrap(&mut self) -> &mut Option<BootstrapContentV0> {
|
||
|
// match self {
|
||
|
// Self::V0(v0) => &mut v0.additional_bootstrap,
|
||
|
// }
|
||
|
// }
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
/// Create an account at a Broker Service Provider (BSP). Version 0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct CreateAccountBSPV0 {
|
||
2 years ago
|
//pub invitation: Option<InvitationV0>,
|
||
2 years ago
|
|
||
2 years ago
|
//pub additional_bootstrap: Option<BootstrapContentV0>,
|
||
2 years ago
|
/// the user asking to create an account
|
||
2 years ago
|
//pub user: PubKey,
|
||
2 years ago
|
|
||
2 years ago
|
/// signature over serialized invitation code, with user key
|
||
|
// pub sig: Sig,
|
||
2 years ago
|
|
||
2 years ago
|
/// for web access, will redirect after successful signup. if left empty, it means user was on native app.
|
||
2 years ago
|
pub redirect_url: Option<String>,
|
||
|
}
|
||
|
|
||
2 years ago
|
/// ListenerInfo
|
||
|
#[cfg(not(target_arch = "wasm32"))]
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct ListenerInfo {
|
||
|
pub config: ListenerV0,
|
||
|
|
||
|
/// list of BindAddresses
|
||
|
pub addrs: Vec<BindAddress>,
|
||
|
}
|
||
|
|
||
|
/// AcceptForwardForV0 type
|
||
|
/// allow answers to connection requests originating from a client behind a reverse proxy
|
||
|
/// 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
|
||
|
/// Empty string means all addresses are accepted
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||
|
pub enum AcceptForwardForV0 {
|
||
|
/// X-Forwarded-For not allowed
|
||
|
No,
|
||
|
|
||
|
/// X-Forwarded-For accepted only for clients with private LAN addresses. First param is the domain of the proxy server
|
||
|
PrivateDomain((String, String)),
|
||
|
|
||
|
/// X-Forwarded-For accepted only for clients with public addresses. First param is the domain of the proxy server
|
||
|
/// domain can take an option port (trailing `:port`)
|
||
|
PublicDomain((String, String)),
|
||
|
|
||
|
/// X-Forwarded-For accepted only for clients with public addresses. First param is the domain of the proxy server
|
||
11 months ago
|
/// domain can take an optional port (trailing `:port`)
|
||
2 years ago
|
/// second param is the privKey of the PeerId of the proxy server, useful when the proxy server is load balancing to several daemons
|
||
|
/// that should all use the same PeerId to answer requests
|
||
|
PublicDomainPeer((String, PrivKey, String)),
|
||
|
|
||
|
/// accepts only clients with public addresses that arrive on a LAN address binding. This is used for DMZ and port forwarding configs
|
||
|
/// first param is the port, second param in tuple is the interval for periodic probe of the external IP
|
||
|
PublicDyn((u16, u32, String)),
|
||
|
|
||
|
/// accepts only clients with public addresses that arrive on a LAN address binding. This is used for DMZ and port forwarding configs
|
||
|
/// First param is the IPv4 bind address of the reverse NAT server (DMZ, port forwarding)
|
||
|
/// Second param is an optional IPv6 bind address of the reverse NAT server (DMZ, port forwarding)
|
||
|
PublicStatic((BindAddress, Option<BindAddress>, String)),
|
||
|
}
|
||
|
|
||
|
impl AcceptForwardForV0 {
|
||
|
pub fn get_public_bind_addresses(&self) -> Vec<BindAddress> {
|
||
|
match self {
|
||
|
AcceptForwardForV0::PublicStatic((ipv4, ipv6, _)) => {
|
||
|
let mut res = vec![ipv4.clone()];
|
||
|
if ipv6.is_some() {
|
||
|
res.push(ipv6.unwrap().clone())
|
||
|
}
|
||
|
res
|
||
|
}
|
||
|
AcceptForwardForV0::PublicDyn(_) => {
|
||
|
todo!();
|
||
|
}
|
||
|
_ => panic!("cannot call get_public_bind_addresses"),
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
pub fn get_public_bind_ipv6_address(&self) -> Option<IP> {
|
||
|
match self {
|
||
11 months ago
|
AcceptForwardForV0::PublicStatic((_ipv4, ipv6, _)) => {
|
||
|
//let _res = vec![ipv4.clone()];
|
||
2 years ago
|
if ipv6.is_some() {
|
||
|
return Some(ipv6.unwrap().ip.clone());
|
||
|
} else {
|
||
|
return None;
|
||
|
}
|
||
|
}
|
||
|
AcceptForwardForV0::PublicDyn(_) => {
|
||
|
todo!();
|
||
|
}
|
||
|
_ => None,
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
pub fn is_public_domain(&self) -> bool {
|
||
|
match self {
|
||
|
AcceptForwardForV0::PublicDomainPeer(_) => true,
|
||
|
AcceptForwardForV0::PublicDomain(_) => true,
|
||
|
_ => false,
|
||
|
}
|
||
|
}
|
||
|
pub fn is_public_static(&self) -> bool {
|
||
|
match self {
|
||
|
AcceptForwardForV0::PublicStatic(_) => true,
|
||
|
_ => false,
|
||
|
}
|
||
|
}
|
||
2 years ago
|
pub fn is_no(&self) -> bool {
|
||
|
match self {
|
||
|
AcceptForwardForV0::No => true,
|
||
|
_ => false,
|
||
|
}
|
||
|
}
|
||
2 years ago
|
pub fn is_public_dyn(&self) -> bool {
|
||
|
match self {
|
||
|
AcceptForwardForV0::PublicDyn(_) => true,
|
||
|
_ => false,
|
||
|
}
|
||
|
}
|
||
|
pub fn is_private_domain(&self) -> bool {
|
||
|
match self {
|
||
|
AcceptForwardForV0::PrivateDomain(_) => true,
|
||
|
_ => false,
|
||
|
}
|
||
|
}
|
||
2 years ago
|
pub fn domain_with_common_peer_id(&self) -> Option<PubKey> {
|
||
|
match self {
|
||
|
AcceptForwardForV0::PublicDomainPeer((_, privkey, _)) => Some(privkey.to_pub()),
|
||
|
_ => None,
|
||
|
}
|
||
|
}
|
||
2 years ago
|
pub fn get_domain(&self) -> &str {
|
||
|
let domain = get_domain_without_port_443(match self {
|
||
|
AcceptForwardForV0::PrivateDomain((d, _)) => d,
|
||
|
AcceptForwardForV0::PublicDomain((d, _)) => d,
|
||
|
AcceptForwardForV0::PublicDomainPeer((d, _, _)) => d,
|
||
|
_ => panic!("cannot call get_domain if AcceptForwardForV0 is not a domain"),
|
||
|
});
|
||
|
//let mut url = "https://".to_string();
|
||
|
//url.push_str(domain);
|
||
|
domain
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[cfg(not(target_arch = "wasm32"))]
|
||
|
/// DaemonConfig Listener Version 0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct ListenerV0 {
|
||
|
/// local interface name to bind to
|
||
|
/// names of interfaces can be retrieved with the --list-interfaces option
|
||
|
pub interface_name: String,
|
||
|
|
||
|
pub if_type: InterfaceType,
|
||
|
|
||
|
/// optional number of seconds for an interval of periodic refresh
|
||
|
/// of the actual IP(s) of the interface. Used for dynamic IP interfaces (DHCP)
|
||
|
pub interface_refresh: u32,
|
||
|
|
||
|
// if to bind to the ipv6 address of the interface
|
||
|
pub ipv6: bool,
|
||
|
|
||
|
/// local port to listen on
|
||
|
pub port: u16,
|
||
|
|
||
11 months ago
|
/// force a private or localhost interface to be accepted as a core interface
|
||
|
pub private_core: bool,
|
||
|
|
||
2 years ago
|
/// 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
|
||
|
pub serve_app: bool,
|
||
|
|
||
2 years ago
|
/// 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
|
||
2 years ago
|
pub bind_public_ipv6: bool,
|
||
2 years ago
|
|
||
11 months ago
|
/// 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.
|
||
2 years ago
|
/// 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 app.nextgraph.one
|
||
|
pub refuse_clients: bool,
|
||
|
|
||
|
// 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.
|
||
|
pub discoverable: bool,
|
||
|
|
||
|
/// Answers to connection requests originating from a direct client, without X-Forwarded-For headers
|
||
|
/// 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
|
||
|
pub accept_direct: bool,
|
||
|
|
||
|
/// X-Forwarded-For config. only valid if IP/interface is localhost or private
|
||
|
pub accept_forward_for: AcceptForwardForV0,
|
||
|
// impl fn is_private()
|
||
|
// returns false if public IP in interface, or if PublicDyn, PublicStatic
|
||
|
|
||
|
// an interface with no accept_forward_for and no accept_direct, is de facto, disabled
|
||
|
}
|
||
|
|
||
|
#[cfg(not(target_arch = "wasm32"))]
|
||
|
impl ListenerV0 {
|
||
2 years ago
|
pub fn should_bind_public_ipv6_to_private_interface(&self, ip: Ipv6Addr) -> bool {
|
||
|
let public_ip = self.accept_forward_for.get_public_bind_ipv6_address();
|
||
|
if public_ip.is_none() {
|
||
|
return false;
|
||
|
}
|
||
|
let public_ipv6addr: IpAddr = public_ip.as_ref().unwrap().into();
|
||
|
return if let IpAddr::V6(v6) = public_ipv6addr {
|
||
2 years ago
|
self.bind_public_ipv6 && self.if_type == InterfaceType::Private && ip == v6
|
||
2 years ago
|
} else {
|
||
|
false
|
||
|
};
|
||
|
}
|
||
|
|
||
2 years ago
|
pub fn new_direct(interface: Interface, ipv6: bool, port: u16) -> Self {
|
||
|
Self {
|
||
|
interface_name: interface.name,
|
||
|
if_type: interface.if_type,
|
||
|
interface_refresh: 0,
|
||
|
ipv6,
|
||
|
port,
|
||
11 months ago
|
private_core: false,
|
||
2 years ago
|
discoverable: false,
|
||
|
accept_direct: true,
|
||
|
refuse_clients: false,
|
||
|
serve_app: true,
|
||
2 years ago
|
bind_public_ipv6: false,
|
||
2 years ago
|
accept_forward_for: AcceptForwardForV0::No,
|
||
|
}
|
||
|
}
|
||
2 years ago
|
|
||
2 years ago
|
pub fn is_core(&self) -> bool {
|
||
|
match self.accept_forward_for {
|
||
|
AcceptForwardForV0::PublicStatic(_) => true,
|
||
|
AcceptForwardForV0::PublicDyn(_) => true,
|
||
|
AcceptForwardForV0::PublicDomain(_) | AcceptForwardForV0::PublicDomainPeer(_) => false,
|
||
|
AcceptForwardForV0::PrivateDomain(_) => false,
|
||
11 months ago
|
AcceptForwardForV0::No => {
|
||
|
self.if_type == InterfaceType::Public
|
||
|
|| (self.private_core && self.if_type != InterfaceType::Invalid)
|
||
|
}
|
||
2 years ago
|
}
|
||
|
}
|
||
|
|
||
|
pub fn accepts_client(&self) -> bool {
|
||
|
match self.accept_forward_for {
|
||
|
AcceptForwardForV0::PublicStatic(_)
|
||
|
| AcceptForwardForV0::PublicDyn(_)
|
||
|
| AcceptForwardForV0::PublicDomain(_)
|
||
|
| AcceptForwardForV0::PublicDomainPeer(_) => self.accept_direct || !self.refuse_clients,
|
||
|
AcceptForwardForV0::PrivateDomain(_) => true,
|
||
|
AcceptForwardForV0::No => {
|
||
|
self.if_type == InterfaceType::Public && !self.refuse_clients
|
||
|
|| self.if_type != InterfaceType::Public
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
pub fn get_bootstraps(&self, addrs: Vec<BindAddress>) -> Vec<BrokerServerTypeV0> {
|
||
|
let mut res: Vec<BrokerServerTypeV0> = vec![];
|
||
|
match self.accept_forward_for {
|
||
|
AcceptForwardForV0::PublicStatic(_) => {
|
||
2 years ago
|
let pub_addrs = self.accept_forward_for.get_public_bind_addresses();
|
||
|
//res.push(BrokerServerTypeV0::Core(pub_addrs.clone()));
|
||
2 years ago
|
if !self.refuse_clients {
|
||
11 months ago
|
res.push(BrokerServerTypeV0::Public(pub_addrs));
|
||
2 years ago
|
}
|
||
|
if self.accept_direct {
|
||
|
res.push(BrokerServerTypeV0::BoxPrivate(addrs));
|
||
|
}
|
||
|
}
|
||
|
AcceptForwardForV0::PublicDyn(_) => {
|
||
2 years ago
|
let pub_addrs = self.accept_forward_for.get_public_bind_addresses();
|
||
|
//res.push(BrokerServerTypeV0::Core(pub_addrs.clone()));
|
||
2 years ago
|
if !self.refuse_clients {
|
||
2 years ago
|
res.push(BrokerServerTypeV0::BoxPublicDyn(pub_addrs));
|
||
2 years ago
|
}
|
||
|
if self.accept_direct {
|
||
|
res.push(BrokerServerTypeV0::BoxPrivate(addrs));
|
||
|
}
|
||
|
}
|
||
|
AcceptForwardForV0::PublicDomain(_) | AcceptForwardForV0::PublicDomainPeer(_) => {
|
||
2 years ago
|
if !self.refuse_clients {
|
||
|
res.push(BrokerServerTypeV0::Domain(
|
||
|
self.accept_forward_for.get_domain().to_string(),
|
||
|
));
|
||
|
}
|
||
1 year ago
|
//// 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.
|
||
|
// if self.accept_direct {
|
||
|
// if self.if_type == InterfaceType::Private {
|
||
|
// res.push(BrokerServerTypeV0::BoxPrivate(addrs));
|
||
|
// } else if self.if_type == InterfaceType::Loopback {
|
||
|
// res.push(BrokerServerTypeV0::Localhost(addrs[0].port));
|
||
|
// }
|
||
|
// }
|
||
2 years ago
|
}
|
||
|
AcceptForwardForV0::PrivateDomain(_) => {
|
||
|
res.push(BrokerServerTypeV0::Domain(
|
||
|
self.accept_forward_for.get_domain().to_string(),
|
||
|
));
|
||
|
}
|
||
|
AcceptForwardForV0::No => {
|
||
|
if self.if_type == InterfaceType::Loopback {
|
||
|
res.push(BrokerServerTypeV0::Localhost(addrs[0].port));
|
||
2 years ago
|
} else if self.if_type == InterfaceType::Public {
|
||
|
//res.push(BrokerServerTypeV0::Core(addrs.clone()));
|
||
|
if !self.refuse_clients {
|
||
11 months ago
|
res.push(BrokerServerTypeV0::Public(addrs));
|
||
2 years ago
|
}
|
||
2 years ago
|
} else if self.if_type == InterfaceType::Private {
|
||
|
res.push(BrokerServerTypeV0::BoxPrivate(addrs));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
res
|
||
|
}
|
||
2 years ago
|
}
|
||
|
#[cfg(not(target_arch = "wasm32"))]
|
||
|
impl fmt::Display for ListenerV0 {
|
||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
|
let mut id = self.interface_name.clone();
|
||
|
id.push('@');
|
||
|
id.push_str(&self.port.to_string());
|
||
|
write!(f, "{}", id)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Broker Overlay Permission
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||
|
pub enum BrokerOverlayPermission {
|
||
|
Nobody,
|
||
|
Anybody,
|
||
|
AllRegisteredUser,
|
||
|
UsersList(Vec<UserId>),
|
||
|
}
|
||
|
|
||
|
/// Broker Overlay Config
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||
|
pub struct BrokerOverlayConfigV0 {
|
||
|
// list of overlays this config applies to. empty array means applying to all
|
||
|
pub overlays: Vec<OverlayId>,
|
||
|
// Who can ask to join an overlay on the core
|
||
|
pub core: BrokerOverlayPermission,
|
||
|
// Who can connect as a client to this server
|
||
|
pub server: BrokerOverlayPermission,
|
||
|
// if core == Nobody and server == Nobody then the listeners will not be started
|
||
|
|
||
|
// are ExtRequest allowed on the server? this requires the core to be ON.
|
||
|
pub allow_read: bool,
|
||
|
|
||
|
/// an empty list means to forward to the peer known for each overlay.
|
||
|
/// forward and core are mutually exclusive. forward becomes the default when core is disabled (set to Nobody).
|
||
|
/// core always takes precedence.
|
||
|
pub forward: Vec<BrokerServerV0>,
|
||
|
}
|
||
|
|
||
|
impl BrokerOverlayConfigV0 {
|
||
|
pub fn new() -> Self {
|
||
|
BrokerOverlayConfigV0 {
|
||
|
overlays: vec![],
|
||
|
core: BrokerOverlayPermission::Nobody,
|
||
|
server: BrokerOverlayPermission::Nobody,
|
||
|
allow_read: false,
|
||
|
forward: vec![],
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
/// Registration config
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum RegistrationConfig {
|
||
|
Closed,
|
||
|
Invitation,
|
||
|
Open,
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Overlay Access
|
||
2 years ago
|
///
|
||
11 months ago
|
/// Used by the Client when opening or pinning a repo.
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||
|
pub enum OverlayAccess {
|
||
|
/// The repo will be accessed on the Outer Overlay in Read Only mode
|
||
|
/// This can be used for Public, Protected or Group overlays
|
||
|
/// Value should be an OverlayId::Outer
|
||
|
ReadOnly(OverlayId),
|
||
|
/// The repo will be accessed on the Inner Overlay in Write mode, and the associated Outer overlay is also given
|
||
|
/// This is used for Public, Protected and Group overlays
|
||
|
/// First value in tuple should be the OverlayId::Inner, second the OverlayId::Outer
|
||
|
ReadWrite((OverlayId, OverlayId)),
|
||
|
/// The repo will be accessed on the Inner Overlay in Write mode, and it doesn't have an Outer overlay
|
||
|
/// This is used for Private and Dialog overlays
|
||
|
/// Value should be an OverlayId::Inner
|
||
|
WriteOnly(OverlayId),
|
||
|
}
|
||
|
|
||
|
impl OverlayAccess {
|
||
|
pub fn new_ro(outer_overlay: OverlayId) -> Result<Self, NgError> {
|
||
|
if let OverlayId::Outer(_digest) = outer_overlay {
|
||
|
Ok(OverlayAccess::ReadOnly(outer_overlay))
|
||
|
} else {
|
||
|
Err(NgError::InvalidArgument)
|
||
|
}
|
||
|
}
|
||
|
pub fn new_rw(inner_overlay: OverlayId, outer_overlay: OverlayId) -> Result<Self, NgError> {
|
||
|
if let OverlayId::Inner(_digest) = inner_overlay {
|
||
|
if let OverlayId::Outer(_digest) = outer_overlay {
|
||
|
Ok(OverlayAccess::ReadWrite((inner_overlay, outer_overlay)))
|
||
|
} else {
|
||
|
Err(NgError::InvalidArgument)
|
||
|
}
|
||
|
} else {
|
||
|
Err(NgError::InvalidArgument)
|
||
|
}
|
||
|
}
|
||
|
pub fn new_wo(inner_overlay: OverlayId) -> Result<Self, NgError> {
|
||
|
if let OverlayId::Inner(_digest) = inner_overlay {
|
||
|
Ok(OverlayAccess::WriteOnly(inner_overlay))
|
||
|
} else {
|
||
|
Err(NgError::InvalidArgument)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Inner Overlay Link
|
||
|
///
|
||
|
/// Details of the inner overlay of an NgLink
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||
|
pub struct InnerOverlayLink {
|
||
|
/// overlay public key ID
|
||
11 months ago
|
pub id: StoreOverlay,
|
||
2 years ago
|
|
||
11 months ago
|
/// The store has a special branch called `overlay` that is used to manage access to the InnerOverlay
|
||
|
/// only the ReadCapSecret is needed to access the InnerOverlay
|
||
|
/// 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
|
||
10 months ago
|
/// 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 refreshReadCap on the overlay
|
||
11 months ago
|
/// if the user is an external user to the store, it will lose access to the InnerOverlay after a RefreshReadCap of the overlay branch of the store.
|
||
|
pub store_overlay_readcap: ReadCap,
|
||
11 months ago
|
}
|
||
|
|
||
|
/// Overlay Link
|
||
|
///
|
||
|
/// Details of the overlay of an NgLink
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||
|
pub enum OverlayLink {
|
||
11 months ago
|
Outer(StoreOverlay),
|
||
11 months ago
|
Inner(InnerOverlayLink),
|
||
|
Inherit,
|
||
|
}
|
||
2 years ago
|
|
||
11 months ago
|
/// Overlay session ID
|
||
|
///
|
||
|
/// It is a pubkey used for signing all OverlayMessage sent by the peer.
|
||
|
/// Each peer generates it randomly when (re)joining the overlay network.
|
||
|
pub type SessionId = PubKey;
|
||
2 years ago
|
|
||
|
/// Client ID: client of a user
|
||
|
pub type ClientId = PubKey;
|
||
|
|
||
|
/// IPv4 address
|
||
|
pub type IPv4 = [u8; 4];
|
||
|
|
||
|
/// IPv6 address
|
||
|
pub type IPv6 = [u8; 16];
|
||
|
|
||
|
/// IP address
|
||
2 years ago
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||
2 years ago
|
pub enum IP {
|
||
|
IPv4(IPv4),
|
||
|
IPv6(IPv6),
|
||
|
}
|
||
|
|
||
2 years ago
|
impl IP {
|
||
|
pub fn is_public(&self) -> bool {
|
||
|
is_public_ip(&self.into())
|
||
|
}
|
||
|
pub fn is_private(&self) -> bool {
|
||
|
is_private_ip(&self.into())
|
||
|
}
|
||
|
pub fn is_loopback(&self) -> bool {
|
||
|
let t: &IpAddr = &self.into();
|
||
|
t.is_loopback()
|
||
|
}
|
||
2 years ago
|
pub fn is_v6(&self) -> bool {
|
||
|
if let Self::IPv6(_) = self {
|
||
|
true
|
||
|
} else {
|
||
|
false
|
||
|
}
|
||
|
}
|
||
|
pub fn is_v4(&self) -> bool {
|
||
|
if let Self::IPv4(_) = self {
|
||
|
true
|
||
|
} else {
|
||
|
false
|
||
|
}
|
||
|
}
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
impl fmt::Display for IP {
|
||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
|
let t: IpAddr = self.try_into().unwrap();
|
||
2 years ago
|
match self {
|
||
|
IP::IPv4(_) => write!(f, "{}", t),
|
||
|
IP::IPv6(_) => write!(f, "[{}]", t),
|
||
|
}
|
||
2 years ago
|
}
|
||
|
}
|
||
|
|
||
|
impl From<&IpAddr> for IP {
|
||
|
#[inline]
|
||
|
fn from(ip: &IpAddr) -> IP {
|
||
|
match ip {
|
||
|
IpAddr::V4(v4) => IP::IPv4(v4.octets()),
|
||
|
IpAddr::V6(v6) => IP::IPv6(v6.octets()),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl From<&IP> for IpAddr {
|
||
|
#[inline]
|
||
|
fn from(ip: &IP) -> IpAddr {
|
||
|
match ip {
|
||
|
IP::IPv4(v4) => IpAddr::from(*v4),
|
||
|
IP::IPv6(v6) => IpAddr::from(*v6),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
/// IP transport protocol
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||
2 years ago
|
pub enum TransportProtocol {
|
||
|
WS,
|
||
2 years ago
|
QUIC,
|
||
2 years ago
|
Local,
|
||
2 years ago
|
}
|
||
|
|
||
|
/// IP transport address
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||
|
pub struct IPTransportAddr {
|
||
|
pub ip: IP,
|
||
|
pub port: u16,
|
||
2 years ago
|
pub protocol: TransportProtocol,
|
||
2 years ago
|
}
|
||
|
|
||
|
/// Network address
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||
|
pub enum NetAddr {
|
||
|
IPTransport(IPTransportAddr),
|
||
|
}
|
||
|
|
||
2 years ago
|
/**
|
||
|
* info : {
|
||
|
type : WEB | NATIVE-IOS | NATIVE-ANDROID | NATIVE-MACOS | NATIVE-LINUX | NATIVE-WIN
|
||
|
NATIVE-SERVICE | NODE-SERVICE | VERIFIER | CLIENT-BROKER | CLI
|
||
|
vendor : (UA, node version, tauri webview, rust version)
|
||
|
os : operating system string
|
||
|
version : version of client
|
||
|
date_install
|
||
|
date_updated : last update
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
/// Client Type
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||
|
pub enum ClientType {
|
||
|
Web,
|
||
|
NativeIos,
|
||
|
NativeAndroid,
|
||
|
NativeMacOS,
|
||
|
NativeLinux,
|
||
|
NativeWin,
|
||
|
NativeService,
|
||
|
NodeService,
|
||
|
Verifier,
|
||
10 months ago
|
Box,
|
||
|
Stick,
|
||
|
WalletMaster,
|
||
2 years ago
|
ClientBroker,
|
||
|
Cli,
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||
|
pub struct ClientInfoV0 {
|
||
|
pub client_type: ClientType,
|
||
|
pub details: String,
|
||
|
pub version: String,
|
||
|
pub timestamp_install: u64,
|
||
|
pub timestamp_updated: u64,
|
||
|
}
|
||
|
|
||
|
/// Client Info
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||
|
pub enum ClientInfo {
|
||
|
V0(ClientInfoV0),
|
||
|
}
|
||
|
|
||
|
impl ClientInfo {
|
||
|
pub fn new(client_type: ClientType, details: String, version: String) -> ClientInfo {
|
||
|
let timestamp_install = SystemTime::now()
|
||
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||
|
.unwrap()
|
||
|
.as_secs();
|
||
|
ClientInfo::V0(ClientInfoV0 {
|
||
|
details,
|
||
|
version,
|
||
|
client_type,
|
||
|
timestamp_install,
|
||
|
timestamp_updated: timestamp_install,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
//
|
||
|
// OVERLAY MESSAGES
|
||
|
//
|
||
|
|
||
11 months ago
|
/// Overlay leave request
|
||
2 years ago
|
///
|
||
11 months ago
|
/// In outerOverlay: informs the broker that the overlay is not needed anymore
|
||
11 months ago
|
/// In innerOverlay: Sent to all connected overlay participants to terminate a session
|
||
2 years ago
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub enum OverlayLeave {
|
||
2 years ago
|
V0(),
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Content of PublisherAdvertV0
|
||
|
/// the peer is matched with the InnerOverlayMessageV0.Session -> peerId.
|
||
2 years ago
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub struct PublisherAdvertContentV0 {
|
||
2 years ago
|
/// Topic public key
|
||
|
pub topic: TopicId,
|
||
|
|
||
|
/// Peer public key
|
||
11 months ago
|
pub peer: DirectPeerId,
|
||
2 years ago
|
}
|
||
|
|
||
|
/// Topic advertisement by a publisher
|
||
|
///
|
||
|
/// Flooded to all peers in overlay
|
||
|
/// Creates subscription routing table entries
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub struct PublisherAdvertV0 {
|
||
|
pub content: PublisherAdvertContentV0,
|
||
2 years ago
|
|
||
|
/// Signature over content by topic key
|
||
|
pub sig: Sig,
|
||
|
}
|
||
|
|
||
|
/// Topic advertisement by a publisher
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub enum PublisherAdvert {
|
||
|
V0(PublisherAdvertV0),
|
||
2 years ago
|
}
|
||
|
|
||
|
/// Topic subscription request by a peer
|
||
|
///
|
||
|
/// Forwarded towards all publishers along subscription routing table entries
|
||
11 months ago
|
/// that are created by PublisherAdverts
|
||
2 years ago
|
/// Creates event routing table entries along the path
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
|
pub struct SubReqV0 {
|
||
|
/// Topic public key
|
||
|
pub topic: TopicId,
|
||
11 months ago
|
|
||
|
/// For initial subscription, should be None,
|
||
|
/// When updating a subscription after a new publisher has joined (with a PublisherAdvert),
|
||
|
/// then the target publisher should be entered here.
|
||
|
/// The brokers will only forward the SubscriptionRequest to that publisher (on all available paths)
|
||
|
pub publisher: Option<DirectPeerId>,
|
||
2 years ago
|
}
|
||
|
|
||
|
/// Topic subscription request by a peer
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
|
pub enum SubReq {
|
||
|
V0(SubReqV0),
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Topic subscription marker sent by all publishers, back to subscriber
|
||
2 years ago
|
///
|
||
11 months ago
|
/// Forwarded to all subscribers.
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct SubMarkerV0 {
|
||
|
/// The publisher broker that marks its starting cut
|
||
|
/// TODO: that could be omitted, because we can retrieve it with the SessionId
|
||
|
pub publisher: DirectPeerId,
|
||
|
|
||
|
/// The subscribed topic
|
||
|
pub topic: TopicId,
|
||
|
|
||
|
/// The subscriber
|
||
|
pub subscriber: DirectPeerId,
|
||
|
|
||
|
/// Current heads at the broker when receiving the SubReq. Can be used to safely do a CoreTopicSyncReq
|
||
|
pub known_heads: Vec<ObjectId>,
|
||
2 years ago
|
}
|
||
|
|
||
|
/// Topic subscription acknowledgement by a publisher
|
||
11 months ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum SubMarker {
|
||
|
V0(SubMarkerV0),
|
||
2 years ago
|
}
|
||
|
|
||
|
/// Topic unsubscription request by a subscriber
|
||
|
///
|
||
11 months ago
|
/// A broker unsubscribes from all publisher brokers in the overlay
|
||
|
/// when it has no more local subscribers left
|
||
2 years ago
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
|
pub struct UnsubReqV0 {
|
||
|
/// Topic public key
|
||
|
pub topic: TopicId,
|
||
|
}
|
||
|
|
||
|
/// Topic unsubscription request by a subscriber
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
|
pub enum UnsubReq {
|
||
|
V0(UnsubReqV0),
|
||
|
}
|
||
|
|
||
|
/// Object search in a pub/sub topic
|
||
|
///
|
||
|
/// Sent along the reverse path of a pub/sub topic
|
||
11 months ago
|
/// from a subscriber to one publisher at a time.
|
||
|
/// fanout is always 1
|
||
|
/// if result is none, tries another path if several paths available locally
|
||
11 months ago
|
/// answered with a stream of BlockResult
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct BlockSearchTopicV0 {
|
||
|
/// Topic to forward the request in
|
||
|
pub topic: TopicId,
|
||
|
|
||
11 months ago
|
/// Also search in subscribers
|
||
|
pub search_in_subs: bool,
|
||
|
|
||
2 years ago
|
/// List of Object IDs to request
|
||
|
pub ids: Vec<ObjectId>,
|
||
|
|
||
|
/// Whether or not to include all children recursively in the response
|
||
|
pub include_children: bool,
|
||
|
|
||
|
/// List of Peer IDs the request traversed so far
|
||
|
pub path: Vec<PeerId>,
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Object request by ID to publishers
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum BlockSearchTopic {
|
||
|
V0(BlockSearchTopicV0),
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Block search along a random walk in the overlay
|
||
|
/// fanout is always 1
|
||
|
/// if result is none, tries another path if several paths available locally
|
||
11 months ago
|
/// answered with a stream BlockResult
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct BlockSearchRandomV0 {
|
||
|
/// List of Block IDs to request
|
||
|
pub ids: Vec<BlockId>,
|
||
|
|
||
|
/// Whether or not to include all children recursively in the response
|
||
|
pub include_children: bool,
|
||
|
|
||
|
/// Number of random nodes to forward the request to at each step
|
||
11 months ago
|
// pub fanout: u8,
|
||
|
// for now fanout is always 1
|
||
2 years ago
|
|
||
11 months ago
|
/// List of Broker Peer IDs the request traversed so far
|
||
|
pub path: Vec<DirectPeerId>,
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Block request by ID using a random walk in the overlay
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum BlockSearchRandom {
|
||
|
V0(BlockSearchRandomV0),
|
||
|
}
|
||
|
|
||
|
/// Response to a BlockSearch* request
|
||
11 months ago
|
/// can be a stream
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct BlockResultV0 {
|
||
11 months ago
|
/// Resulting Blocks(s)
|
||
2 years ago
|
pub payload: Vec<Block>,
|
||
|
}
|
||
|
|
||
|
/// Response to a BlockSearch* request
|
||
11 months ago
|
/// can be a stream
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum BlockResult {
|
||
|
V0(BlockResultV0),
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Topic synchronization request
|
||
2 years ago
|
///
|
||
11 months ago
|
/// In response a stream of `TopicSyncRes`s containing the missing Commits or events are sent
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub struct TopicSyncReqV0 {
|
||
|
/// Topic public key
|
||
|
pub topic: TopicId,
|
||
2 years ago
|
|
||
|
/// Fully synchronized until these commits
|
||
|
pub known_heads: Vec<ObjectId>,
|
||
|
|
||
11 months ago
|
/// Stop synchronizing when these commits are met.
|
||
|
/// if empty, the local HEAD at the responder is used instead
|
||
|
pub target_heads: Vec<ObjectId>,
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Topic synchronization request
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub enum TopicSyncReq {
|
||
|
V0(TopicSyncReqV0),
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
impl TopicSyncReq {
|
||
|
pub fn topic(&self) -> &TopicId {
|
||
2 years ago
|
match self {
|
||
11 months ago
|
TopicSyncReq::V0(o) => &o.topic,
|
||
2 years ago
|
}
|
||
|
}
|
||
|
pub fn known_heads(&self) -> &Vec<ObjectId> {
|
||
|
match self {
|
||
11 months ago
|
TopicSyncReq::V0(o) => &o.known_heads,
|
||
2 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Status of a Forwarded Peer, sent in the Advert
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub enum PeerStatus {
|
||
|
Connected,
|
||
|
Disconnected,
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// ForwardedPeerAdvertV0
|
||
|
/// peer_advert.forwarded_by is matched with sessionid->peerid
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub struct ForwardedPeerAdvertV0 {
|
||
|
/// PeerAdvert received from Client
|
||
11 months ago
|
// TODO: this could be obfuscated when user doesnt want to recall events.
|
||
11 months ago
|
pub peer_advert: PeerAdvertV0,
|
||
2 years ago
|
|
||
11 months ago
|
/// Hashed user Id, used to prevent concurrent connection from different brokers
|
||
|
/// BLAKE3 keyed hash over the UserId
|
||
11 months ago
|
/// - key: BLAKE3 derive_key ("NextGraph UserId Hash Overlay Id ForwardedPeerAdvertV0 BLAKE3 key", overlayId) // will always be an Inner overlay
|
||
11 months ago
|
pub user_hash: Digest,
|
||
2 years ago
|
|
||
11 months ago
|
/// whether the Advert is about connection or disconnection
|
||
|
pub status: PeerStatus,
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Forwarded Peer advertisement
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub enum ForwardedPeerAdvert {
|
||
|
V0(ForwardedPeerAdvertV0),
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// ForwardedPeerConflictV0
|
||
|
/// peer_advert.forwarded_by is matched with sessionid->peerid
|
||
10 months ago
|
/// When the forwarding broker receives the conflict (or notices it), it sends a notification
|
||
11 months ago
|
/// In order to avoid conflicts, the highest version of PeerAdvert should win, when the Forwarding Broker is different.
|
||
|
/// Disconnect wins over connect, for the exact same peer, version and forwarding broker.
|
||
|
/// Conflict can occur when same user_hash, on 2 different Forwarding Broker
|
||
|
/// Or when same peerId appears on 2 different Forwarding Broker.
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub struct ForwardedPeerConflictV0 {
|
||
|
/// First conflicting PeerAdvert
|
||
|
pub advert_1: ForwardedPeerAdvertV0,
|
||
|
/// Second conflicting PeerAdvert
|
||
|
pub advert_2: ForwardedPeerAdvertV0,
|
||
2 years ago
|
|
||
11 months ago
|
pub error_code: u16,
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Forwarded Peer advertisement conflict
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub enum ForwardedPeerConflict {
|
||
|
V0(ForwardedPeerConflictV0),
|
||
2 years ago
|
}
|
||
|
|
||
|
/// Content of PeerAdvertV0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct PeerAdvertContentV0 {
|
||
|
/// Peer ID
|
||
|
pub peer: PeerId,
|
||
|
|
||
11 months ago
|
/// Id of the broker that is forwarding the peer
|
||
|
pub forwarded_by: Option<DirectPeerId>,
|
||
|
|
||
2 years ago
|
/// Topic subscriptions
|
||
11 months ago
|
// pub subs: BloomFilter128,
|
||
2 years ago
|
|
||
11 months ago
|
/// Network addresses, must be empty for forwarded peers
|
||
2 years ago
|
pub address: Vec<NetAddr>,
|
||
|
|
||
|
/// Version number
|
||
|
pub version: u32,
|
||
|
|
||
|
/// App-specific metadata (profile, cryptographic material, etc)
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub metadata: Vec<u8>,
|
||
|
}
|
||
|
|
||
|
/// Peer advertisement
|
||
|
///
|
||
11 months ago
|
/// Sent when a peer joins an inner overlay.
|
||
|
/// Used only for forwardedPeer for now.
|
||
|
/// 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
|
||
|
/// When the forwarding broker receives a client connection, it checks that the peer isn't
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct PeerAdvertV0 {
|
||
|
/// Peer advertisement content
|
||
|
pub content: PeerAdvertContentV0,
|
||
|
|
||
|
/// Signature over content by peer's private key
|
||
|
pub sig: Sig,
|
||
|
}
|
||
|
|
||
|
/// Peer advertisement
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum PeerAdvert {
|
||
|
V0(PeerAdvertV0),
|
||
|
}
|
||
|
|
||
|
impl PeerAdvert {
|
||
|
pub fn version(&self) -> u32 {
|
||
|
match self {
|
||
|
PeerAdvert::V0(o) => o.content.version,
|
||
|
}
|
||
|
}
|
||
|
pub fn peer(&self) -> &PeerId {
|
||
|
match self {
|
||
|
PeerAdvert::V0(o) => &o.content.peer,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Content of InnerOverlayMessageV0
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub enum InnerOverlayMessageContentV0 {
|
||
|
OverlayLeave(OverlayLeave),
|
||
|
ForwardedPeerAdvert(ForwardedPeerAdvert),
|
||
|
ForwardedPeerConflict(ForwardedPeerConflict),
|
||
|
PublisherJoined(PublisherAdvert),
|
||
|
PublisherLeft(PublisherAdvert),
|
||
2 years ago
|
SubReq(SubReq),
|
||
11 months ago
|
SubMarker(SubMarker),
|
||
2 years ago
|
UnsubReq(UnsubReq),
|
||
|
Event(Event),
|
||
11 months ago
|
//PostInboxRequest(PostInboxRequest),
|
||
|
//PostInboxResponse(PostInboxResponse),
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Inner Overlay message payload V0
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub struct InnerOverlayMessagePayloadV0 {
|
||
|
/// Sequence number incremented by peer when sending every overlay message in a session
|
||
|
/// Used to prevent replay attacks inside the overlay
|
||
|
pub seq: u64,
|
||
|
|
||
|
pub content: InnerOverlayMessageContentV0,
|
||
|
}
|
||
2 years ago
|
|
||
11 months ago
|
/// Inner Overlay message V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct InnerOverlayMessageV0 {
|
||
2 years ago
|
/// Session ID
|
||
|
pub session: SessionId,
|
||
|
|
||
11 months ago
|
pub payload: InnerOverlayMessagePayloadV0,
|
||
|
|
||
|
/// Signature with Session private key, over payload
|
||
|
pub sig: Sig,
|
||
2 years ago
|
|
||
|
/// Optional padding
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub padding: Vec<u8>,
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Inner Overlay message
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub enum InnerOverlayMessage {
|
||
|
V0(InnerOverlayMessageV0),
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Overlay Advert Payload V0
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub struct OverlayAdvertPayloadV0 {
|
||
|
/// the target Overlay ID (cannot be an Outer overlay)
|
||
|
pub overlay: OverlayId,
|
||
2 years ago
|
|
||
11 months ago
|
/// the newly generated session ID the peer will use in this overlay
|
||
|
/// All the revoked sessionIDs are kept locally by their initiator.
|
||
|
pub session: SessionId,
|
||
2 years ago
|
|
||
11 months ago
|
/// Current sequence number. For a new session, must be zero.
|
||
|
pub seq: u64,
|
||
2 years ago
|
|
||
11 months ago
|
/// the previous session ID the peer was using in this overlay. Used to cleanup seq counters maintained in each other peer
|
||
|
/// if the previous session is empty (because it is the first time broker joins this overlay)
|
||
|
/// or if a remote peer doesn't find this session kept locally, it is not an error.
|
||
|
/// In the later case (if broker missed some intermediary sessions), the remote peer can ask the initiator peer if the last known
|
||
|
/// session can be locally revoked with a ConfirmRevokedSession message (answered with yes or no)
|
||
|
pub previous_session: Option<SessionId>,
|
||
2 years ago
|
|
||
11 months ago
|
/// peer ID of the broker issuing this Advert
|
||
|
pub peer: DirectPeerId,
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Overlay Advert V0 : used by a broker peer every time it (re)joins an overlay
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct OverlayAdvertV0 {
|
||
|
pub payload: OverlayAdvertPayloadV0,
|
||
|
|
||
|
/// Signature with peerId private key, over payload
|
||
|
pub sig: Sig,
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Overlay Advert : used by a broker peer every time it (re)joins an overlay
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum OverlayAdvert {
|
||
|
V0(OverlayAdvertV0),
|
||
|
}
|
||
|
|
||
|
/// CoreBrokerJoinedAdvert V0
|
||
|
/// Each broker that is already part of an overlay, when receiving the CoreBrokerJoinedAdvert, should answer with one direct message
|
||
|
/// to the joining peer (found in OverlayAdvertPayloadV0.peer) for each overlay, containing an OverlayAdvertMarker containing their current sequence number.
|
||
|
/// 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
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct CoreBrokerJoinedAdvertV0 {
|
||
|
/// list of overlays joined by an initiator broker, and that the forwarding broker has also previously joined
|
||
|
/// the forwarding broker keeps the ingress edge and all egress edges in the coreRoutingTable
|
||
|
pub overlays: Vec<OverlayAdvertV0>,
|
||
|
}
|
||
|
|
||
|
/// CoreBrokerLeftAdvert V0
|
||
|
/// A broker has disconnected from another broker, and the routes need to be updated
|
||
|
/// this is not used to leave one specific overlay. see OverlayLeave message for that purpose
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct CoreBrokerLeftAdvertV0 {
|
||
|
/// The broker that disconnected from the one that is emitting this advert.
|
||
|
pub disconnected: DirectPeerId,
|
||
|
}
|
||
|
|
||
|
/// CoreOverlayJoinedAdvert V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct CoreOverlayJoinedAdvertV0 {
|
||
|
/// One additional overlay joined by an initiator broker, and that the forwarding broker has also previously joined
|
||
|
/// the forwarding broker keeps the ingress edge and all egress edges in the coreRoutingTable
|
||
|
pub overlay: OverlayAdvertV0,
|
||
|
}
|
||
|
|
||
11 months ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreBrokerJoinedAdvert {
|
||
|
V0(CoreBrokerJoinedAdvertV0),
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreBrokerLeftAdvert {
|
||
|
V0(CoreBrokerLeftAdvertV0),
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreOverlayJoinedAdvert {
|
||
|
V0(CoreOverlayJoinedAdvertV0),
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Content of CoreAdvert V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreAdvertContentV0 {
|
||
11 months ago
|
BrokerJoined(CoreBrokerJoinedAdvert),
|
||
|
BrokerLeft(CoreBrokerLeftAdvert),
|
||
|
OverlayJoined(CoreOverlayJoinedAdvert),
|
||
11 months ago
|
}
|
||
|
|
||
|
/// CoreAdvert V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct CoreAdvertV0 {
|
||
|
pub content: CoreAdvertContentV0,
|
||
|
|
||
|
/// list of brokers on the path that was followed to deliver this advert.
|
||
|
/// new entry pushed each time a forward is happening in the core network
|
||
|
pub path: Vec<DirectPeerId>,
|
||
|
|
||
|
/// content signed by the first broker in the path
|
||
|
pub sig: Sig,
|
||
|
|
||
|
/// Optional padding
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub padding: Vec<u8>,
|
||
|
}
|
||
|
|
||
|
/// OverlayAdvertMarker V0
|
||
|
/// when receiving a marker, the broker saves the ingress edge and the corresponding remote peer and
|
||
|
/// overlay that can be reached (the OverlayAdvertPayloadV0.peer and .overlay) in the CoreRoutingTable
|
||
|
/// It also saves the sessionId and seq number
|
||
|
/// then a ReturnPathTimingAdvert is sent back
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct OverlayAdvertMarkerV0 {
|
||
|
pub marker: OverlayAdvertV0,
|
||
|
|
||
|
/// New SessionId that triggered this marker (to avoid replay attacks in the core network)
|
||
|
pub in_reply_to: SessionId,
|
||
|
|
||
|
/// path from the new broker who started a session, to the broker that is sending the marker
|
||
|
pub path: Vec<DirectPeerId>,
|
||
|
|
||
11 months ago
|
/// randomly generated nonce used for the reply (a ReturnPathTimingMarker) that will be sent back after this marker has been received on the other end
|
||
11 months ago
|
pub reply_nonce: u64,
|
||
|
}
|
||
|
|
||
|
/// Core Block Get V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct CoreBlockGetV0 {
|
||
|
/// Block ID to request
|
||
11 months ago
|
pub ids: Vec<BlockId>,
|
||
11 months ago
|
|
||
|
/// Whether or not to include all children recursively
|
||
|
pub include_children: bool,
|
||
|
|
||
11 months ago
|
/// randomly generated number by requester, used for sending reply.
|
||
|
/// the requester keeps track of req_nonce and requested peerid.
|
||
|
/// used for handling the stream
|
||
11 months ago
|
pub req_nonce: u64,
|
||
|
}
|
||
|
|
||
|
/// Core Block Result V0
|
||
11 months ago
|
/// can be a stream
|
||
11 months ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct CoreBlockResultV0 {
|
||
|
/// Resulting Object(s)
|
||
|
pub payload: Vec<Block>,
|
||
|
|
||
|
/// randomly generated number by requester, as received in the request
|
||
|
pub req_nonce: u64,
|
||
|
}
|
||
|
|
||
|
/// ReturnPathTimingAdvertV0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct ReturnPathTimingAdvertV0 {
|
||
|
/// Signature over nonce, by sessionId
|
||
|
pub sig: Sig,
|
||
|
|
||
|
/// randomly generated number as received in the OverlayAdvertMarker
|
||
|
pub nonce: u64,
|
||
|
}
|
||
|
|
||
11 months ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum OverlayAdvertMarker {
|
||
|
V0(OverlayAdvertMarkerV0),
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum ReturnPathTimingAdvert {
|
||
|
V0(ReturnPathTimingAdvertV0),
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreBlockGet {
|
||
|
V0(CoreBlockGetV0),
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreBlockResult {
|
||
|
V0(CoreBlockResultV0),
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Content of CoreDirectMessage V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreDirectMessageContentV0 {
|
||
11 months ago
|
OverlayAdvertMarker(OverlayAdvertMarker),
|
||
|
ReturnPathTimingAdvert(ReturnPathTimingAdvert),
|
||
|
BlockGet(CoreBlockGet),
|
||
|
BlockResult(CoreBlockResult),
|
||
11 months ago
|
//PostInbox,
|
||
|
//PartialSignature,
|
||
|
//ClientDirectMessage //for messages between forwarded or direct peers
|
||
|
}
|
||
|
|
||
|
/// CoreDirectMessage V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct CoreDirectMessageV0 {
|
||
|
pub content: CoreDirectMessageContentV0,
|
||
|
|
||
|
/// list of brokers on the path that must be followed to deliver this message, next hop is at the bottom of the list.
|
||
|
/// last entry on the list is popped each time a broker is forwarding upstream
|
||
|
/// when list size is zero, the final destination is reached.
|
||
|
/// if only one peer in list, and peer not found in local CoreRoutingTable, use the best route to reach it (without popping)
|
||
|
pub reverse_path: Vec<DirectPeerId>,
|
||
|
|
||
|
/// The sender
|
||
|
pub from: DirectPeerId,
|
||
|
|
||
|
/// content signed by the sender
|
||
|
pub sig: Sig,
|
||
|
|
||
|
/// Optional padding
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub padding: Vec<u8>,
|
||
|
}
|
||
|
|
||
|
/// CoreBrokerConnect V0
|
||
|
/// replied with CoreBrokerConnectResponse
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct CoreBrokerConnectV0 {
|
||
|
pub inner_overlays: Vec<OverlayAdvertV0>,
|
||
|
pub outer_overlays: Vec<Digest>,
|
||
|
}
|
||
|
|
||
|
/// CoreBrokerConnect
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreBrokerConnect {
|
||
|
V0(CoreBrokerConnectV0),
|
||
|
}
|
||
|
|
||
|
/// CoreBrokerConnectResponse
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreBrokerConnectResponse {
|
||
|
V0(CoreBrokerConnectResponseV0),
|
||
|
}
|
||
|
|
||
|
impl CoreBrokerConnect {
|
||
|
pub fn core_message(&self, id: i64) -> CoreMessage {
|
||
|
match self {
|
||
11 months ago
|
CoreBrokerConnect::V0(v0) => {
|
||
|
CoreMessage::V0(CoreMessageV0::Request(CoreRequest::V0(CoreRequestV0 {
|
||
|
padding: vec![],
|
||
|
id,
|
||
|
content: CoreRequestContentV0::BrokerConnect(CoreBrokerConnect::V0(v0.clone())),
|
||
|
})))
|
||
|
}
|
||
11 months ago
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// sent to a direct peer just before closing the connection
|
||
|
pub type CoreBrokerDisconnectV0 = ();
|
||
|
|
||
|
/// Content of CoreOverlayJoin V0
|
||
|
/// // replied with an emptyResponse, and an error code if OverlayId not present on remote broker
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreOverlayJoinV0 {
|
||
11 months ago
|
Inner(OverlayAdvert),
|
||
11 months ago
|
Outer(Digest),
|
||
|
}
|
||
|
|
||
|
/// Content of OuterOverlayResponse V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum OuterOverlayResponseContentV0 {
|
||
|
EmptyResponse(()),
|
||
|
Block(Block),
|
||
11 months ago
|
TopicSyncRes(TopicSyncRes),
|
||
11 months ago
|
//PostInboxResponse(PostInboxResponse),
|
||
|
}
|
||
|
|
||
|
/// Content of OuterOverlayRequest V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum OuterOverlayRequestContentV0 {
|
||
|
TopicSyncReq(TopicSyncReq),
|
||
|
OverlayLeave(OverlayLeave),
|
||
|
TopicSub(PubKey),
|
||
|
TopicUnsub(PubKey),
|
||
|
BlockGet(BlockGet),
|
||
|
//PostInboxRequest(PostInboxRequest),
|
||
|
}
|
||
|
|
||
|
/// OuterOverlayRequestV0 V0
|
||
|
/// replied with OuterOverlayResponseV0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct OuterOverlayRequestV0 {
|
||
|
pub overlay: Digest,
|
||
|
pub content: OuterOverlayRequestContentV0,
|
||
|
}
|
||
|
|
||
|
/// OuterOverlayResponse V0
|
||
|
/// reply to an OuterOverlayRequest V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct OuterOverlayResponseV0 {
|
||
|
pub overlay: Digest,
|
||
|
pub content: OuterOverlayResponseContentV0,
|
||
|
}
|
||
|
|
||
|
/// Core Topic synchronization request
|
||
|
///
|
||
11 months ago
|
/// behaves like BlockSearchTopic (primarily searches among the publishers, except if search_in_subs is set to true)
|
||
11 months ago
|
/// fanout is 1 for now
|
||
|
///
|
||
11 months ago
|
/// If some target_heads are not found locally, all successors of known_heads are sent anyway,
|
||
|
/// and then this temporary HEAD is used to propagate/fanout the CoreTopicSyncReq to upstream brokers
|
||
|
///
|
||
|
/// Answered with one or many TopicSyncRes a stream of `Block`s or Event of the commits
|
||
|
/// 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.
|
||
11 months ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct CoreTopicSyncReqV0 {
|
||
|
/// Topic public key
|
||
|
pub topic: TopicId,
|
||
|
|
||
|
/// Also search in subscribers, in addition to publishers
|
||
|
pub search_in_subs: bool,
|
||
|
|
||
|
/// Fully synchronized until these commits
|
||
|
pub known_heads: Vec<ObjectId>,
|
||
|
|
||
11 months ago
|
/// Stop synchronizing when these commits are met.
|
||
|
/// if empty, the local HEAD at the responder is used instead
|
||
11 months ago
|
pub target_heads: Vec<ObjectId>,
|
||
|
}
|
||
|
|
||
|
/// Topic synchronization request
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreTopicSyncReq {
|
||
|
V0(CoreTopicSyncReqV0),
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Topic synchronization response V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum TopicSyncResV0 {
|
||
|
Event(Event),
|
||
|
Block(Block),
|
||
|
}
|
||
|
|
||
|
/// Topic synchronization response
|
||
|
/// it is a stream of blocks and or events.
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum TopicSyncRes {
|
||
|
V0(TopicSyncResV0),
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreBrokerDisconnect {
|
||
|
V0(CoreBrokerDisconnectV0),
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreOverlayJoin {
|
||
|
V0(CoreOverlayJoinV0),
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum OuterOverlayRequest {
|
||
|
V0(OuterOverlayRequestV0),
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Content of CoreRequest V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreRequestContentV0 {
|
||
11 months ago
|
BrokerConnect(CoreBrokerConnect),
|
||
|
BrokerDisconnect(CoreBrokerDisconnect),
|
||
|
OverlayJoin(CoreOverlayJoin),
|
||
|
BlockSearchTopic(BlockSearchTopic),
|
||
|
BlockSearchRandom(BlockSearchRandom),
|
||
|
TopicSyncReq(CoreTopicSyncReq),
|
||
|
OuterOverlayRequest(OuterOverlayRequest),
|
||
11 months ago
|
}
|
||
|
|
||
|
/// CoreRequest V0
|
||
|
/// replied with CoreResponse V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct CoreRequestV0 {
|
||
|
/// Request ID
|
||
|
pub id: i64,
|
||
|
pub content: CoreRequestContentV0,
|
||
|
|
||
|
/// Optional padding
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub padding: Vec<u8>,
|
||
|
}
|
||
|
|
||
|
/// Request sent to a broker in the core network
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreRequest {
|
||
|
V0(CoreRequestV0),
|
||
|
}
|
||
|
|
||
|
/// CoreBrokerConnectResponse V0
|
||
|
/// reply to a CoreBrokerConnect V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct CoreBrokerConnectResponseV0 {
|
||
|
pub successes: Vec<OverlayId>,
|
||
|
pub errors: Vec<OverlayId>,
|
||
|
}
|
||
|
|
||
11 months ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum OuterOverlayResponse {
|
||
|
V0(OuterOverlayResponseV0),
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Content CoreResponse V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreResponseContentV0 {
|
||
11 months ago
|
BrokerConnectResponse(CoreBrokerConnectResponse),
|
||
|
BlockResult(BlockResult),
|
||
|
TopicSyncRes(TopicSyncRes),
|
||
|
OuterOverlayResponse(OuterOverlayResponse),
|
||
11 months ago
|
EmptyResponse(()),
|
||
|
}
|
||
|
|
||
|
/// CoreResponse V0
|
||
|
/// reply to an CoreRequest V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct CoreResponseV0 {
|
||
|
/// Request ID
|
||
|
pub id: i64,
|
||
|
|
||
|
/// Result
|
||
|
pub result: u16,
|
||
|
pub content: CoreResponseContentV0,
|
||
|
|
||
|
/// Optional padding
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub padding: Vec<u8>,
|
||
|
}
|
||
|
|
||
|
/// Response to a Request sent to a broker in the core network
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreResponse {
|
||
|
V0(CoreResponseV0),
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum OuterOverlayMessageContentV0 {
|
||
|
Event(Event),
|
||
|
}
|
||
|
|
||
|
/// OuterOverlayMessage V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct OuterOverlayMessageV0 {
|
||
|
pub overlay: Digest,
|
||
|
|
||
|
pub content: OuterOverlayMessageContentV0,
|
||
|
|
||
|
/// Optional padding
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub padding: Vec<u8>,
|
||
|
}
|
||
|
|
||
11 months ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreAdvert {
|
||
|
V0(CoreAdvertV0),
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreDirectMessage {
|
||
|
V0(CoreDirectMessageV0),
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum OuterOverlayMessage {
|
||
|
V0(OuterOverlayMessageV0),
|
||
|
}
|
||
|
|
||
11 months ago
|
/// CoreMessageV0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreMessageV0 {
|
||
11 months ago
|
Request(CoreRequest),
|
||
|
Response(CoreResponse),
|
||
|
Advert(CoreAdvert),
|
||
|
Direct(CoreDirectMessage),
|
||
|
InnerOverlay(InnerOverlayMessage),
|
||
|
OuterOverlay(OuterOverlayMessage),
|
||
11 months ago
|
}
|
||
|
|
||
|
/// Core message
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum CoreMessage {
|
||
|
V0(CoreMessageV0),
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// ADMIN PROTOCOL
|
||
|
//
|
||
|
|
||
|
/// Content of `AdminRequestV0`
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum AdminRequestContentV0 {
|
||
|
AddUser(AddUser),
|
||
|
DelUser(DelUser),
|
||
|
ListUsers(ListUsers),
|
||
|
ListInvitations(ListInvitations),
|
||
|
AddInvitation(AddInvitation),
|
||
|
}
|
||
|
impl AdminRequestContentV0 {
|
||
|
pub fn type_id(&self) -> TypeId {
|
||
|
match self {
|
||
|
Self::AddUser(a) => a.type_id(),
|
||
|
Self::DelUser(a) => a.type_id(),
|
||
|
Self::ListUsers(a) => a.type_id(),
|
||
|
Self::ListInvitations(a) => a.type_id(),
|
||
|
Self::AddInvitation(a) => a.type_id(),
|
||
|
}
|
||
|
}
|
||
|
pub fn get_actor(&self) -> Box<dyn EActor> {
|
||
|
match self {
|
||
|
Self::AddUser(a) => a.get_actor(),
|
||
|
Self::DelUser(a) => a.get_actor(),
|
||
|
Self::ListUsers(a) => a.get_actor(),
|
||
|
Self::ListInvitations(a) => a.get_actor(),
|
||
|
Self::AddInvitation(a) => a.get_actor(),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Admin request
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct AdminRequestV0 {
|
||
|
/// Request ID
|
||
|
pub id: i64,
|
||
|
|
||
|
/// Request content
|
||
|
pub content: AdminRequestContentV0,
|
||
|
|
||
|
/// Signature over content by admin key
|
||
|
pub sig: Sig,
|
||
|
|
||
|
/// THe admin user requesting this operation
|
||
|
pub admin_user: PubKey,
|
||
|
|
||
|
/// Optional padding
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub padding: Vec<u8>,
|
||
|
}
|
||
|
|
||
|
impl AdminRequestV0 {
|
||
|
pub fn get_actor(&self) -> Box<dyn EActor> {
|
||
|
self.content.get_actor()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Admin request
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum AdminRequest {
|
||
|
V0(AdminRequestV0),
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
impl AdminRequest {
|
||
|
pub fn id(&self) -> i64 {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
Self::V0(o) => o.id,
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
pub fn set_id(&mut self, id: i64) {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
Self::V0(v0) => {
|
||
|
v0.id = id;
|
||
|
}
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
pub fn type_id(&self) -> TypeId {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
Self::V0(o) => o.content.type_id(),
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
pub fn sig(&self) -> Sig {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
Self::V0(o) => o.sig,
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
pub fn admin_user(&self) -> PubKey {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
Self::V0(o) => o.admin_user,
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
pub fn get_actor(&self) -> Box<dyn EActor> {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
Self::V0(a) => a.get_actor(),
|
||
2 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
impl From<AdminRequest> for ProtocolMessage {
|
||
|
fn from(msg: AdminRequest) -> ProtocolMessage {
|
||
|
ProtocolMessage::Start(StartProtocol::Admin(msg))
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
|
||
2 years ago
|
/// Content of `AdminResponseV0`
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum AdminResponseContentV0 {
|
||
|
EmptyResponse,
|
||
|
Users(Vec<PubKey>),
|
||
2 years ago
|
Invitations(Vec<(InvitationCode, u32, Option<String>)>),
|
||
|
Invitation(Invitation),
|
||
2 years ago
|
}
|
||
|
|
||
|
/// Response to an `AdminRequest` V0
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
2 years ago
|
pub struct AdminResponseV0 {
|
||
2 years ago
|
/// Request ID
|
||
2 years ago
|
pub id: i64,
|
||
2 years ago
|
|
||
2 years ago
|
/// Result (including but not limited to Result)
|
||
|
pub result: u16,
|
||
|
|
||
|
pub content: AdminResponseContentV0,
|
||
|
|
||
|
/// Optional padding
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub padding: Vec<u8>,
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
/// Response to an `AdminRequest`
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
2 years ago
|
pub enum AdminResponse {
|
||
|
V0(AdminResponseV0),
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
impl From<Result<(), ProtocolError>> for AdminResponseV0 {
|
||
|
fn from(res: Result<(), ProtocolError>) -> AdminResponseV0 {
|
||
|
AdminResponseV0 {
|
||
|
id: 0,
|
||
|
result: res.map(|_| 0).unwrap_or_else(|e| e.into()),
|
||
|
content: AdminResponseContentV0::EmptyResponse,
|
||
|
padding: vec![],
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
}
|
||
|
|
||
|
impl From<Result<Vec<PubKey>, ProtocolError>> for AdminResponseV0 {
|
||
|
fn from(res: Result<Vec<PubKey>, ProtocolError>) -> AdminResponseV0 {
|
||
|
match res {
|
||
|
Err(e) => AdminResponseV0 {
|
||
|
id: 0,
|
||
|
result: e.into(),
|
||
|
content: AdminResponseContentV0::EmptyResponse,
|
||
|
padding: vec![],
|
||
|
},
|
||
|
Ok(vec) => AdminResponseV0 {
|
||
|
id: 0,
|
||
|
result: 0,
|
||
|
content: AdminResponseContentV0::Users(vec),
|
||
|
padding: vec![],
|
||
|
},
|
||
2 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
impl From<AdminResponseV0> for ProtocolMessage {
|
||
|
fn from(msg: AdminResponseV0) -> ProtocolMessage {
|
||
|
ProtocolMessage::AdminResponse(AdminResponse::V0(msg))
|
||
|
}
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
impl From<AdminResponse> for ProtocolMessage {
|
||
|
fn from(msg: AdminResponse) -> ProtocolMessage {
|
||
|
ProtocolMessage::AdminResponse(msg)
|
||
|
}
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
impl TryFrom<ProtocolMessage> for AdminResponse {
|
||
|
type Error = ProtocolError;
|
||
|
fn try_from(msg: ProtocolMessage) -> Result<Self, Self::Error> {
|
||
|
if let ProtocolMessage::AdminResponse(res) = msg {
|
||
|
Ok(res)
|
||
|
} else {
|
||
|
Err(ProtocolError::InvalidValue)
|
||
|
}
|
||
|
}
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
impl AdminResponse {
|
||
2 years ago
|
pub fn id(&self) -> i64 {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
Self::V0(o) => o.id,
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
pub fn set_id(&mut self, id: i64) {
|
||
|
match self {
|
||
2 years ago
|
Self::V0(v0) => {
|
||
2 years ago
|
v0.id = id;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
2 years ago
|
pub fn result(&self) -> u16 {
|
||
|
match self {
|
||
2 years ago
|
Self::V0(o) => o.result,
|
||
|
}
|
||
|
}
|
||
|
pub fn content_v0(&self) -> AdminResponseContentV0 {
|
||
|
match self {
|
||
|
Self::V0(o) => o.content.clone(),
|
||
2 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
//
|
||
|
// CLIENT PROTOCOL
|
||
|
//
|
||
|
|
||
11 months ago
|
/// Request to open a repo in a non-durable way (without pinning it).
|
||
|
/// When client will disconnect, the subscriptions and publisherAdvert of the topics will be removed,
|
||
|
/// except if a PinRepo occurred before or after the OpenRepo
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub struct OpenRepoV0 {
|
||
|
/// Repo Hash
|
||
|
pub hash: RepoHash,
|
||
2 years ago
|
|
||
11 months ago
|
// for RW overlay, the overlay that should be used in the clientmessage is the innerOverlay
|
||
|
pub overlay: OverlayAccess,
|
||
2 years ago
|
|
||
11 months ago
|
/// Broker peers to connect to in order to join the overlay
|
||
11 months ago
|
/// can be empty for private store (the broker will not connect to any other broker)
|
||
10 months ago
|
/// but if the private repo is pinned in other brokers, those brokers should be entered here for syncing.
|
||
|
/// can be empty also when we just created the repo, and there are no other brokers in the overlay
|
||
2 years ago
|
pub peers: Vec<PeerAdvert>,
|
||
11 months ago
|
|
||
10 months ago
|
/// a list of core brokers that are allowed to connect to the overlay (only valid for an inner (RW/WO) overlay).
|
||
|
/// an empty list means any core broker is allowed. this is the default behaviour.
|
||
|
/// to restrict the overlay to only the current core, its DirectPeerId should be entered here.
|
||
|
pub allowed_peers: Vec<DirectPeerId>,
|
||
|
|
||
11 months ago
|
/// Maximum number of peers to connect to for this overlay (only valid for an inner (RW/WO) overlay)
|
||
|
pub max_peer_count: u16,
|
||
|
|
||
|
/// list of topics that should be subscribed to
|
||
|
pub ro_topics: Vec<TopicId>,
|
||
|
|
||
|
/// list of topics for which we will be a publisher
|
||
|
/// only possible with inner (RW or WO) overlays.
|
||
10 months ago
|
/// implies also subscribing to it (no need to put it also in ro_topics)
|
||
11 months ago
|
pub rw_topics: Vec<PublisherAdvert>,
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Request to open a repo
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub enum OpenRepo {
|
||
|
V0(OpenRepoV0),
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
impl OpenRepo {
|
||
|
pub fn peers(&self) -> &Vec<PeerAdvert> {
|
||
2 years ago
|
match self {
|
||
11 months ago
|
OpenRepo::V0(o) => &o.peers,
|
||
2 years ago
|
}
|
||
|
}
|
||
11 months ago
|
}
|
||
|
|
||
|
/// Request to pin a repo on the broker.
|
||
|
/// When client will disconnect, the subscriptions and publisherAdvert of the topics will be remain active on the broker,
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct PinRepoV0 {
|
||
|
/// Repo Hash
|
||
|
pub hash: RepoHash,
|
||
|
|
||
|
/// for RW overlay, the overlay that should be used in the clientmessage is the innerOverlay
|
||
|
pub overlay: OverlayAccess,
|
||
|
|
||
|
/// Root topic of the overlay, used to listen to overlay refreshes. Only used for inner (RW or WO) overlays
|
||
|
pub overlay_root_topic: Option<TopicId>,
|
||
|
|
||
10 months ago
|
/// only possible for RW overlays. not allowed for private or dialog overlay
|
||
11 months ago
|
pub expose_outer: bool,
|
||
|
|
||
|
/// Broker peers to connect to in order to join the overlay
|
||
10 months ago
|
/// If the repo has previously been opened (during the same session) or if it is a private overlay, then peers info can be omitted
|
||
11 months ago
|
pub peers: Vec<PeerAdvert>,
|
||
|
|
||
|
/// Maximum number of peers to connect to for this overlay (only valid for an inner (RW/WO) overlay)
|
||
|
pub max_peer_count: u16,
|
||
|
|
||
10 months ago
|
/// a list of core brokers that are allowed to connect to the overlay (only valid for an inner (RW/WO) overlay).
|
||
|
/// an empty list means any core broker is allowed. this is the default behaviour.
|
||
|
/// to restrict the overlay to only the current core, its DirectPeerId should be entered here.
|
||
|
/// not compatible with expose_outer
|
||
|
pub allowed_peers: Vec<DirectPeerId>,
|
||
|
|
||
11 months ago
|
/// list of topics that should be subscribed to
|
||
|
/// If the repo has previously been opened (during the same session) then ro_topics info can be omitted
|
||
|
pub ro_topics: Vec<TopicId>,
|
||
|
|
||
|
/// list of topics for which we will be a publisher
|
||
|
/// only possible with inner (RW or WO) overlays.
|
||
|
/// If the repo has previously been opened (during the same session) then rw_topics info can be omitted
|
||
|
pub rw_topics: Vec<PublisherAdvert>,
|
||
11 months ago
|
// TODO pub inbox_proof
|
||
|
// TODO pub signer_proof
|
||
11 months ago
|
}
|
||
|
|
||
|
/// Request to pin a repo
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum PinRepo {
|
||
|
V0(PinRepoV0),
|
||
|
}
|
||
|
|
||
|
impl PinRepo {
|
||
|
pub fn peers(&self) -> &Vec<PeerAdvert> {
|
||
2 years ago
|
match self {
|
||
11 months ago
|
PinRepo::V0(o) => &o.peers,
|
||
2 years ago
|
}
|
||
|
}
|
||
11 months ago
|
}
|
||
|
|
||
11 months ago
|
/// Request to refresh the Pinning of a previously pinned repo.
|
||
|
/// it can consist of updating the expose_outer, the list of ro_topics and/or rw_topics,
|
||
|
/// 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
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct RefreshPinRepoV0 {
|
||
|
/// The new PinRepo info
|
||
|
pub pin: PinRepo,
|
||
|
|
||
|
/// optional hashed member ID that should be banned
|
||
|
pub ban_member: Option<Digest>,
|
||
|
|
||
|
/// when banning, list of topics that are to be flushed (once all the local members have left, except the one to be banned)
|
||
|
/// All the honest local members have to send this list in order for the banned one to be effectively banned
|
||
|
/// for each Topic, a signature over the hashed UserId to ban, by the Topic private key.
|
||
|
/// 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.
|
||
|
/// The userId of banned user is revealed to the local broker where it was attached, which is a breach of privacy deemed acceptable
|
||
|
/// as only a broker that already knew the userid will enforce it, and
|
||
|
/// that broker might be interested to know that the offending user was banned from a repo, as only malicious users are banned.
|
||
|
/// The broker might also discard this information, and just proceeed with the flush without much ado.
|
||
|
/// 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.
|
||
|
pub flush_topics: Vec<(TopicId, Sig)>,
|
||
|
}
|
||
|
|
||
|
/// Request to pin a repo
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum RefreshPinRepo {
|
||
|
V0(RefreshPinRepoV0),
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Request to unpin a repo on the broker.
|
||
|
/// When client will disconnect, the subscriptions and publisherAdvert of the topics will be removed on the broker
|
||
|
/// (for that user only. other users might continue to have the repo pinned)
|
||
|
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct UnpinRepoV0 {
|
||
|
/// Repo Hash
|
||
|
pub hash: RepoHash,
|
||
|
}
|
||
|
|
||
|
/// Request to unpin a repo
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum UnpinRepo {
|
||
|
V0(UnpinRepoV0),
|
||
|
}
|
||
|
|
||
|
impl UnpinRepo {
|
||
|
pub fn hash(&self) -> &RepoHash {
|
||
2 years ago
|
match self {
|
||
11 months ago
|
UnpinRepo::V0(o) => &o.hash,
|
||
2 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Request the status of pinning for a repo on the broker. V0
|
||
|
/// returns an error code if not pinned, otherwise returns a RepoPinStatusV0
|
||
|
/// the overlay entered in ClientMessage is important. if it is the outer, only outer pinning will be checked.
|
||
|
/// if it is the inner overlay, only the inner pinning will be checked.
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct RepoPinStatusReqV0 {
|
||
|
/// Repo Hash
|
||
|
pub hash: RepoHash,
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Request the status of pinning for a repo on the broker.
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum RepoPinStatusReq {
|
||
|
V0(RepoPinStatusReqV0),
|
||
|
}
|
||
|
|
||
|
impl RepoPinStatusReq {
|
||
|
pub fn hash(&self) -> &RepoHash {
|
||
|
match self {
|
||
|
RepoPinStatusReq::V0(o) => &o.hash,
|
||
|
}
|
||
|
}
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Response with the status of pinning for a repo on the broker. V0
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub struct RepoPinStatusV0 {
|
||
|
/// Repo Hash
|
||
|
pub hash: RepoHash,
|
||
2 years ago
|
|
||
11 months ago
|
/// only possible for RW overlays
|
||
|
pub expose_outer: bool,
|
||
|
|
||
|
/// list of topics that are subscribed to (not included the RW ones. see list just below)
|
||
|
pub ro_topics: Vec<TopicId>,
|
||
|
|
||
|
/// list of topics that are publisher
|
||
|
pub rw_topics: Vec<TopicId>,
|
||
|
// TODO pub inbox_proof
|
||
|
|
||
|
// TODO pub signer_proof
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Response with the status of pinning for a repo on the broker.
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub enum RepoPinStatus {
|
||
|
V0(RepoPinStatusV0),
|
||
|
}
|
||
|
|
||
|
impl RepoPinStatus {
|
||
|
pub fn hash(&self) -> &RepoHash {
|
||
|
match self {
|
||
|
RepoPinStatus::V0(o) => &o.hash,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Request subscription to a `Topic` of an already opened or pinned Repo
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
|
pub struct TopicSubV0 {
|
||
|
/// Topic to subscribe
|
||
|
pub topic: PubKey,
|
||
|
|
||
|
/// Hash of the repo that was previously opened or pinned
|
||
|
pub repo_hash: RepoHash,
|
||
|
|
||
|
/// Publisher need to provide a signed `PublisherAdvert` for the PeerId of the broker
|
||
|
pub publisher: Option<PublisherAdvert>,
|
||
|
}
|
||
|
|
||
|
/// Request subscription to a `Topic` of an already opened or pinned Repo
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
|
pub enum TopicSub {
|
||
|
V0(TopicSubV0),
|
||
|
}
|
||
|
|
||
|
/// Request unsubscription from a `Topic` of an already opened or pinned Repo
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
|
pub struct TopicUnsubV0 {
|
||
|
/// Topic to unsubscribe
|
||
|
pub topic: PubKey,
|
||
|
|
||
|
/// Hash of the repo that was previously opened or pinned
|
||
|
pub repo_hash: RepoHash,
|
||
|
}
|
||
|
|
||
|
/// Request unsubscription from a `Topic` of an already opened or pinned Repo
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
|
pub enum TopicUnsub {
|
||
|
V0(TopicUnsubV0),
|
||
2 years ago
|
}
|
||
|
|
||
|
/// Request a Block by ID
|
||
11 months ago
|
/// commit_header_key is always set to None in the reply when request is made on OuterOverlay of protected or Group overlays
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct BlockGetV0 {
|
||
11 months ago
|
/// Block IDs to request
|
||
|
pub ids: Vec<BlockId>,
|
||
2 years ago
|
|
||
|
/// Whether or not to include all children recursively
|
||
|
pub include_children: bool,
|
||
|
|
||
11 months ago
|
/// Topic the object is referenced from, if it is known by the requester.
|
||
|
/// can be used to do a BlockSearchTopic in the core overlay.
|
||
|
pub topic: Option<TopicId>,
|
||
2 years ago
|
}
|
||
|
|
||
|
/// Request an object by ID
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum BlockGet {
|
||
|
V0(BlockGetV0),
|
||
|
}
|
||
|
|
||
|
impl BlockGet {
|
||
11 months ago
|
pub fn ids(&self) -> &Vec<BlockId> {
|
||
2 years ago
|
match self {
|
||
11 months ago
|
BlockGet::V0(o) => &o.ids,
|
||
2 years ago
|
}
|
||
|
}
|
||
|
pub fn include_children(&self) -> bool {
|
||
|
match self {
|
||
|
BlockGet::V0(o) => o.include_children,
|
||
|
}
|
||
|
}
|
||
|
pub fn topic(&self) -> Option<PubKey> {
|
||
|
match self {
|
||
|
BlockGet::V0(o) => o.topic,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Request to store one or more blocks
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub struct BlocksPutV0 {
|
||
|
/// Blocks to store
|
||
|
pub blocks: Vec<Block>,
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Request to store one or more blocks
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum BlocksPut {
|
||
|
V0(BlocksPutV0),
|
||
|
}
|
||
|
|
||
|
impl BlocksPut {
|
||
|
pub fn blocks(&self) -> &Vec<Block> {
|
||
2 years ago
|
match self {
|
||
11 months ago
|
BlocksPut::V0(o) => &o.blocks,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Request to know if some blocks are present locally
|
||
11 months ago
|
/// used by client before publishing an event, to know what to push
|
||
11 months ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct BlocksExistV0 {
|
||
|
/// Ids of Blocks to check
|
||
|
pub blocks: Vec<BlockId>,
|
||
|
}
|
||
|
|
||
|
/// Request to store one or more blocks
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum BlocksExist {
|
||
|
V0(BlocksExistV0),
|
||
|
}
|
||
|
|
||
|
impl BlocksExist {
|
||
|
pub fn blocks(&self) -> &Vec<BlockId> {
|
||
|
match self {
|
||
|
BlocksExist::V0(o) => &o.blocks,
|
||
2 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Request to pin an object
|
||
|
///
|
||
|
/// Brokers maintain an LRU cache of objects,
|
||
|
/// where old, unused objects might get deleted to free up space for new ones.
|
||
|
/// Pinned objects are retained, regardless of last access.
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
|
pub struct ObjectPinV0 {
|
||
|
pub id: ObjectId,
|
||
|
}
|
||
|
|
||
|
/// Request to pin an object
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
|
pub enum ObjectPin {
|
||
|
V0(ObjectPinV0),
|
||
|
}
|
||
|
|
||
|
impl ObjectPin {
|
||
|
pub fn id(&self) -> ObjectId {
|
||
|
match self {
|
||
|
ObjectPin::V0(o) => o.id,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Request to unpin an object
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
|
pub struct ObjectUnpinV0 {
|
||
|
pub id: ObjectId,
|
||
|
}
|
||
|
|
||
|
/// Request to unpin an object
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
|
pub enum ObjectUnpin {
|
||
|
V0(ObjectUnpinV0),
|
||
|
}
|
||
|
|
||
|
impl ObjectUnpin {
|
||
|
pub fn id(&self) -> ObjectId {
|
||
|
match self {
|
||
|
ObjectUnpin::V0(o) => o.id,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Request to delete an object
|
||
11 months ago
|
/// only effective if the refcount for this object is zero (basically it removes it from LRU)
|
||
2 years ago
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
|
pub struct ObjectDelV0 {
|
||
|
pub id: ObjectId,
|
||
|
}
|
||
|
|
||
|
/// Request to delete an object
|
||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||
|
pub enum ObjectDel {
|
||
|
V0(ObjectDelV0),
|
||
|
}
|
||
|
|
||
|
impl ObjectDel {
|
||
|
pub fn id(&self) -> ObjectId {
|
||
|
match self {
|
||
|
ObjectDel::V0(o) => o.id,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Content of `ClientRequestV0`
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum ClientRequestContentV0 {
|
||
11 months ago
|
OpenRepo(OpenRepo),
|
||
|
PinRepo(PinRepo),
|
||
|
UnpinRepo(UnpinRepo),
|
||
|
RepoPinStatusReq(RepoPinStatusReq),
|
||
2 years ago
|
|
||
11 months ago
|
// once repo is opened or pinned:
|
||
11 months ago
|
TopicSub(TopicSub),
|
||
|
TopicUnsub(TopicUnsub),
|
||
2 years ago
|
|
||
11 months ago
|
BlocksExist(BlocksExist),
|
||
|
BlockGet(BlockGet),
|
||
|
TopicSyncReq(TopicSyncReq),
|
||
2 years ago
|
|
||
11 months ago
|
// For Pinned Repos only :
|
||
11 months ago
|
ObjectPin(ObjectPin),
|
||
|
ObjectUnpin(ObjectUnpin),
|
||
|
ObjectDel(ObjectDel),
|
||
2 years ago
|
|
||
11 months ago
|
// For InnerOverlay's only :
|
||
11 months ago
|
BlocksPut(BlocksPut),
|
||
|
PublishEvent(Event),
|
||
2 years ago
|
}
|
||
|
/// Broker overlay request
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
2 years ago
|
pub struct ClientRequestV0 {
|
||
2 years ago
|
/// Request ID
|
||
2 years ago
|
pub id: i64,
|
||
2 years ago
|
|
||
|
/// Request content
|
||
2 years ago
|
pub content: ClientRequestContentV0,
|
||
2 years ago
|
}
|
||
|
|
||
|
/// Broker overlay request
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
2 years ago
|
pub enum ClientRequest {
|
||
|
V0(ClientRequestV0),
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
impl ClientRequest {
|
||
2 years ago
|
pub fn id(&self) -> i64 {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
ClientRequest::V0(o) => o.id,
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
pub fn set_id(&mut self, id: i64) {
|
||
|
match self {
|
||
2 years ago
|
ClientRequest::V0(v0) => {
|
||
2 years ago
|
v0.id = id;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
2 years ago
|
pub fn content_v0(&self) -> &ClientRequestContentV0 {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
ClientRequest::V0(o) => &o.content,
|
||
2 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Response which blocks have been found locally. V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct BlocksFoundV0 {
|
||
|
/// Ids of Blocks that were found locally
|
||
|
pub found: Vec<BlockId>,
|
||
|
|
||
|
/// Ids of Blocks that were missing locally
|
||
|
pub missing: Vec<BlockId>,
|
||
|
}
|
||
|
|
||
|
/// Response which blocks have been found locally.
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum BlocksFound {
|
||
|
V0(BlocksFoundV0),
|
||
|
}
|
||
|
|
||
|
impl BlocksFound {
|
||
|
pub fn found(&self) -> &Vec<BlockId> {
|
||
|
match self {
|
||
|
BlocksFound::V0(o) => &o.found,
|
||
|
}
|
||
|
}
|
||
|
pub fn missing(&self) -> &Vec<BlockId> {
|
||
|
match self {
|
||
|
BlocksFound::V0(o) => &o.missing,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
/// Content of `ClientResponseV0`
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
2 years ago
|
pub enum ClientResponseContentV0 {
|
||
|
EmptyResponse,
|
||
2 years ago
|
Block(Block),
|
||
11 months ago
|
TopicSyncRes(TopicSyncRes),
|
||
|
BlocksFound(BlocksFound),
|
||
|
RepoPinStatus(RepoPinStatus),
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
/// Response to a `ClientRequest`
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
2 years ago
|
pub struct ClientResponseV0 {
|
||
2 years ago
|
/// Request ID
|
||
2 years ago
|
pub id: i64,
|
||
2 years ago
|
|
||
|
/// Result (including but not limited to Result)
|
||
|
pub result: u16,
|
||
|
|
||
|
/// Response content
|
||
2 years ago
|
pub content: ClientResponseContentV0,
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
/// Response to a `ClientRequest`
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
2 years ago
|
pub enum ClientResponse {
|
||
|
V0(ClientResponseV0),
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
impl ClientResponse {
|
||
2 years ago
|
pub fn id(&self) -> i64 {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
ClientResponse::V0(o) => o.id,
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
pub fn set_id(&mut self, id: i64) {
|
||
|
match self {
|
||
2 years ago
|
ClientResponse::V0(v0) => {
|
||
2 years ago
|
v0.id = id;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
2 years ago
|
pub fn result(&self) -> u16 {
|
||
|
match self {
|
||
2 years ago
|
ClientResponse::V0(o) => o.result,
|
||
2 years ago
|
}
|
||
|
}
|
||
|
pub fn block(&self) -> Option<&Block> {
|
||
|
match self {
|
||
2 years ago
|
ClientResponse::V0(o) => match &o.content {
|
||
|
ClientResponseContentV0::Block(b) => Some(b),
|
||
2 years ago
|
_ => panic!("this not a block response"),
|
||
2 years ago
|
},
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
/// Content of `ClientMessageV0`
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
2 years ago
|
pub enum ClientMessageContentV0 {
|
||
|
ClientRequest(ClientRequest),
|
||
|
ClientResponse(ClientResponse),
|
||
11 months ago
|
ForwardedEvent(Event),
|
||
11 months ago
|
ForwardedBlock(Block),
|
||
2 years ago
|
}
|
||
|
/// Broker message for an overlay
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
2 years ago
|
pub struct ClientMessageV0 {
|
||
2 years ago
|
pub overlay: OverlayId,
|
||
2 years ago
|
pub content: ClientMessageContentV0,
|
||
|
/// Optional padding
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub padding: Vec<u8>,
|
||
2 years ago
|
}
|
||
|
|
||
|
/// Broker message for an overlay
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
2 years ago
|
pub enum ClientMessage {
|
||
|
V0(ClientMessageV0),
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
impl ClientMessage {
|
||
|
pub fn content_v0(&self) -> &ClientMessageContentV0 {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
ClientMessage::V0(o) => &o.content,
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
pub fn overlay_request(&self) -> &ClientRequest {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
ClientMessage::V0(o) => match &o.content {
|
||
|
ClientMessageContentV0::ClientRequest(r) => &r,
|
||
2 years ago
|
_ => panic!("not an overlay request"),
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
pub fn overlay_id(&self) -> OverlayId {
|
||
|
match self {
|
||
2 years ago
|
ClientMessage::V0(o) => o.overlay,
|
||
2 years ago
|
}
|
||
|
}
|
||
|
pub fn is_request(&self) -> bool {
|
||
|
match self {
|
||
2 years ago
|
ClientMessage::V0(o) => {
|
||
|
matches!(o.content, ClientMessageContentV0::ClientRequest { .. })
|
||
|
}
|
||
2 years ago
|
}
|
||
|
}
|
||
|
pub fn is_response(&self) -> bool {
|
||
|
match self {
|
||
2 years ago
|
ClientMessage::V0(o) => {
|
||
|
matches!(o.content, ClientMessageContentV0::ClientResponse { .. })
|
||
|
}
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
pub fn id(&self) -> i64 {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
ClientMessage::V0(o) => match &o.content {
|
||
|
ClientMessageContentV0::ClientResponse(r) => r.id(),
|
||
|
ClientMessageContentV0::ClientRequest(r) => r.id(),
|
||
11 months ago
|
ClientMessageContentV0::ForwardedEvent(_)
|
||
|
| ClientMessageContentV0::ForwardedBlock(_) => {
|
||
2 years ago
|
panic!("it is an event")
|
||
|
}
|
||
|
},
|
||
|
}
|
||
|
}
|
||
2 years ago
|
pub fn set_id(&mut self, id: i64) {
|
||
|
match self {
|
||
2 years ago
|
ClientMessage::V0(o) => match &mut o.content {
|
||
|
ClientMessageContentV0::ClientResponse(ref mut r) => r.set_id(id),
|
||
|
ClientMessageContentV0::ClientRequest(ref mut r) => r.set_id(id),
|
||
11 months ago
|
ClientMessageContentV0::ForwardedEvent(_)
|
||
|
| ClientMessageContentV0::ForwardedBlock(_) => {
|
||
2 years ago
|
panic!("it is an event")
|
||
|
}
|
||
|
},
|
||
|
}
|
||
|
}
|
||
2 years ago
|
pub fn result(&self) -> u16 {
|
||
|
match self {
|
||
2 years ago
|
ClientMessage::V0(o) => match &o.content {
|
||
|
ClientMessageContentV0::ClientResponse(r) => r.result(),
|
||
11 months ago
|
ClientMessageContentV0::ClientRequest(_)
|
||
|
| ClientMessageContentV0::ForwardedEvent(_)
|
||
|
| ClientMessageContentV0::ForwardedBlock(_) => {
|
||
2 years ago
|
panic!("it is not a response");
|
||
|
}
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
pub fn block<'a>(&self) -> Option<&Block> {
|
||
|
match self {
|
||
2 years ago
|
ClientMessage::V0(o) => match &o.content {
|
||
|
ClientMessageContentV0::ClientResponse(r) => r.block(),
|
||
11 months ago
|
ClientMessageContentV0::ClientRequest(_)
|
||
|
| ClientMessageContentV0::ForwardedEvent(_)
|
||
|
| ClientMessageContentV0::ForwardedBlock(_) => {
|
||
2 years ago
|
panic!("it is not a response");
|
||
|
}
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// EXTERNAL REQUESTS
|
||
|
//
|
||
|
|
||
|
/// Request object(s) by ID from a repository by non-members
|
||
|
///
|
||
|
/// The request is sent by a non-member to an overlay member node,
|
||
|
/// which has a replica of the repository.
|
||
|
///
|
||
|
/// The response includes the requested objects and all their children recursively,
|
||
|
/// and optionally all object dependencies recursively.
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct ExtObjectGetV0 {
|
||
|
/// Repository to request the objects from
|
||
|
pub repo: PubKey,
|
||
|
|
||
|
/// List of Object IDs to request, including their children
|
||
|
pub ids: Vec<ObjectId>,
|
||
|
|
||
|
/// Whether or not to include all children recursively
|
||
|
pub include_children: bool,
|
||
|
|
||
|
/// Expiry time after which the link becomes invalid
|
||
|
pub expiry: Option<Timestamp>,
|
||
|
}
|
||
|
|
||
|
/// Request object(s) by ID from a repository by non-members
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum ExtObjectGet {
|
||
|
V0(ExtObjectGetV0),
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Topic synchronization request
|
||
|
pub type ExtTopicSyncReq = TopicSyncReq;
|
||
2 years ago
|
|
||
|
/// Content of ExtRequestV0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum ExtRequestContentV0 {
|
||
|
ExtObjectGet(ExtObjectGet),
|
||
11 months ago
|
ExtTopicSyncReq(ExtTopicSyncReq),
|
||
|
// TODO inbox requests
|
||
|
// TODO subreq ?
|
||
2 years ago
|
}
|
||
|
|
||
|
/// External request with its request ID
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct ExtRequestV0 {
|
||
11 months ago
|
/// outer overlayId
|
||
|
pub overlay: Digest,
|
||
|
|
||
2 years ago
|
/// Request ID
|
||
2 years ago
|
pub id: i64,
|
||
2 years ago
|
|
||
11 months ago
|
/// Request content
|
||
|
pub content: ExtRequestContentV0,
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// External request are made by clients directly to a core broker of their choice.
|
||
|
/// They differ from OuterOverlayRequests in the sense that the broker where the client is attached, is not involved in the request.
|
||
|
/// It is a direct connection that is established between the client and the core broker that will give the response.
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum ExtRequest {
|
||
|
V0(ExtRequestV0),
|
||
|
}
|
||
|
|
||
2 years ago
|
impl ExtRequest {
|
||
|
pub fn id(&self) -> i64 {
|
||
|
match self {
|
||
|
ExtRequest::V0(v0) => v0.id,
|
||
|
}
|
||
|
}
|
||
2 years ago
|
pub fn set_id(&mut self, id: i64) {
|
||
|
match self {
|
||
|
ExtRequest::V0(v0) => {
|
||
|
v0.id = id;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
/// Content of ExtResponseV0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum ExtResponseContentV0 {
|
||
|
Block(Block),
|
||
11 months ago
|
// TODO inbox related replies
|
||
|
// TODO event ?
|
||
2 years ago
|
}
|
||
|
|
||
|
/// Response to an ExtRequest
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct ExtResponseV0 {
|
||
|
/// Request ID
|
||
2 years ago
|
pub id: i64,
|
||
2 years ago
|
|
||
|
/// Result code
|
||
|
pub result: u16,
|
||
|
|
||
|
/// Response content
|
||
|
pub content: Option<ExtResponseContentV0>,
|
||
|
}
|
||
|
|
||
|
/// Response to an ExtRequest
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum ExtResponse {
|
||
|
V0(ExtResponseV0),
|
||
|
}
|
||
|
|
||
2 years ago
|
impl ExtResponse {
|
||
|
pub fn id(&self) -> i64 {
|
||
|
match self {
|
||
|
ExtResponse::V0(v0) => v0.id,
|
||
|
}
|
||
|
}
|
||
2 years ago
|
pub fn set_id(&mut self, id: i64) {
|
||
|
match self {
|
||
|
ExtResponse::V0(v0) => {
|
||
|
v0.id = id;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
2 years ago
|
}
|
||
|
|
||
|
impl TryFrom<ProtocolMessage> for ExtResponse {
|
||
|
type Error = ProtocolError;
|
||
|
fn try_from(msg: ProtocolMessage) -> Result<Self, Self::Error> {
|
||
|
if let ProtocolMessage::ExtResponse(ext_res) = msg {
|
||
|
Ok(ext_res)
|
||
|
} else {
|
||
|
Err(ProtocolError::InvalidValue)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
///
|
||
|
/// PROTOCOL MESSAGES
|
||
|
///
|
||
2 years ago
|
|
||
|
pub static MAGIC_NG_REQUEST: [u8; 2] = [78u8, 71u8];
|
||
|
pub static MAGIC_NG_RESPONSE: [u8; 4] = [89u8, 88u8, 78u8, 75u8];
|
||
|
|
||
|
#[derive(Clone, Debug)]
|
||
|
pub enum Authorization {
|
||
|
Discover,
|
||
|
ExtMessage,
|
||
|
Core,
|
||
2 years ago
|
Client((PubKey, Option<Option<[u8; 32]>>)),
|
||
2 years ago
|
OverlayJoin(PubKey),
|
||
|
Admin(PubKey),
|
||
2 years ago
|
}
|
||
|
|
||
|
/// ProbeResponse
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct ProbeResponse {
|
||
|
/// Response Magic number
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub magic: Vec<u8>,
|
||
|
|
||
|
/// Used for discovery of broker on private LAN
|
||
|
/// see ListenerV0.discoverable
|
||
|
pub peer_id: Option<PubKey>,
|
||
|
}
|
||
|
|
||
|
/// RelayRequest
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct RelayRequest {
|
||
|
/// The BindAddress of the broker to relay to should be of the same IP family than the TunnelRequest.remote_addr
|
||
|
pub address: BindAddress,
|
||
|
}
|
||
|
|
||
|
/// RelayResponse
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct RelayResponse {
|
||
|
/// Response Magic number
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub magic: Vec<u8>,
|
||
|
|
||
|
/// result to the relay request (accept, refuse)
|
||
|
pub result: u16,
|
||
|
}
|
||
|
|
||
|
/// Tunnel Request
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct TunnelRequest {
|
||
|
/// Request Magic number
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub magic: Vec<u8>,
|
||
|
|
||
|
// Bind address of client as connected to the relaying broker.
|
||
|
pub remote_addr: BindAddress,
|
||
|
}
|
||
|
|
||
|
/// Tunnel Response
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct TunnelResponse {
|
||
|
/// Response Magic number
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub magic: Vec<u8>,
|
||
|
|
||
|
/// result to the tunnel request (accept, refuse)
|
||
|
pub result: u16,
|
||
|
}
|
||
|
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum ProtocolMessage {
|
||
2 years ago
|
Probe([u8; 2]),
|
||
|
ProbeResponse(ProbeResponse),
|
||
|
Relay(RelayRequest),
|
||
|
RelayResponse(RelayResponse),
|
||
|
Tunnel(TunnelRequest),
|
||
|
TunnelResponse(TunnelResponse),
|
||
2 years ago
|
Noise(Noise),
|
||
|
Start(StartProtocol),
|
||
|
ServerHello(ServerHello),
|
||
|
ClientAuth(ClientAuth),
|
||
|
AuthResult(AuthResult),
|
||
2 years ago
|
ExtRequest(ExtRequest),
|
||
2 years ago
|
ExtResponse(ExtResponse),
|
||
2 years ago
|
//AdminRequest(AdminRequest),
|
||
|
AdminResponse(AdminResponse),
|
||
|
ClientMessage(ClientMessage),
|
||
|
CoreMessage(CoreMessage),
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
impl ProtocolMessage {
|
||
|
pub fn id(&self) -> i64 {
|
||
|
match self {
|
||
|
ProtocolMessage::ExtRequest(ext_req) => ext_req.id(),
|
||
|
ProtocolMessage::ExtResponse(ext_res) => ext_res.id(),
|
||
2 years ago
|
ProtocolMessage::ClientMessage(client_msg) => client_msg.id(),
|
||
2 years ago
|
_ => 0,
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
pub fn set_id(&mut self, id: i64) {
|
||
|
match self {
|
||
|
ProtocolMessage::ExtRequest(ext_req) => ext_req.set_id(id),
|
||
|
ProtocolMessage::ExtResponse(ext_res) => ext_res.set_id(id),
|
||
2 years ago
|
ProtocolMessage::ClientMessage(client_msg) => client_msg.set_id(id),
|
||
2 years ago
|
_ => panic!("cannot set ID"),
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
pub fn type_id(&self) -> TypeId {
|
||
|
match self {
|
||
|
ProtocolMessage::Noise(a) => a.type_id(),
|
||
|
ProtocolMessage::Start(a) => a.type_id(),
|
||
|
ProtocolMessage::ServerHello(a) => a.type_id(),
|
||
|
ProtocolMessage::ClientAuth(a) => a.type_id(),
|
||
|
ProtocolMessage::AuthResult(a) => a.type_id(),
|
||
|
ProtocolMessage::ExtRequest(a) => a.type_id(),
|
||
|
ProtocolMessage::ExtResponse(a) => a.type_id(),
|
||
2 years ago
|
ProtocolMessage::ClientMessage(a) => a.type_id(),
|
||
|
ProtocolMessage::CoreMessage(a) => a.type_id(),
|
||
|
//ProtocolMessage::AdminRequest(a) => a.type_id(),
|
||
|
ProtocolMessage::AdminResponse(a) => a.type_id(),
|
||
2 years ago
|
ProtocolMessage::Probe(a) => a.type_id(),
|
||
|
ProtocolMessage::ProbeResponse(a) => a.type_id(),
|
||
|
ProtocolMessage::Relay(a) => a.type_id(),
|
||
|
ProtocolMessage::RelayResponse(a) => a.type_id(),
|
||
|
ProtocolMessage::Tunnel(a) => a.type_id(),
|
||
|
ProtocolMessage::TunnelResponse(a) => a.type_id(),
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
|
||
2 years ago
|
pub fn get_actor(&self) -> Box<dyn EActor> {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
//ProtocolMessage::Noise(a) => a.get_actor(),
|
||
|
ProtocolMessage::Start(a) => a.get_actor(),
|
||
|
// ProtocolMessage::ServerHello(a) => a.get_actor(),
|
||
|
// ProtocolMessage::ClientAuth(a) => a.get_actor(),
|
||
|
// ProtocolMessage::AuthResult(a) => a.get_actor(),
|
||
|
// ProtocolMessage::ExtRequest(a) => a.get_actor(),
|
||
|
// ProtocolMessage::ExtResponse(a) => a.get_actor(),
|
||
|
// ProtocolMessage::BrokerMessage(a) => a.get_actor(),
|
||
|
_ => unimplemented!(),
|
||
2 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
///
|
||
|
/// AUTHENTICATION MESSAGES
|
||
|
///
|
||
|
|
||
2 years ago
|
/// Content of ClientAuthV0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct ClientAuthContentV0 {
|
||
|
/// User pub key
|
||
|
pub user: PubKey,
|
||
|
|
||
|
/// Client pub key
|
||
|
pub client: PubKey,
|
||
|
|
||
2 years ago
|
pub info: ClientInfoV0,
|
||
|
|
||
2 years ago
|
pub registration: Option<Option<[u8; 32]>>,
|
||
|
|
||
2 years ago
|
/// Nonce from ServerHello
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub nonce: Vec<u8>,
|
||
|
}
|
||
|
|
||
|
/// Client authentication
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct ClientAuthV0 {
|
||
|
/// Authentication data
|
||
|
pub content: ClientAuthContentV0,
|
||
|
|
||
2 years ago
|
/// Signature by user key
|
||
2 years ago
|
pub sig: Sig,
|
||
10 months ago
|
|
||
|
/// Signature by client key
|
||
|
pub client_sig: Sig,
|
||
2 years ago
|
}
|
||
|
|
||
|
/// Client authentication
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum ClientAuth {
|
||
|
V0(ClientAuthV0),
|
||
|
}
|
||
|
|
||
|
impl ClientAuth {
|
||
|
pub fn content_v0(&self) -> ClientAuthContentV0 {
|
||
|
match self {
|
||
|
ClientAuth::V0(o) => o.content.clone(),
|
||
|
}
|
||
|
}
|
||
|
pub fn sig(&self) -> Sig {
|
||
|
match self {
|
||
|
ClientAuth::V0(o) => o.sig,
|
||
|
}
|
||
|
}
|
||
|
pub fn user(&self) -> PubKey {
|
||
|
match self {
|
||
|
ClientAuth::V0(o) => o.content.user,
|
||
|
}
|
||
|
}
|
||
|
pub fn client(&self) -> PubKey {
|
||
|
match self {
|
||
|
ClientAuth::V0(o) => o.content.client,
|
||
|
}
|
||
|
}
|
||
|
pub fn nonce(&self) -> &Vec<u8> {
|
||
|
match self {
|
||
|
ClientAuth::V0(o) => &o.content.nonce,
|
||
|
}
|
||
|
}
|
||
2 years ago
|
pub fn registration(&self) -> Option<Option<[u8; 32]>> {
|
||
|
match self {
|
||
|
ClientAuth::V0(o) => o.content.registration,
|
||
|
}
|
||
|
}
|
||
2 years ago
|
}
|
||
|
|
||
2 years ago
|
impl From<ClientAuth> for ProtocolMessage {
|
||
|
fn from(msg: ClientAuth) -> ProtocolMessage {
|
||
|
ProtocolMessage::ClientAuth(msg)
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
/// Authentication result
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct AuthResultV0 {
|
||
|
pub result: u16,
|
||
|
#[serde(with = "serde_bytes")]
|
||
|
pub metadata: Vec<u8>,
|
||
|
}
|
||
|
|
||
|
/// Authentication result
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum AuthResult {
|
||
|
V0(AuthResultV0),
|
||
|
}
|
||
|
|
||
|
impl AuthResult {
|
||
|
pub fn result(&self) -> u16 {
|
||
|
match self {
|
||
|
AuthResult::V0(o) => o.result,
|
||
|
}
|
||
|
}
|
||
|
pub fn metadata(&self) -> &Vec<u8> {
|
||
|
match self {
|
||
|
AuthResult::V0(o) => &o.metadata,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
impl From<AuthResult> for ProtocolMessage {
|
||
|
fn from(msg: AuthResult) -> ProtocolMessage {
|
||
|
ProtocolMessage::AuthResult(msg)
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
//
|
||
11 months ago
|
// LINKS
|
||
2 years ago
|
//
|
||
|
|
||
11 months ago
|
/// Link to a repository
|
||
|
/// Consists of an identifier (repoid), a ReadCap or WriteCap, and a locator (peers and overlayLink)
|
||
|
/// Those capabilities are not durable: They can be refreshed by the members and previously shared Caps will become obsolete/revoked.
|
||
|
/// 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.
|
||
|
/// But if they don't subscribe, they will lose access after the refresh.
|
||
10 months ago
|
/// For durable capabilities, see PermaCap.
|
||
|
/// 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
|
||
11 months ago
|
/// Perma capabilities are needed only when the link is stored on disk and kept there unopened for a long period.
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct RepoLinkV0 {
|
||
11 months ago
|
/// Repository ID
|
||
|
pub id: RepoId,
|
||
2 years ago
|
|
||
11 months ago
|
/// read capability for the whole repo
|
||
|
/// current (at the time of sharing the link) root branch definition commit
|
||
|
pub read_cap: ReadCap,
|
||
11 months ago
|
|
||
11 months ago
|
/// Write capability secret. Only set for editors. in this case, overlay MUST be set to an InnerOverlay
|
||
10 months ago
|
// pub write_cap_secret: Option<RepoWriteCapSecret>,
|
||
2 years ago
|
|
||
11 months ago
|
/// Current overlay link, used to join the overlay
|
||
|
pub overlay: OverlayLink,
|
||
2 years ago
|
|
||
11 months ago
|
/// Peer brokers to connect to
|
||
2 years ago
|
pub peers: Vec<PeerAdvert>,
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Link to a repository
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum RepoLink {
|
||
|
V0(RepoLinkV0),
|
||
|
}
|
||
|
|
||
|
impl RepoLink {
|
||
11 months ago
|
pub fn id(&self) -> &RepoId {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
RepoLink::V0(o) => &o.id,
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
pub fn peers(&self) -> &Vec<PeerAdvert> {
|
||
2 years ago
|
match self {
|
||
2 years ago
|
RepoLink::V0(o) => &o.peers,
|
||
2 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
11 months ago
|
/// The latest ReadCap of the branch (or main branch) will be downloaded from the outerOverlay, if the peer brokers listed below allow it.
|
||
|
/// The snapshot can be downloaded instead
|
||
|
/// This locator is durable, because the public site are served differently by brokers.
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub struct PublicRepoLocatorV0 {
|
||
|
/// Repository ID
|
||
|
pub repo: RepoId,
|
||
|
|
||
|
/// optional branchId to access. a specific public branch,
|
||
|
/// if not set, the main branch of the repo will be used.
|
||
|
pub branch: Option<BranchId>,
|
||
|
|
||
|
/// optional commits of head to access.
|
||
|
/// if not set, the main branch of the repo will be used.
|
||
|
pub heads: Vec<ObjectRef>,
|
||
|
|
||
|
/// optional snapshot to download, in order to display the content quicker to end-user.
|
||
|
pub snapshot: Option<ObjectRef>,
|
||
|
|
||
|
/// The public site store
|
||
|
pub public_store: PubKey,
|
||
|
|
||
|
/// Peer brokers to connect to
|
||
|
pub peers: Vec<PeerAdvert>,
|
||
|
}
|
||
2 years ago
|
|
||
11 months ago
|
/// Link to a public repository
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum PublicRepoLocator {
|
||
|
V0(PublicRepoLocatorV0),
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Read access to a branch of a Public, Protected or Group store.
|
||
|
/// The overlay to join can be the outer or the inner, depending on what was offered in the link.
|
||
|
/// The difference between the two is that in the outer overlay, only one broker is contacted.
|
||
|
/// In the inner overlay, all the publisher's brokers are contacted, so subscription to the pub/sub is more reliable, less prone to outage.
|
||
|
/// This is not a durable link. If the topic has been refreshed, the pubsub won't be able to be subscribed to,
|
||
|
/// but TopicSyncReq will still work (answering the commits up until the moment the topic was refreshed)
|
||
|
/// and the optional heads will always be retrievable
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub struct ReadBranchLinkV0 {
|
||
|
/// Repository ID
|
||
|
pub repo: RepoId,
|
||
|
|
||
|
pub branch: BranchId, // must match the one in read_cap
|
||
|
|
||
10 months ago
|
/// an optional list of heads that can be fetched in this branch
|
||
11 months ago
|
/// useful if a specific head is to be shared
|
||
|
pub heads: Vec<ObjectRef>,
|
||
|
|
||
|
/// read capability for the branch
|
||
|
/// current (at the time of sharing the link) branch definition commit
|
||
|
pub read_cap: ReadCap,
|
||
|
|
||
|
/// Current overlay link, used to join the overlay, most of the time, an outerOverlay is preferred
|
||
|
pub overlay: OverlayLink,
|
||
|
|
||
|
/// Peer brokers to connect to
|
||
|
pub peers: Vec<PeerAdvert>,
|
||
2 years ago
|
}
|
||
|
|
||
11 months ago
|
/// Link to a repository
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub enum ReadBranchLink {
|
||
|
V0(ReadBranchLinkV0),
|
||
|
}
|
||
2 years ago
|
|
||
11 months ago
|
/// Obtains one or more objects of a repo (Commit, File) by their ID.
|
||
|
/// 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
|
||
|
/// If the intent is to share a whole DAG of commits at a definite CommitID/HEAD, then ReadBranchLink should be used instead (or PublicRepoLocator if public site)
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub struct ObjectLinkV0 {
|
||
|
/// 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.
|
||
|
/// (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)
|
||
|
/// 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.
|
||
|
pub repo: Option<RepoId>,
|
||
|
|
||
|
/// An optional topic that will be used to retrieve the Certificate of a commit, if needed
|
||
|
/// (topic has to be checked with the one inside the commit. the one here might be wrong. it is provided here as an optimization)
|
||
|
/// or can be used to help with BlockSearchTopic.
|
||
10 months ago
|
/// 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),
|
||
11 months ago
|
/// hence defeating the "emptied header" protection
|
||
|
pub topic: Option<TopicId>,
|
||
|
|
||
|
pub objects: Vec<ObjectRef>,
|
||
|
|
||
|
/// Overlay to join
|
||
|
pub overlay: OverlayLink,
|
||
2 years ago
|
|
||
11 months ago
|
/// Peer brokers to connect to
|
||
2 years ago
|
pub peers: Vec<PeerAdvert>,
|
||
|
}
|
||
|
|
||
11 months ago
|
/// Link to a specific commit, without its causal past
|
||
2 years ago
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
11 months ago
|
pub enum ObjectLink {
|
||
|
V0(ObjectLinkV0),
|
||
2 years ago
|
}
|
||
2 years ago
|
|
||
11 months ago
|
/// NextGraph Link V0
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum NgLinkV0 {
|
||
|
Repo(RepoLink),
|
||
|
PublicRepo(PublicRepoLocator),
|
||
|
Branch(ReadBranchLink),
|
||
|
Object(ObjectLink),
|
||
|
}
|
||
|
|
||
|
/// NextGraph Link
|
||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||
|
pub enum NgLink {
|
||
|
V0(NgLinkV0),
|
||
|
}
|
||
|
|
||
|
// TODO: PermaLinks and PostInbox (and ExtRequests)
|
||
|
|
||
2 years ago
|
#[cfg(test)]
|
||
|
mod test {
|
||
|
|
||
|
use crate::types::{BootstrapContentV0, BrokerServerTypeV0, BrokerServerV0, Invitation};
|
||
10 months ago
|
use ng_repo::types::PubKey;
|
||
2 years ago
|
|
||
|
#[test]
|
||
|
pub fn invitation() {
|
||
|
let inv = Invitation::new_v0(
|
||
|
BootstrapContentV0 {
|
||
|
servers: vec![BrokerServerV0 {
|
||
|
server_type: BrokerServerTypeV0::Localhost(14400),
|
||
|
peer_id: PubKey::Ed25519PubKey([
|
||
|
95, 73, 225, 250, 3, 147, 24, 164, 177, 211, 34, 244, 45, 130, 111, 136,
|
||
|
229, 145, 53, 167, 50, 168, 140, 227, 65, 111, 203, 41, 210, 186, 162, 149,
|
||
|
]),
|
||
|
}],
|
||
|
},
|
||
|
Some("test invitation".to_string()),
|
||
|
None,
|
||
|
);
|
||
|
|
||
|
println!("{:?}", inv.get_urls());
|
||
|
}
|
||
|
}
|