mirror of
https://gitlab.com/veilid/veilid.git
synced 2024-10-01 01:26:08 -04:00
xfer
This commit is contained in:
parent
60c4648530
commit
ed0049dc22
@ -2,6 +2,7 @@ use crate::xx::*;
|
|||||||
use crate::*;
|
use crate::*;
|
||||||
use data_encoding::BASE64URL_NOPAD;
|
use data_encoding::BASE64URL_NOPAD;
|
||||||
use keyring_manager::*;
|
use keyring_manager::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
pub struct ProtectedStoreInner {
|
pub struct ProtectedStoreInner {
|
||||||
@ -31,15 +32,18 @@ impl ProtectedStore {
|
|||||||
#[instrument(level = "trace", skip(self), err)]
|
#[instrument(level = "trace", skip(self), err)]
|
||||||
pub async fn delete_all(&self) -> EyreResult<()> {
|
pub async fn delete_all(&self) -> EyreResult<()> {
|
||||||
// Delete all known keys
|
// Delete all known keys
|
||||||
if self.remove_user_secret_string("node_id").await? {
|
if self.remove_user_secret("node_id").await? {
|
||||||
debug!("deleted protected_store key 'node_id'");
|
debug!("deleted protected_store key 'node_id'");
|
||||||
}
|
}
|
||||||
if self.remove_user_secret_string("node_id_secret").await? {
|
if self.remove_user_secret("node_id_secret").await? {
|
||||||
debug!("deleted protected_store key 'node_id_secret'");
|
debug!("deleted protected_store key 'node_id_secret'");
|
||||||
}
|
}
|
||||||
if self.remove_user_secret_string("_test_key").await? {
|
if self.remove_user_secret("_test_key").await? {
|
||||||
debug!("deleted protected_store key '_test_key'");
|
debug!("deleted protected_store key '_test_key'");
|
||||||
}
|
}
|
||||||
|
if self.remove_user_secret("RouteSpecStore").await? {
|
||||||
|
debug!("deleted protected_store key 'RouteSpecStore'");
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,19 +143,30 @@ impl ProtectedStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "trace", skip(self), ret, err)]
|
#[instrument(level = "trace", skip(self, value), ret, err)]
|
||||||
pub async fn remove_user_secret_string(&self, key: &str) -> EyreResult<bool> {
|
pub async fn save_user_secret_cbor<T>(&self, key: &str, value: &T) -> EyreResult<bool>
|
||||||
let inner = self.inner.lock();
|
where
|
||||||
match inner
|
T: Serialize,
|
||||||
.keyring_manager
|
{
|
||||||
.as_ref()
|
let v = serde_cbor::to_vec(value).wrap_err("couldn't store as CBOR")?;
|
||||||
.ok_or_else(|| eyre!("Protected store not initialized"))?
|
self.save_user_secret(&key, &v).await
|
||||||
.with_keyring(&self.service_name(), key, |kr| kr.delete_value())
|
}
|
||||||
{
|
|
||||||
Ok(_) => Ok(true),
|
#[instrument(level = "trace", skip(self), err)]
|
||||||
Err(KeyringError::NoPasswordFound) => Ok(false),
|
pub async fn load_user_secret_cbor<T>(&self, key: &str) -> EyreResult<Option<T>>
|
||||||
Err(e) => Err(eyre!("Failed to remove user secret: {}", e)),
|
where
|
||||||
}
|
T: for<'de> Deserialize<'de>,
|
||||||
|
{
|
||||||
|
let out = self.load_user_secret(key).await?;
|
||||||
|
let b = match out {
|
||||||
|
Some(v) => v,
|
||||||
|
None => {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let obj = serde_cbor::from_slice::<T>(&b).wrap_err("failed to deserialize")?;
|
||||||
|
Ok(Some(obj))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "trace", skip(self, value), ret, err)]
|
#[instrument(level = "trace", skip(self, value), ret, err)]
|
||||||
@ -195,6 +210,16 @@ impl ProtectedStore {
|
|||||||
|
|
||||||
#[instrument(level = "trace", skip(self), ret, err)]
|
#[instrument(level = "trace", skip(self), ret, err)]
|
||||||
pub async fn remove_user_secret(&self, key: &str) -> EyreResult<bool> {
|
pub async fn remove_user_secret(&self, key: &str) -> EyreResult<bool> {
|
||||||
self.remove_user_secret_string(key).await
|
let inner = self.inner.lock();
|
||||||
|
match inner
|
||||||
|
.keyring_manager
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| eyre!("Protected store not initialized"))?
|
||||||
|
.with_keyring(&self.service_name(), key, |kr| kr.delete_value())
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(true),
|
||||||
|
Err(KeyringError::NoPasswordFound) => Ok(false),
|
||||||
|
Err(e) => Err(eyre!("Failed to remove user secret: {}", e)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,38 +17,40 @@ extern "C" {
|
|||||||
fn keytar_deletePassword(service: &str, account: &str) -> Result<Promise, JsValue>;
|
fn keytar_deletePassword(service: &str, account: &str) -> Result<Promise, JsValue>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ProtectedStore {
|
pub struct ProtectedStore {
|
||||||
config: VeilidConfig,
|
config: VeilidConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProtectedStore {
|
impl ProtectedStore {
|
||||||
|
|
||||||
pub fn new(config: VeilidConfig) -> Self {
|
pub fn new(config: VeilidConfig) -> Self {
|
||||||
Self {
|
Self { config }
|
||||||
config,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(self), err)]
|
||||||
pub async fn delete_all(&self) -> EyreResult<()> {
|
pub async fn delete_all(&self) -> EyreResult<()> {
|
||||||
// Delete all known keys
|
// Delete all known keys
|
||||||
if self.remove_user_secret_string("node_id").await? {
|
if self.remove_user_secret("node_id").await? {
|
||||||
debug!("deleted protected_store key 'node_id'");
|
debug!("deleted protected_store key 'node_id'");
|
||||||
}
|
}
|
||||||
if self.remove_user_secret_string("node_id_secret").await? {
|
if self.remove_user_secret("node_id_secret").await? {
|
||||||
debug!("deleted protected_store key 'node_id_secret'");
|
debug!("deleted protected_store key 'node_id_secret'");
|
||||||
}
|
}
|
||||||
if self.remove_user_secret_string("_test_key").await? {
|
if self.remove_user_secret("_test_key").await? {
|
||||||
debug!("deleted protected_store key '_test_key'");
|
debug!("deleted protected_store key '_test_key'");
|
||||||
}
|
}
|
||||||
|
if self.remove_user_secret("RouteSpecStore").await? {
|
||||||
|
debug!("deleted protected_store key 'RouteSpecStore'");
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self), err)]
|
||||||
pub async fn init(&self) -> EyreResult<()> {
|
pub async fn init(&self) -> EyreResult<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self))]
|
||||||
pub async fn terminate(&self) {}
|
pub async fn terminate(&self) {}
|
||||||
|
|
||||||
fn keyring_name(&self) -> String {
|
fn keyring_name(&self) -> String {
|
||||||
@ -69,12 +71,13 @@ impl ProtectedStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(self, value), ret, err)]
|
||||||
pub async fn save_user_secret_string(&self, key: &str, value: &str) -> EyreResult<bool> {
|
pub async fn save_user_secret_string(&self, key: &str, value: &str) -> EyreResult<bool> {
|
||||||
if is_nodejs() {
|
if is_nodejs() {
|
||||||
let prev = match JsFuture::from(
|
let prev = match JsFuture::from(
|
||||||
keytar_getPassword(self.keyring_name().as_str(), key)
|
keytar_getPassword(self.keyring_name().as_str(), key)
|
||||||
.map_err(map_jsvalue_error)
|
.map_err(map_jsvalue_error)
|
||||||
.wrap_err("exception thrown")?,
|
.wrap_err("exception thrown")?,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
@ -84,8 +87,8 @@ impl ProtectedStore {
|
|||||||
|
|
||||||
match JsFuture::from(
|
match JsFuture::from(
|
||||||
keytar_setPassword(self.keyring_name().as_str(), key, value)
|
keytar_setPassword(self.keyring_name().as_str(), key, value)
|
||||||
.map_err(map_jsvalue_error)
|
.map_err(map_jsvalue_error)
|
||||||
.wrap_err("exception thrown")?,
|
.wrap_err("exception thrown")?,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
@ -134,6 +137,7 @@ impl ProtectedStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(self), err)]
|
||||||
pub async fn load_user_secret_string(&self, key: &str) -> EyreResult<Option<String>> {
|
pub async fn load_user_secret_string(&self, key: &str) -> EyreResult<Option<String>> {
|
||||||
if is_nodejs() {
|
if is_nodejs() {
|
||||||
let prev = match JsFuture::from(
|
let prev = match JsFuture::from(
|
||||||
@ -181,7 +185,73 @@ impl ProtectedStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn remove_user_secret_string(&self, key: &str) -> EyreResult<bool> {
|
#[instrument(level = "trace", skip(self, value), ret, err)]
|
||||||
|
pub async fn save_user_secret_cbor<T>(&self, key: &str, value: &T) -> EyreResult<bool>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
let v = serde_cbor::to_vec(value).wrap_err("couldn't store as CBOR")?;
|
||||||
|
self.save_user_secret(&key, &v).await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(self), err)]
|
||||||
|
pub async fn load_user_secret_cbor<T>(&self, key: &str) -> EyreResult<Option<T>>
|
||||||
|
where
|
||||||
|
T: for<'de> Deserialize<'de>,
|
||||||
|
{
|
||||||
|
let out = self.load_user_secret(key).await?;
|
||||||
|
let b = match out {
|
||||||
|
Some(v) => v,
|
||||||
|
None => {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let obj = serde_cbor::from_slice::<T>(&b).wrap_err("failed to deserialize")?;
|
||||||
|
Ok(Some(obj))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(self, value), ret, err)]
|
||||||
|
pub async fn save_user_secret(&self, key: &str, value: &[u8]) -> EyreResult<bool> {
|
||||||
|
let mut s = BASE64URL_NOPAD.encode(value);
|
||||||
|
s.push('!');
|
||||||
|
|
||||||
|
self.save_user_secret_string(key, s.as_str()).await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(self), err)]
|
||||||
|
pub async fn load_user_secret(&self, key: &str) -> EyreResult<Option<Vec<u8>>> {
|
||||||
|
let mut s = match self.load_user_secret_string(key).await? {
|
||||||
|
Some(s) => s,
|
||||||
|
None => {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if s.pop() != Some('!') {
|
||||||
|
bail!("User secret is not a buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut bytes = Vec::<u8>::new();
|
||||||
|
let res = BASE64URL_NOPAD.decode_len(s.len());
|
||||||
|
match res {
|
||||||
|
Ok(l) => {
|
||||||
|
bytes.resize(l, 0u8);
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
bail!("Failed to decode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = BASE64URL_NOPAD.decode_mut(s.as_bytes(), &mut bytes);
|
||||||
|
match res {
|
||||||
|
Ok(_) => Ok(Some(bytes)),
|
||||||
|
Err(_) => bail!("Failed to decode"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(self), ret, err)]
|
||||||
|
pub async fn remove_user_secret(&self, key: &str) -> EyreResult<bool> {
|
||||||
if is_nodejs() {
|
if is_nodejs() {
|
||||||
match JsFuture::from(
|
match JsFuture::from(
|
||||||
keytar_deletePassword(self.keyring_name().as_str(), key)
|
keytar_deletePassword(self.keyring_name().as_str(), key)
|
||||||
@ -231,45 +301,4 @@ impl ProtectedStore {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn save_user_secret(&self, key: &str, value: &[u8]) -> EyreResult<bool> {
|
|
||||||
let mut s = BASE64URL_NOPAD.encode(value);
|
|
||||||
s.push('!');
|
|
||||||
|
|
||||||
self.save_user_secret_string(key, s.as_str()).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn load_user_secret(&self, key: &str) -> EyreResult<Option<Vec<u8>>> {
|
|
||||||
let mut s = match self.load_user_secret_string(key).await? {
|
|
||||||
Some(s) => s,
|
|
||||||
None => {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if s.pop() != Some('!') {
|
|
||||||
bail!("User secret is not a buffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut bytes = Vec::<u8>::new();
|
|
||||||
let res = BASE64URL_NOPAD.decode_len(s.len());
|
|
||||||
match res {
|
|
||||||
Ok(l) => {
|
|
||||||
bytes.resize(l, 0u8);
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
bail!("Failed to decode");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let res = BASE64URL_NOPAD.decode_mut(s.as_bytes(), &mut bytes);
|
|
||||||
match res {
|
|
||||||
Ok(_) => Ok(Some(bytes)),
|
|
||||||
Err(_) => bail!("Failed to decode"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn remove_user_secret(&self, key: &str) -> EyreResult<bool> {
|
|
||||||
self.remove_user_secret_string(key).await
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1747,7 +1747,7 @@ impl NetworkManager {
|
|||||||
|
|
||||||
// Ignore these reports if we are currently detecting public dial info
|
// Ignore these reports if we are currently detecting public dial info
|
||||||
let net = self.net();
|
let net = self.net();
|
||||||
if net.doing_public_dial_info_check() {
|
if net.needs_public_dial_info_check() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,8 +63,6 @@ struct NetworkInner {
|
|||||||
enable_ipv6_local: bool,
|
enable_ipv6_local: bool,
|
||||||
/// set if we need to calculate our public dial info again
|
/// set if we need to calculate our public dial info again
|
||||||
needs_public_dial_info_check: bool,
|
needs_public_dial_info_check: bool,
|
||||||
/// set during the actual execution of the public dial info check to ensure we don't do it more than once
|
|
||||||
doing_public_dial_info_check: bool,
|
|
||||||
/// the punishment closure to enax
|
/// the punishment closure to enax
|
||||||
public_dial_info_check_punishment: Option<Box<dyn FnOnce() + Send + 'static>>,
|
public_dial_info_check_punishment: Option<Box<dyn FnOnce() + Send + 'static>>,
|
||||||
/// udp socket record for bound-first sockets, which are used to guarantee a port is available before
|
/// udp socket record for bound-first sockets, which are used to guarantee a port is available before
|
||||||
@ -116,7 +114,6 @@ impl Network {
|
|||||||
network_started: false,
|
network_started: false,
|
||||||
network_needs_restart: false,
|
network_needs_restart: false,
|
||||||
needs_public_dial_info_check: false,
|
needs_public_dial_info_check: false,
|
||||||
doing_public_dial_info_check: false,
|
|
||||||
public_dial_info_check_punishment: None,
|
public_dial_info_check_punishment: None,
|
||||||
protocol_config: Default::default(),
|
protocol_config: Default::default(),
|
||||||
static_public_dialinfo: ProtocolTypeSet::empty(),
|
static_public_dialinfo: ProtocolTypeSet::empty(),
|
||||||
@ -871,16 +868,11 @@ impl Network {
|
|||||||
inner.public_dial_info_check_punishment = punishment;
|
inner.public_dial_info_check_punishment = punishment;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn needs_public_dial_info_check(&self) -> bool {
|
pub fn needs_public_dial_info_check(&self) -> bool {
|
||||||
let inner = self.inner.lock();
|
let inner = self.inner.lock();
|
||||||
inner.needs_public_dial_info_check
|
inner.needs_public_dial_info_check
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn doing_public_dial_info_check(&self) -> bool {
|
|
||||||
let inner = self.inner.lock();
|
|
||||||
inner.doing_public_dial_info_check
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
|
|
||||||
#[instrument(level = "trace", skip(self), err)]
|
#[instrument(level = "trace", skip(self), err)]
|
||||||
|
@ -883,15 +883,11 @@ impl Network {
|
|||||||
l: u64,
|
l: u64,
|
||||||
t: u64,
|
t: u64,
|
||||||
) -> EyreResult<()> {
|
) -> EyreResult<()> {
|
||||||
// Note that we are doing the public dial info check
|
|
||||||
// We don't have to check this for concurrency, since this routine is run in a TickTask/SingleFuture
|
|
||||||
self.inner.lock().doing_public_dial_info_check = true;
|
|
||||||
|
|
||||||
// Do the public dial info check
|
// Do the public dial info check
|
||||||
let out = self.do_public_dial_info_check(stop_token, l, t).await;
|
let out = self.do_public_dial_info_check(stop_token, l, t).await;
|
||||||
|
|
||||||
// Done with public dial info check
|
// Done with public dial info check
|
||||||
self.inner.lock().doing_public_dial_info_check = false;
|
self.inner.lock().needs_public_dial_info_check = false;
|
||||||
|
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ impl Network {
|
|||||||
NetworkUnlockedInner {
|
NetworkUnlockedInner {
|
||||||
network_manager,
|
network_manager,
|
||||||
routing_table,
|
routing_table,
|
||||||
connection_manager
|
connection_manager,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +58,11 @@ impl Network {
|
|||||||
Self {
|
Self {
|
||||||
config: network_manager.config(),
|
config: network_manager.config(),
|
||||||
inner: Arc::new(Mutex::new(Self::new_inner())),
|
inner: Arc::new(Mutex::new(Self::new_inner())),
|
||||||
unlocked_inner: Arc::new(Self::new_unlocked_inner(network_manager, routing_table, connection_manager))
|
unlocked_inner: Arc::new(Self::new_unlocked_inner(
|
||||||
|
network_manager,
|
||||||
|
routing_table,
|
||||||
|
connection_manager,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,11 +324,14 @@ impl Network {
|
|||||||
|
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
|
|
||||||
pub fn set_needs_public_dial_info_check(&self, _punishment: Option<Box<dyn FnOnce() + Send + 'static>>) {
|
pub fn set_needs_public_dial_info_check(
|
||||||
|
&self,
|
||||||
|
_punishment: Option<Box<dyn FnOnce() + Send + 'static>>,
|
||||||
|
) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn doing_public_dial_info_check(&self) -> bool {
|
pub fn needs_public_dial_info_check(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ fn with_route_permutations(
|
|||||||
// initial permutation
|
// initial permutation
|
||||||
let mut permutation: Vec<usize> = Vec::with_capacity(hop_count);
|
let mut permutation: Vec<usize> = Vec::with_capacity(hop_count);
|
||||||
for n in 0..hop_count {
|
for n in 0..hop_count {
|
||||||
permutation[n] = start + n;
|
permutation.push(start + n);
|
||||||
}
|
}
|
||||||
// if we have one hop or two, then there's only one permutation
|
// if we have one hop or two, then there's only one permutation
|
||||||
if hop_count == 1 || hop_count == 2 {
|
if hop_count == 1 || hop_count == 2 {
|
||||||
@ -229,22 +229,17 @@ impl RouteSpecStore {
|
|||||||
|
|
||||||
// Load secrets from pstore
|
// Load secrets from pstore
|
||||||
let pstore = routing_table.network_manager().protected_store();
|
let pstore = routing_table.network_manager().protected_store();
|
||||||
|
let out: Vec<(DHTKey, DHTKeySecret)> = pstore
|
||||||
|
.load_user_secret_cbor("RouteSpecStore")
|
||||||
|
.await?
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
let mut dead_keys = Vec::new();
|
let mut dead_keys = Vec::new();
|
||||||
for (k, v) in &mut content.details {
|
for (k, v) in out {
|
||||||
if let Some(secret_key) = pstore
|
if let Some(rsd) = content.details.get_mut(&k) {
|
||||||
.load_user_secret(&format!("RouteSpecStore_{}", k.encode()))
|
rsd.secret_key = v;
|
||||||
.await?
|
|
||||||
{
|
|
||||||
match secret_key.try_into() {
|
|
||||||
Ok(s) => {
|
|
||||||
v.secret_key = DHTKeySecret::new(s);
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
dead_keys.push(*k);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
dead_keys.push(*k);
|
dead_keys.push(k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for k in dead_keys {
|
for k in dead_keys {
|
||||||
@ -293,18 +288,14 @@ impl RouteSpecStore {
|
|||||||
.routing_table
|
.routing_table
|
||||||
.network_manager()
|
.network_manager()
|
||||||
.protected_store();
|
.protected_store();
|
||||||
|
|
||||||
|
let mut out: Vec<(DHTKey, DHTKeySecret)> = Vec::with_capacity(content.details.len());
|
||||||
for (k, v) in &content.details {
|
for (k, v) in &content.details {
|
||||||
if pstore
|
out.push((*k, v.secret_key));
|
||||||
.save_user_secret(
|
|
||||||
&format!("RouteSpecStore_{}", k.encode()),
|
|
||||||
&v.secret_key.bytes,
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
{
|
|
||||||
panic!("route spec should not already have secret key saved");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _ = pstore.save_user_secret_cbor("RouteSpecStore", &out).await?; // ignore if this previously existed or not
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,6 +337,14 @@ impl RouteSpecStore {
|
|||||||
inner.content.details.get_mut(public_key)
|
inner.content.details.get_mut(public_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Purge the route spec store
|
||||||
|
pub async fn purge(&self) -> EyreResult<()> {
|
||||||
|
let inner = &mut *self.inner.lock();
|
||||||
|
inner.content = Default::default();
|
||||||
|
inner.cache = Default::default();
|
||||||
|
self.save().await
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new route
|
/// Create a new route
|
||||||
/// Prefers nodes that are not currently in use by another route
|
/// Prefers nodes that are not currently in use by another route
|
||||||
/// The route is not yet tested for its reachability
|
/// The route is not yet tested for its reachability
|
||||||
@ -675,7 +674,7 @@ impl RouteSpecStore {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn release_route(&self, public_key: DHTKey) {
|
pub fn release_route(&self, public_key: DHTKey) -> EyreResult<()> {
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
if let Some(detail) = inner.content.details.remove(&public_key) {
|
if let Some(detail) = inner.content.details.remove(&public_key) {
|
||||||
// Remove from hop cache
|
// Remove from hop cache
|
||||||
@ -710,8 +709,9 @@ impl RouteSpecStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("can't release route that was never allocated");
|
bail!("can't release route that was never allocated");
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find first matching unpublished route that fits into the selection criteria
|
/// Find first matching unpublished route that fits into the selection criteria
|
||||||
@ -739,6 +739,22 @@ impl RouteSpecStore {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// List all routes
|
||||||
|
pub fn list_routes(&self) -> Vec<DHTKey> {
|
||||||
|
let inner = self.inner.lock();
|
||||||
|
let mut out = Vec::with_capacity(inner.content.details.len());
|
||||||
|
for detail in &inner.content.details {
|
||||||
|
out.push(*detail.0);
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the debug description of a route
|
||||||
|
pub fn debug_route(&self, key: &DHTKey) -> Option<String> {
|
||||||
|
let inner = &*self.inner.lock();
|
||||||
|
Self::detail(inner, key).map(|rsd| format!("{:#?}", rsd))
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// Compiles a safety route to the private route, with caching
|
/// Compiles a safety route to the private route, with caching
|
||||||
@ -973,17 +989,18 @@ impl RouteSpecStore {
|
|||||||
/// Assemble private route for publication
|
/// Assemble private route for publication
|
||||||
pub fn assemble_private_route(
|
pub fn assemble_private_route(
|
||||||
&self,
|
&self,
|
||||||
rti: &RoutingTableInner,
|
|
||||||
routing_table: RoutingTable,
|
|
||||||
key: &DHTKey,
|
key: &DHTKey,
|
||||||
|
optimize: Option<bool>,
|
||||||
) -> EyreResult<PrivateRoute> {
|
) -> EyreResult<PrivateRoute> {
|
||||||
let inner = &*self.inner.lock();
|
let inner = &*self.inner.lock();
|
||||||
|
let routing_table = self.unlocked_inner.routing_table.clone();
|
||||||
|
let rti = &*routing_table.inner.read();
|
||||||
|
|
||||||
let rsd = Self::detail(inner, &key).ok_or_else(|| eyre!("route does not exist"))?;
|
let rsd = Self::detail(inner, key).ok_or_else(|| eyre!("route does not exist"))?;
|
||||||
|
|
||||||
// See if we can optimize this compilation yet
|
// See if we can optimize this compilation yet
|
||||||
// We don't want to include full nodeinfo if we don't have to
|
// We don't want to include full nodeinfo if we don't have to
|
||||||
let optimize = rsd.reachable;
|
let optimize = optimize.unwrap_or(rsd.reachable);
|
||||||
|
|
||||||
// Make innermost route hop to our own node
|
// Make innermost route hop to our own node
|
||||||
let mut route_hop = RouteHop {
|
let mut route_hop = RouteHop {
|
||||||
@ -1053,79 +1070,79 @@ impl RouteSpecStore {
|
|||||||
/// Mark route as published
|
/// Mark route as published
|
||||||
/// When first deserialized, routes must be re-published in order to ensure they remain
|
/// When first deserialized, routes must be re-published in order to ensure they remain
|
||||||
/// in the RouteSpecStore.
|
/// in the RouteSpecStore.
|
||||||
pub fn mark_route_published(&mut self, key: &DHTKey) -> EyreResult<()> {
|
pub fn mark_route_published(&self, key: &DHTKey, published: bool) -> EyreResult<()> {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
Self::detail_mut(inner, &key)
|
Self::detail_mut(inner, key)
|
||||||
.ok_or_else(|| eyre!("route does not exist"))?
|
.ok_or_else(|| eyre!("route does not exist"))?
|
||||||
.published = true;
|
.published = published;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark route as reachable
|
/// Mark route as reachable
|
||||||
/// When first deserialized, routes must be re-tested for reachability
|
/// When first deserialized, routes must be re-tested for reachability
|
||||||
/// This can be used to determine if routes need to be sent with full peerinfo or can just use a node id
|
/// This can be used to determine if routes need to be sent with full peerinfo or can just use a node id
|
||||||
pub fn mark_route_reachable(&mut self, key: &DHTKey) -> EyreResult<()> {
|
pub fn mark_route_reachable(&self, key: &DHTKey, reachable: bool) -> EyreResult<()> {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
Self::detail_mut(inner, &key)
|
Self::detail_mut(inner, key)
|
||||||
.ok_or_else(|| eyre!("route does not exist"))?
|
.ok_or_else(|| eyre!("route does not exist"))?
|
||||||
.published = true;
|
.reachable = reachable;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark route as checked
|
/// Mark route as checked
|
||||||
pub fn touch_route_checked(&mut self, key: &DHTKey, cur_ts: u64) -> EyreResult<()> {
|
pub fn touch_route_checked(&self, key: &DHTKey, cur_ts: u64) -> EyreResult<()> {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
Self::detail_mut(inner, &key)
|
Self::detail_mut(inner, key)
|
||||||
.ok_or_else(|| eyre!("route does not exist"))?
|
.ok_or_else(|| eyre!("route does not exist"))?
|
||||||
.last_checked_ts = Some(cur_ts);
|
.last_checked_ts = Some(cur_ts);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark route as used
|
/// Mark route as used
|
||||||
pub fn touch_route_used(&mut self, key: &DHTKey, cur_ts: u64) -> EyreResult<()> {
|
pub fn touch_route_used(&self, key: &DHTKey, cur_ts: u64) -> EyreResult<()> {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
Self::detail_mut(inner, &key)
|
Self::detail_mut(inner, key)
|
||||||
.ok_or_else(|| eyre!("route does not exist"))?
|
.ok_or_else(|| eyre!("route does not exist"))?
|
||||||
.last_used_ts = Some(cur_ts);
|
.last_used_ts = Some(cur_ts);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Record latency on the route
|
/// Record latency on the route
|
||||||
pub fn record_latency(&mut self, key: &DHTKey, latency: u64) -> EyreResult<()> {
|
pub fn record_latency(&self, key: &DHTKey, latency: u64) -> EyreResult<()> {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
|
|
||||||
let rsd = Self::detail_mut(inner, &key).ok_or_else(|| eyre!("route does not exist"))?;
|
let rsd = Self::detail_mut(inner, key).ok_or_else(|| eyre!("route does not exist"))?;
|
||||||
rsd.latency_stats = rsd.latency_stats_accounting.record_latency(latency);
|
rsd.latency_stats = rsd.latency_stats_accounting.record_latency(latency);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the calculated latency stats
|
/// Get the calculated latency stats
|
||||||
pub fn latency_stats(&mut self, key: &DHTKey) -> EyreResult<LatencyStats> {
|
pub fn latency_stats(&self, key: &DHTKey) -> EyreResult<LatencyStats> {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
Ok(Self::detail_mut(inner, &key)
|
Ok(Self::detail_mut(inner, key)
|
||||||
.ok_or_else(|| eyre!("route does not exist"))?
|
.ok_or_else(|| eyre!("route does not exist"))?
|
||||||
.latency_stats
|
.latency_stats
|
||||||
.clone())
|
.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add download transfers to route
|
/// Add download transfers to route
|
||||||
pub fn add_down(&mut self, key: &DHTKey, bytes: u64) -> EyreResult<()> {
|
pub fn add_down(&self, key: &DHTKey, bytes: u64) -> EyreResult<()> {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
let rsd = Self::detail_mut(inner, &key).ok_or_else(|| eyre!("route does not exist"))?;
|
let rsd = Self::detail_mut(inner, key).ok_or_else(|| eyre!("route does not exist"))?;
|
||||||
rsd.transfer_stats_accounting.add_down(bytes);
|
rsd.transfer_stats_accounting.add_down(bytes);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add upload transfers to route
|
/// Add upload transfers to route
|
||||||
pub fn add_up(&mut self, key: &DHTKey, bytes: u64) -> EyreResult<()> {
|
pub fn add_up(&self, key: &DHTKey, bytes: u64) -> EyreResult<()> {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
let rsd = Self::detail_mut(inner, &key).ok_or_else(|| eyre!("route does not exist"))?;
|
let rsd = Self::detail_mut(inner, key).ok_or_else(|| eyre!("route does not exist"))?;
|
||||||
rsd.transfer_stats_accounting.add_up(bytes);
|
rsd.transfer_stats_accounting.add_up(bytes);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process transfer statistics to get averages
|
/// Process transfer statistics to get averages
|
||||||
pub fn roll_transfers(&mut self, last_ts: u64, cur_ts: u64) {
|
pub fn roll_transfers(&self, last_ts: u64, cur_ts: u64) {
|
||||||
let inner = &mut *self.inner.lock();
|
let inner = &mut *self.inner.lock();
|
||||||
for rsd in inner.content.details.values_mut() {
|
for rsd in inner.content.details.values_mut() {
|
||||||
rsd.transfer_stats_accounting.roll_transfers(
|
rsd.transfer_stats_accounting.roll_transfers(
|
||||||
@ -1135,4 +1152,22 @@ impl RouteSpecStore {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert private route to binary blob
|
||||||
|
pub fn private_route_to_blob(private_route: &PrivateRoute) -> EyreResult<Vec<u8>> {
|
||||||
|
let mut pr_message = ::capnp::message::Builder::new_default();
|
||||||
|
let mut pr_builder = pr_message.init_root::<veilid_capnp::private_route::Builder>();
|
||||||
|
encode_private_route(&private_route, &mut pr_builder)
|
||||||
|
.wrap_err("failed to encode private route")?;
|
||||||
|
builder_to_vec(pr_message).wrap_err("failed to convert builder to vec")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert binary blob to private route
|
||||||
|
pub fn blob_to_private_route(blob: Vec<u8>) -> EyreResult<PrivateRoute> {
|
||||||
|
let reader = ::capnp::message::Reader::new(RPCMessageData::new(blob), Default::default());
|
||||||
|
let pr_reader = reader
|
||||||
|
.get_root::<veilid_capnp::private_route::Reader>()
|
||||||
|
.wrap_err("failed to make reader for private_route")?;
|
||||||
|
decode_private_route(&pr_reader).wrap_err("failed to decode private route")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,10 +90,16 @@ struct RPCMessageHeader {
|
|||||||
impl RPCMessageHeader {}
|
impl RPCMessageHeader {}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct RPCMessageData {
|
pub struct RPCMessageData {
|
||||||
contents: Vec<u8>, // rpc messages must be a canonicalized single segment
|
contents: Vec<u8>, // rpc messages must be a canonicalized single segment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RPCMessageData {
|
||||||
|
pub fn new(contents: Vec<u8>) -> Self {
|
||||||
|
Self { contents }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ReaderSegments for RPCMessageData {
|
impl ReaderSegments for RPCMessageData {
|
||||||
fn get_segment(&self, idx: u32) -> Option<&[u8]> {
|
fn get_segment(&self, idx: u32) -> Option<&[u8]> {
|
||||||
if idx > 0 {
|
if idx > 0 {
|
||||||
|
@ -16,12 +16,41 @@ fn get_bucket_entry_state(text: &str) -> Option<BucketEntryState> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_string(text: &str) -> Option<String> {
|
||||||
|
Some(text.to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_route_id(rss: RouteSpecStore) -> impl Fn(&str) -> Option<DHTKey> {
|
||||||
|
return move |text: &str| {
|
||||||
|
match DHTKey::try_decode(text).ok() {
|
||||||
|
Some(key) => {
|
||||||
|
let routes = rss.list_routes();
|
||||||
|
if routes.contains(&key) {
|
||||||
|
return Some(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let routes = rss.list_routes();
|
||||||
|
for r in routes {
|
||||||
|
let rkey = r.encode();
|
||||||
|
if rkey.starts_with(text) {
|
||||||
|
return Some(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn get_number(text: &str) -> Option<usize> {
|
fn get_number(text: &str) -> Option<usize> {
|
||||||
usize::from_str(text).ok()
|
usize::from_str(text).ok()
|
||||||
}
|
}
|
||||||
fn get_dht_key(text: &str) -> Option<DHTKey> {
|
fn get_dht_key(text: &str) -> Option<DHTKey> {
|
||||||
DHTKey::try_decode(text).ok()
|
DHTKey::try_decode(text).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_protocol_type(text: &str) -> Option<ProtocolType> {
|
fn get_protocol_type(text: &str) -> Option<ProtocolType> {
|
||||||
let lctext = text.to_ascii_lowercase();
|
let lctext = text.to_ascii_lowercase();
|
||||||
if lctext == "udp" {
|
if lctext == "udp" {
|
||||||
@ -36,6 +65,41 @@ fn get_protocol_type(text: &str) -> Option<ProtocolType> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn get_sequencing(text: &str) -> Option<Sequencing> {
|
||||||
|
let seqtext = text.to_ascii_lowercase();
|
||||||
|
if seqtext == "np" {
|
||||||
|
Some(Sequencing::NoPreference)
|
||||||
|
} else if seqtext == "ord" {
|
||||||
|
Some(Sequencing::PreferOrdered)
|
||||||
|
} else if seqtext == "*ord" {
|
||||||
|
Some(Sequencing::EnsureOrdered)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn get_stability(text: &str) -> Option<Stability> {
|
||||||
|
let sttext = text.to_ascii_lowercase();
|
||||||
|
if sttext == "ll" {
|
||||||
|
Some(Stability::LowLatency)
|
||||||
|
} else if sttext == "rel" {
|
||||||
|
Some(Stability::Reliable)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn get_direction_set(text: &str) -> Option<DirectionSet> {
|
||||||
|
let dstext = text.to_ascii_lowercase();
|
||||||
|
if dstext == "in" {
|
||||||
|
Some(Direction::Inbound.into())
|
||||||
|
} else if dstext == "out" {
|
||||||
|
Some(Direction::Outbound.into())
|
||||||
|
} else if dstext == "inout" {
|
||||||
|
Some(DirectionSet::all())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_address_type(text: &str) -> Option<AddressType> {
|
fn get_address_type(text: &str) -> Option<AddressType> {
|
||||||
let lctext = text.to_ascii_lowercase();
|
let lctext = text.to_ascii_lowercase();
|
||||||
if lctext == "ipv4" {
|
if lctext == "ipv4" {
|
||||||
@ -251,6 +315,13 @@ impl VeilidAPI {
|
|||||||
.purge_last_connections();
|
.purge_last_connections();
|
||||||
|
|
||||||
Ok("Connections purged".to_owned())
|
Ok("Connections purged".to_owned())
|
||||||
|
} else if args[0] == "routes" {
|
||||||
|
// Purge route spec store
|
||||||
|
let rss = self.network_manager()?.routing_table().route_spec_store();
|
||||||
|
match rss.purge().await {
|
||||||
|
Ok(_) => Ok("Routes purged".to_owned()),
|
||||||
|
Err(e) => Ok(format!("Routes purged but failed to save: {}", e)),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(VeilidAPIError::InvalidArgument {
|
Err(VeilidAPIError::InvalidArgument {
|
||||||
context: "debug_purge".to_owned(),
|
context: "debug_purge".to_owned(),
|
||||||
@ -420,6 +491,191 @@ impl VeilidAPI {
|
|||||||
Ok(format!("{:#?}", out))
|
Ok(format!("{:#?}", out))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn debug_route_allocate(&self, args: Vec<String>) -> Result<String, VeilidAPIError> {
|
||||||
|
// [ord|*ord] [rel] [<count>] [in|out]
|
||||||
|
|
||||||
|
let netman = self.network_manager()?;
|
||||||
|
let routing_table = netman.routing_table();
|
||||||
|
let rss = routing_table.route_spec_store();
|
||||||
|
let config = self.config().unwrap();
|
||||||
|
let default_route_hop_count = {
|
||||||
|
let c = config.get();
|
||||||
|
c.network.rpc.default_route_hop_count as usize
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut ai = 1;
|
||||||
|
let mut sequencing = Sequencing::NoPreference;
|
||||||
|
let mut stability = Stability::LowLatency;
|
||||||
|
let mut hop_count = default_route_hop_count;
|
||||||
|
let mut directions = DirectionSet::all();
|
||||||
|
|
||||||
|
while ai < args.len() {
|
||||||
|
if let Ok(seq) =
|
||||||
|
get_debug_argument_at(&args, ai, "debug_route", "sequencing", get_sequencing)
|
||||||
|
{
|
||||||
|
sequencing = seq;
|
||||||
|
} else if let Ok(sta) =
|
||||||
|
get_debug_argument_at(&args, ai, "debug_route", "stability", get_stability)
|
||||||
|
{
|
||||||
|
stability = sta;
|
||||||
|
} else if let Ok(hc) =
|
||||||
|
get_debug_argument_at(&args, ai, "debug_route", "hop_count", get_number)
|
||||||
|
{
|
||||||
|
hop_count = hc;
|
||||||
|
} else if let Ok(ds) =
|
||||||
|
get_debug_argument_at(&args, ai, "debug_route", "direction_set", get_direction_set)
|
||||||
|
{
|
||||||
|
directions = ds;
|
||||||
|
} else {
|
||||||
|
return Ok(format!("Invalid argument specified: {}", args[ai]));
|
||||||
|
}
|
||||||
|
ai += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate route
|
||||||
|
let out = match rss.allocate_route(stability, sequencing, hop_count, directions) {
|
||||||
|
Ok(Some(v)) => format!("{}", v.encode()),
|
||||||
|
Ok(None) => format!("<unavailable>"),
|
||||||
|
Err(e) => {
|
||||||
|
format!("Route allocation failed: {}", e)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
async fn debug_route_release(&self, args: Vec<String>) -> Result<String, VeilidAPIError> {
|
||||||
|
// <route id>
|
||||||
|
let netman = self.network_manager()?;
|
||||||
|
let routing_table = netman.routing_table();
|
||||||
|
let rss = routing_table.route_spec_store();
|
||||||
|
|
||||||
|
let route_id = get_debug_argument_at(&args, 1, "debug_route", "route_id", get_dht_key)?;
|
||||||
|
|
||||||
|
// Release route
|
||||||
|
let out = match rss.release_route(route_id) {
|
||||||
|
Ok(()) => format!("Released"),
|
||||||
|
Err(e) => {
|
||||||
|
format!("Route release failed: {}", e)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
async fn debug_route_publish(&self, args: Vec<String>) -> Result<String, VeilidAPIError> {
|
||||||
|
// <route id> [full]
|
||||||
|
let netman = self.network_manager()?;
|
||||||
|
let routing_table = netman.routing_table();
|
||||||
|
let rss = routing_table.route_spec_store();
|
||||||
|
|
||||||
|
let route_id = get_debug_argument_at(&args, 1, "debug_route", "route_id", get_dht_key)?;
|
||||||
|
let full = {
|
||||||
|
if args.len() > 2 {
|
||||||
|
let full_val = get_debug_argument_at(&args, 2, "debug_route", "full", get_string)?
|
||||||
|
.to_ascii_lowercase();
|
||||||
|
if full_val == "full" {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
return Err(VeilidAPIError::invalid_argument(
|
||||||
|
"debug_route",
|
||||||
|
"full",
|
||||||
|
full_val,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Publish route
|
||||||
|
let out = match rss.assemble_private_route(&route_id, Some(!full)) {
|
||||||
|
Ok(private_route) => {
|
||||||
|
if let Err(e) = rss.mark_route_published(&route_id, true) {
|
||||||
|
return Ok(format!("Couldn't mark route published: {}", e));
|
||||||
|
}
|
||||||
|
// Convert to blob
|
||||||
|
let blob_data = RouteSpecStore::private_route_to_blob(&private_route)
|
||||||
|
.map_err(VeilidAPIError::internal)?;
|
||||||
|
data_encoding::BASE64URL_NOPAD.encode(&blob_data)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
format!("Couldn't assemble private route: {}", e)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
async fn debug_route_unpublish(&self, args: Vec<String>) -> Result<String, VeilidAPIError> {
|
||||||
|
// <route id>
|
||||||
|
let netman = self.network_manager()?;
|
||||||
|
let routing_table = netman.routing_table();
|
||||||
|
let rss = routing_table.route_spec_store();
|
||||||
|
|
||||||
|
let route_id = get_debug_argument_at(&args, 1, "debug_route", "route_id", get_dht_key)?;
|
||||||
|
|
||||||
|
// Unpublish route
|
||||||
|
let out = if let Err(e) = rss.mark_route_published(&route_id, false) {
|
||||||
|
return Ok(format!("Couldn't mark route unpublished: {}", e));
|
||||||
|
} else {
|
||||||
|
"Route unpublished".to_owned()
|
||||||
|
};
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
async fn debug_route_print(&self, args: Vec<String>) -> Result<String, VeilidAPIError> {
|
||||||
|
// <route id>
|
||||||
|
let netman = self.network_manager()?;
|
||||||
|
let routing_table = netman.routing_table();
|
||||||
|
let rss = routing_table.route_spec_store();
|
||||||
|
|
||||||
|
let route_id = get_debug_argument_at(&args, 1, "debug_route", "route_id", get_dht_key)?;
|
||||||
|
|
||||||
|
match rss.debug_route(&route_id) {
|
||||||
|
Some(s) => Ok(s),
|
||||||
|
None => Ok("Route does not exist".to_owned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async fn debug_route_list(&self, _args: Vec<String>) -> Result<String, VeilidAPIError> {
|
||||||
|
//
|
||||||
|
let netman = self.network_manager()?;
|
||||||
|
let routing_table = netman.routing_table();
|
||||||
|
let rss = routing_table.route_spec_store();
|
||||||
|
|
||||||
|
let routes = rss.list_routes();
|
||||||
|
let mut out = format!("Routes: (count = {}):\n", routes.len());
|
||||||
|
for r in routes {
|
||||||
|
out.push_str(&format!("{}\n", r.encode()));
|
||||||
|
}
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
async fn debug_route_import(&self, _args: Vec<String>) -> Result<String, VeilidAPIError> {
|
||||||
|
// <blob>
|
||||||
|
let out = format!("");
|
||||||
|
return Ok(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn debug_route(&self, args: String) -> Result<String, VeilidAPIError> {
|
||||||
|
let args: Vec<String> = args.split_whitespace().map(|s| s.to_owned()).collect();
|
||||||
|
|
||||||
|
let command = get_debug_argument_at(&args, 0, "debug_route", "command", get_string)?;
|
||||||
|
|
||||||
|
if command == "allocate" {
|
||||||
|
self.debug_route_allocate(args).await
|
||||||
|
} else if command == "release" {
|
||||||
|
self.debug_route_release(args).await
|
||||||
|
} else if command == "publish" {
|
||||||
|
self.debug_route_publish(args).await
|
||||||
|
} else if command == "unpublish" {
|
||||||
|
self.debug_route_unpublish(args).await
|
||||||
|
} else if command == "print" {
|
||||||
|
self.debug_route_print(args).await
|
||||||
|
} else if command == "list" {
|
||||||
|
self.debug_route_list(args).await
|
||||||
|
} else if command == "import" {
|
||||||
|
self.debug_route_import(args).await
|
||||||
|
} else {
|
||||||
|
Ok(">>> Unknown command\n".to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn debug_help(&self, _args: String) -> Result<String, VeilidAPIError> {
|
pub async fn debug_help(&self, _args: String) -> Result<String, VeilidAPIError> {
|
||||||
Ok(r#">>> Debug commands:
|
Ok(r#">>> Debug commands:
|
||||||
help
|
help
|
||||||
@ -435,6 +691,13 @@ impl VeilidAPI {
|
|||||||
restart network
|
restart network
|
||||||
ping <node_id> [protocol_type][address_type][routing_domain]
|
ping <node_id> [protocol_type][address_type][routing_domain]
|
||||||
contact <node_id> [protocol_type [address_type]]
|
contact <node_id> [protocol_type [address_type]]
|
||||||
|
route allocate [ord|*ord] [rel] [<count>] [in|out]
|
||||||
|
route release <route id>
|
||||||
|
route publish <route id> [full]
|
||||||
|
route unpublish <route id>
|
||||||
|
route print <route id>
|
||||||
|
route list
|
||||||
|
route import <blob>
|
||||||
"#
|
"#
|
||||||
.to_owned())
|
.to_owned())
|
||||||
}
|
}
|
||||||
@ -476,6 +739,8 @@ impl VeilidAPI {
|
|||||||
self.debug_config(rest).await
|
self.debug_config(rest).await
|
||||||
} else if arg == "restart" {
|
} else if arg == "restart" {
|
||||||
self.debug_restart(rest).await
|
self.debug_restart(rest).await
|
||||||
|
} else if arg == "route" {
|
||||||
|
self.debug_route(rest).await
|
||||||
} else {
|
} else {
|
||||||
Ok(">>> Unknown command\n".to_owned())
|
Ok(">>> Unknown command\n".to_owned())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user