cli fixes

This commit is contained in:
John Smith 2023-06-20 23:46:39 -04:00
parent e80a3d3063
commit 1c8ecab2b6
11 changed files with 170 additions and 69 deletions

View File

@ -187,8 +187,14 @@ reply - reply to an AppCall not handled directly by the server
let ui = self.ui_sender(); let ui = self.ui_sender();
spawn_detached_local(async move { spawn_detached_local(async move {
match capi.server_debug(rest.unwrap_or_default()).await { match capi.server_debug(rest.unwrap_or_default()).await {
Ok(output) => ui.display_string_dialog("Debug Output", output, callback), Ok(output) => {
Err(e) => ui.display_string_dialog("Debug Error", e.to_string(), callback), ui.add_node_event(Level::Debug, output);
ui.send_callback(callback);
}
Err(e) => {
ui.add_node_event(Level::Error, e.to_string());
ui.send_callback(callback);
}
} }
}); });
Ok(()) Ok(())

View File

@ -14,8 +14,8 @@ use cursive::CursiveRunnable;
use cursive_flexi_logger_view::{CursiveLogWriter, FlexiLoggerView}; use cursive_flexi_logger_view::{CursiveLogWriter, FlexiLoggerView};
// use cursive_multiplex::*; // use cursive_multiplex::*;
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use std::io::Write;
use thiserror::Error; use thiserror::Error;
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
/// ///
struct Dirty<T> { struct Dirty<T> {
@ -454,20 +454,52 @@ impl UI {
Self::command_processor(s).start_connection(); Self::command_processor(s).start_connection();
} }
fn copy_to_clipboard<S: AsRef<str>>(s: &mut Cursive, text: S) {
if let Ok(mut clipboard) = arboard::Clipboard::new() {
// X11/Wayland/other system copy
if clipboard.set_text(text.as_ref()).is_ok() {
let color = *Self::inner_mut(s).log_colors.get(&Level::Info).unwrap();
cursive_flexi_logger_view::push_to_log(StyledString::styled(
format!(">> Copied: {}", text.as_ref()),
color,
));
} else {
let color = *Self::inner_mut(s).log_colors.get(&Level::Warn).unwrap();
cursive_flexi_logger_view::push_to_log(StyledString::styled(
format!(">> Could not copy to clipboard"),
color,
));
}
} else {
// OSC52 clipboard copy for terminals
if std::io::stdout()
.write_all(
format!(
"\x1B]52;c;{}\x07",
data_encoding::BASE64.encode(text.as_ref().as_bytes()),
)
.as_bytes(),
)
.is_ok()
{
if std::io::stdout().flush().is_ok() {
let color = *Self::inner_mut(s).log_colors.get(&Level::Info).unwrap();
cursive_flexi_logger_view::push_to_log(StyledString::styled(
format!(">> Copied: {}", text.as_ref()),
color,
));
}
}
}
}
fn on_submit_peers_table_view(s: &mut Cursive, _row: usize, index: usize) { fn on_submit_peers_table_view(s: &mut Cursive, _row: usize, index: usize) {
let peers_table_view = UI::peers(s); let peers_table_view = UI::peers(s);
let node_id = peers_table_view let node_id = peers_table_view
.borrow_item(index) .borrow_item(index)
.map(|j| j["node_ids"][0].to_string()); .map(|j| j["node_ids"][0].to_string());
if let Some(node_id) = node_id { if let Some(node_id) = node_id {
let mut clipboard = arboard::Clipboard::new().unwrap(); Self::copy_to_clipboard(s, node_id);
clipboard.set_text(node_id.clone()).unwrap();
let color = *Self::inner_mut(s).log_colors.get(&Level::Info).unwrap();
cursive_flexi_logger_view::push_to_log(StyledString::styled(
format!(">> NodeId Copied: {}", node_id),
color,
));
} }
} }
@ -967,10 +999,18 @@ impl UISender {
pub fn set_config(&mut self, config: &json::JsonValue) { pub fn set_config(&mut self, config: &json::JsonValue) {
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
inner let node_ids = &config["network"]["routing_table"]["node_id"];
.ui_state
.node_id let mut node_id_str = String::new();
.set(config["network"]["routing_table"]["node_id"].to_string()); for l in 0..node_ids.len() {
let nid = &node_ids[l];
if !node_id_str.is_empty() {
node_id_str.push_str(" ");
}
node_id_str.push_str(nid.to_string().as_ref());
}
inner.ui_state.node_id.set(node_id_str);
} }
pub fn set_connection_state(&mut self, state: ConnectionState) { pub fn set_connection_state(&mut self, state: ConnectionState) {
{ {

View File

@ -130,6 +130,7 @@ macro_rules! byte_array_type {
Self { bytes } Self { bytes }
} }
// Big endian bit ordering
pub fn bit(&self, index: usize) -> bool { pub fn bit(&self, index: usize) -> bool {
assert!(index < ($size * 8)); assert!(index < ($size * 8));
let bi = index / 8; let bi = index / 8;
@ -152,6 +153,7 @@ macro_rules! byte_array_type {
None None
} }
// Big endian nibble ordering
pub fn nibble(&self, index: usize) -> u8 { pub fn nibble(&self, index: usize) -> u8 {
assert!(index < ($size * 2)); assert!(index < ($size * 2));
let bi = index / 2; let bi = index / 2;

View File

@ -353,10 +353,40 @@ async fn test_operations(vcrypto: CryptoSystemVersion) {
assert_eq!(d4.first_nonzero_bit(), Some(0)); assert_eq!(d4.first_nonzero_bit(), Some(0));
} }
pub async fn test_crypto_key_ordering() {
let k1 = CryptoKey::new([
128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
]);
let k2 = CryptoKey::new([
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
]);
let k3 = CryptoKey::new([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 128,
]);
let k4 = CryptoKey::new([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1,
]);
let k5 = CryptoKey::new([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
]);
assert!(k2 < k1);
assert!(k3 < k2);
assert!(k4 < k3);
assert!(k5 < k4);
}
pub async fn test_all() { pub async fn test_all() {
let api = crypto_tests_startup().await; let api = crypto_tests_startup().await;
let crypto = api.crypto().unwrap(); let crypto = api.crypto().unwrap();
test_crypto_key_ordering().await;
// Test versions // Test versions
for v in VALID_CRYPTO_KINDS { for v in VALID_CRYPTO_KINDS {
let vcrypto = crypto.get(v).unwrap(); let vcrypto = crypto.get(v).unwrap();

View File

@ -51,6 +51,7 @@ impl RoutingTable {
return NetworkResult::invalid_message("unsupported cryptosystem"); return NetworkResult::invalid_message("unsupported cryptosystem");
}; };
let own_distance = vcrypto.distance(&own_node_id.value, &key.value); let own_distance = vcrypto.distance(&own_node_id.value, &key.value);
let vcrypto2 = vcrypto.clone();
let filter = Box::new( let filter = Box::new(
move |rti: &RoutingTableInner, opt_entry: Option<Arc<BucketEntry>>| { move |rti: &RoutingTableInner, opt_entry: Option<Arc<BucketEntry>>| {
@ -98,6 +99,46 @@ impl RoutingTable {
}, },
); );
// xxx test
// Validate peers returned are, in fact, closer to the key than the node we sent this to
let valid = match Self::verify_peers_closer(vcrypto2, own_node_id, key, &closest_nodes) {
Ok(v) => v,
Err(e) => {
panic!("missing cryptosystem in peers node ids: {}", e);
}
};
if !valid {
panic!("non-closer peers returned");
}
NetworkResult::value(closest_nodes) NetworkResult::value(closest_nodes)
} }
/// Determine if set of peers is closer to key_near than key_far
pub(crate) fn verify_peers_closer(
vcrypto: CryptoSystemVersion,
key_far: TypedKey,
key_near: TypedKey,
peers: &[PeerInfo],
) -> EyreResult<bool> {
let kind = vcrypto.kind();
if key_far.kind != kind || key_near.kind != kind {
bail!("keys all need the same cryptosystem");
}
let mut closer = true;
for peer in peers {
let Some(key_peer) = peer.node_ids().get(kind) else {
bail!("peers need to have a key with the same cryptosystem");
};
let d_near = vcrypto.distance(&key_near.value, &key_peer.value);
let d_far = vcrypto.distance(&key_far.value, &key_peer.value);
if d_far < d_near {
closer = false;
}
}
Ok(closer)
}
} }

View File

@ -404,37 +404,6 @@ impl RPCProcessor {
routing_table.signed_node_info_is_valid_in_routing_domain(routing_domain, &signed_node_info) routing_table.signed_node_info_is_valid_in_routing_domain(routing_domain, &signed_node_info)
} }
/// Determine if set of peers is closer to key_near than key_far
fn verify_peers_closer(
&self,
vcrypto: CryptoSystemVersion,
key_far: TypedKey,
key_near: TypedKey,
peers: &[PeerInfo],
) -> Result<bool, RPCError> {
let kind = vcrypto.kind();
if key_far.kind != kind || key_near.kind != kind {
return Err(RPCError::internal("keys all need the same cryptosystem"));
}
let mut closer = true;
for peer in peers {
let Some(key_peer) = peer.node_ids().get(kind) else {
return Err(RPCError::invalid_format(
"peers need to have a key with the same cryptosystem",
));
};
let d_near = vcrypto.distance(&key_near.value, &key_peer.value);
let d_far = vcrypto.distance(&key_far.value, &key_peer.value);
if d_far < d_near {
closer = false;
}
}
Ok(closer)
}
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
/// Search the DHT for a single node closest to a key and add it to the routing table and return the node reference /// Search the DHT for a single node closest to a key and add it to the routing table and return the node reference

View File

@ -76,15 +76,13 @@ impl RPCProcessor {
let (value, peers, descriptor) = get_value_a.destructure(); let (value, peers, descriptor) = get_value_a.destructure();
// Validate peers returned are, in fact, closer to the key than the node we sent this to // Validate peers returned are, in fact, closer to the key than the node we sent this to
let valid = match self.verify_peers_closer(vcrypto, target_node_id, key, &peers) { let valid = match RoutingTable::verify_peers_closer(vcrypto, target_node_id, key, &peers) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
if matches!(e, RPCError::Internal(_)) { return Ok(NetworkResult::invalid_message(format!(
return Err(e); "missing cryptosystem in peers node ids: {}",
} e
return Ok(NetworkResult::invalid_message( )));
"missing cryptosystem in peers node ids",
));
} }
}; };
if !valid { if !valid {

View File

@ -83,15 +83,13 @@ impl RPCProcessor {
let (set, value, peers) = set_value_a.destructure(); let (set, value, peers) = set_value_a.destructure();
// Validate peers returned are, in fact, closer to the key than the node we sent this to // Validate peers returned are, in fact, closer to the key than the node we sent this to
let valid = match self.verify_peers_closer(vcrypto, target_node_id, key, &peers) { let valid = match RoutingTable::verify_peers_closer(vcrypto, target_node_id, key, &peers) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
if matches!(e, RPCError::Internal(_)) { return Ok(NetworkResult::invalid_message(format!(
return Err(e); "missing cryptosystem in peers node ids: {}",
} e
return Ok(NetworkResult::invalid_message( )));
"missing cryptosystem in peers node ids",
));
} }
}; };
if !valid { if !valid {

View File

@ -341,7 +341,6 @@ impl StorageManager {
} else { } else {
ValueData::new(data, writer.key) ValueData::new(data, writer.key)
}; };
let seq = value_data.seq();
// Validate with schema // Validate with schema
if !schema.check_subkey_value_data(descriptor.owner(), subkey, &value_data) { if !schema.check_subkey_value_data(descriptor.owner(), subkey, &value_data) {
@ -374,7 +373,6 @@ impl StorageManager {
drop(inner); drop(inner);
// Use the safety selection we opened the record with // Use the safety selection we opened the record with
let final_signed_value_data = self let final_signed_value_data = self
.outbound_set_value( .outbound_set_value(
rpc_processor, rpc_processor,
@ -386,13 +384,12 @@ impl StorageManager {
) )
.await?; .await?;
// If we got a new value back then write it to the opened record // Whatever record we got back, store it locally, might be newer than the one we asked to save
if final_signed_value_data.value_data().seq() != seq { let mut inner = self.lock().await?;
let mut inner = self.lock().await?; inner
inner .handle_set_local_value(key, subkey, final_signed_value_data.clone())
.handle_set_local_value(key, subkey, final_signed_value_data.clone()) .await?;
.await?;
}
Ok(Some(final_signed_value_data.into_value_data())) Ok(Some(final_signed_value_data.into_value_data()))
} }

View File

@ -67,6 +67,9 @@ async def test_set_get_dht_value(api_connection: veilid.VeilidAPI):
vd2 = await rc.get_dht_value(rec.key, 0, False) vd2 = await rc.get_dht_value(rec.key, 0, False)
assert vd2 != None assert vd2 != None
print("vd: {}", vd.__dict__)
print("vd2: {}", vd2.__dict__)
assert vd == vd2 assert vd == vd2
await rc.close_dht_record(rec.key) await rc.close_dht_record(rec.key)

View File

@ -2,6 +2,7 @@ import base64
import json import json
from enum import StrEnum from enum import StrEnum
from typing import Any, Optional, Self, Tuple from typing import Any, Optional, Self, Tuple
from functools import total_ordering
#################################################################### ####################################################################
@ -323,6 +324,7 @@ class DHTRecordDescriptor:
return self.__dict__ return self.__dict__
# @total_ordering
class ValueData: class ValueData:
seq: ValueSeqNum seq: ValueSeqNum
data: bytes data: bytes
@ -333,6 +335,21 @@ class ValueData:
self.data = data self.data = data
self.writer = writer self.writer = writer
# def __lt__(self, other):
# return self.data < other.data
# def __eq__(self, other):
# return self.cgpa == other.cgpa
# def __le__(self, other):
# return self.cgpa<= other.cgpa
# def __ge__(self, other):
# return self.cgpa>= other.cgpa
# def __ne__(self, other):
# return self.cgpa != other.cgpa
@classmethod @classmethod
def from_json(cls, j: dict) -> Self: def from_json(cls, j: dict) -> Self:
return cls( return cls(