veilid-cli cleanup

This commit is contained in:
John Smith 2022-09-06 16:49:43 -04:00
parent 4d65903ee4
commit ca6c616d66
17 changed files with 689 additions and 108 deletions

11
Cargo.lock generated
View File

@ -1209,6 +1209,15 @@ dependencies = [
"xi-unicode",
]
[[package]]
name = "cursive_table_view"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8935dd87d19c54b7506b245bc988a7b4e65b1058e1d0d64c0ad9b3188e48060"
dependencies = [
"cursive_core",
]
[[package]]
name = "curve25519-dalek"
version = "3.2.1"
@ -5087,6 +5096,7 @@ dependencies = [
"cursive",
"cursive-flexi-logger-view",
"cursive_buffered_backend",
"cursive_table_view",
"directories",
"flexi_logger",
"futures",
@ -5155,6 +5165,7 @@ dependencies = [
"nix 0.25.0",
"no-std-net",
"once_cell",
"owning_ref",
"owo-colors",
"parking_lot 0.12.1",
"rand 0.7.3",

View File

@ -23,9 +23,9 @@ tokio-util = { version = "^0", features = ["compat"], optional = true}
async-tungstenite = { version = "^0.8" }
cursive-flexi-logger-view = { path = "../external/cursive-flexi-logger-view" }
cursive_buffered_backend = { path = "../external/cursive_buffered_backend" }
# cursive-multiplex = "0.4.0"
# cursive-multiplex = "0.6.0"
# cursive_tree_view = "0.6.0"
# cursive_table_view = "0.12.0"
cursive_table_view = "0.14.0"
# cursive-tabs = "0.5.0"
clap = "^3"
directories = "^4"

View File

@ -8,7 +8,7 @@ use std::net::SocketAddr;
use std::rc::Rc;
use std::time::{Duration, SystemTime};
use veilid_core::xx::{Eventual, EventualCommon};
use veilid_core::VeilidConfigLogLevel;
use veilid_core::*;
pub fn convert_loglevel(s: &str) -> Result<VeilidConfigLogLevel, String> {
match s.to_ascii_lowercase().as_str() {
@ -323,9 +323,12 @@ change_log_level - change the log level for a tracing layer
}
pub fn update_network_status(&mut self, network: veilid_core::VeilidStateNetwork) {
self.inner_mut()
.ui
.set_network_status(network.started, network.bps_down, network.bps_up);
self.inner_mut().ui.set_network_status(
network.started,
network.bps_down,
network.bps_up,
network.peers,
);
}
pub fn update_log(&mut self, log: veilid_core::VeilidStateLog) {

View File

@ -12,6 +12,7 @@ use tools::*;
mod client_api_connection;
mod command_processor;
mod peers_table_view;
mod settings;
mod tools;
mod ui;

View File

@ -0,0 +1,99 @@
use super::*;
use cursive_table_view::*;
use std::cmp::Ordering;
use veilid_core::PeerTableData;
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum PeerTableColumn {
NodeId,
Address,
LatencyAvg,
TransferDownAvg,
TransferUpAvg,
}
// impl PeerTableColumn {
// fn as_str(&self) -> &str {
// match self {
// PeerTableColumn::NodeId => "Node Id",
// PeerTableColumn::Address => "Address",
// PeerTableColumn::LatencyAvg => "Latency",
// PeerTableColumn::TransferDownAvg => "Down",
// PeerTableColumn::TransferUpAvg => "Up",
// }
// }
// }
fn format_ts(ts: u64) -> String {
let secs = timestamp_to_secs(ts);
if secs >= 1.0 {
format!("{:.2}s", timestamp_to_secs(ts))
} else {
format!("{:.2}ms", timestamp_to_secs(ts) * 1000.0)
}
}
fn format_bps(bps: u64) -> String {
if bps >= 1024u64 * 1024u64 * 1024u64 {
format!("{:.2}GB/s", (bps / (1024u64 * 1024u64)) as f64 / 1024.0)
} else if bps >= 1024u64 * 1024u64 {
format!("{:.2}MB/s", (bps / 1024u64) as f64 / 1024.0)
} else if bps >= 1024u64 {
format!("{:.2}KB/s", bps as f64 / 1024.0)
} else {
format!("{:.2}B/s", bps as f64)
}
}
impl TableViewItem<PeerTableColumn> for PeerTableData {
fn to_column(&self, column: PeerTableColumn) -> String {
match column {
PeerTableColumn::NodeId => self.node_id.encode(),
PeerTableColumn::Address => format!(
"{:?}:{}",
self.peer_address.protocol_type(),
self.peer_address.to_socket_addr()
),
PeerTableColumn::LatencyAvg => format!(
"{}",
self.peer_stats
.latency
.as_ref()
.map(|l| format_ts(l.average))
.unwrap_or("---".to_owned())
),
PeerTableColumn::TransferDownAvg => format_bps(self.peer_stats.transfer.down.average),
PeerTableColumn::TransferUpAvg => format_bps(self.peer_stats.transfer.up.average),
}
}
fn cmp(&self, other: &Self, column: PeerTableColumn) -> Ordering
where
Self: Sized,
{
match column {
PeerTableColumn::NodeId => self.node_id.cmp(&other.node_id),
PeerTableColumn::Address => self.to_column(column).cmp(&other.to_column(column)),
PeerTableColumn::LatencyAvg => self
.peer_stats
.latency
.as_ref()
.map(|l| l.average)
.cmp(&other.peer_stats.latency.as_ref().map(|l| l.average)),
PeerTableColumn::TransferDownAvg => self
.peer_stats
.transfer
.down
.average
.cmp(&other.peer_stats.transfer.down.average),
PeerTableColumn::TransferUpAvg => self
.peer_stats
.transfer
.up
.average
.cmp(&other.peer_stats.transfer.up.average),
}
}
}
pub type PeersTableView = TableView<PeerTableData, PeerTableColumn>;

View File

@ -1,4 +1,5 @@
use crate::command_processor::*;
use crate::peers_table_view::*;
use crate::settings::Settings;
use crossbeam_channel::Sender;
use cursive::align::*;
@ -10,6 +11,7 @@ use cursive::views::*;
use cursive::Cursive;
use cursive::CursiveRunnable;
use cursive_flexi_logger_view::{CursiveLogWriter, FlexiLoggerView};
//use cursive_multiplex::*;
use log::*;
use std::cell::RefCell;
use std::collections::{HashMap, VecDeque};
@ -20,7 +22,7 @@ use veilid_core::*;
//////////////////////////////////////////////////////////////
///
struct Dirty<T> {
pub value: T,
value: T,
dirty: bool,
}
@ -52,6 +54,7 @@ struct UIState {
network_started: Dirty<bool>,
network_down_up: Dirty<(f32, f32)>,
connection_state: Dirty<ConnectionState>,
peers_state: Dirty<Vec<PeerTableData>>,
}
impl UIState {
@ -61,6 +64,7 @@ impl UIState {
network_started: Dirty::new(false),
network_down_up: Dirty::new((0.0, 0.0)),
connection_state: Dirty::new(ConnectionState::Disconnected),
peers_state: Dirty::new(Vec::new()),
}
}
}
@ -219,6 +223,9 @@ impl UI {
fn status_bar(s: &mut Cursive) -> ViewRef<TextView> {
s.find_name("status-bar").unwrap()
}
fn peers(s: &mut Cursive) -> ViewRef<PeersTableView> {
s.find_name("peers").unwrap()
}
fn render_attachment_state<'a>(inner: &mut UIInner) -> &'a str {
match inner.ui_state.attachment_state.get() {
AttachmentState::Detached => " Detached [----]",
@ -607,15 +614,23 @@ impl UI {
statusbar.set_content(status);
}
fn refresh_peers(s: &mut Cursive) {
let mut peers = UI::peers(s);
let inner = Self::inner_mut(s);
peers.set_items_stable(inner.ui_state.peers_state.get().clone());
}
fn update_cb(s: &mut Cursive) {
let mut inner = Self::inner_mut(s);
let mut refresh_statusbar = false;
let mut refresh_button_attach = false;
let mut refresh_connection_dialog = false;
let mut refresh_peers = false;
if inner.ui_state.attachment_state.take_dirty() {
refresh_statusbar = true;
refresh_button_attach = true;
refresh_peers = true;
}
if inner.ui_state.network_started.take_dirty() {
refresh_statusbar = true;
@ -627,6 +642,10 @@ impl UI {
refresh_statusbar = true;
refresh_button_attach = true;
refresh_connection_dialog = true;
refresh_peers = true;
}
if inner.ui_state.peers_state.take_dirty() {
refresh_peers = true;
}
drop(inner);
@ -640,6 +659,9 @@ impl UI {
if refresh_connection_dialog {
Self::refresh_connection_dialog(s);
}
if refresh_peers {
Self::refresh_peers(s);
}
}
////////////////////////////////////////////////////////////////////////////
@ -686,30 +708,48 @@ impl UI {
siv.set_user_data(this.inner.clone());
// Create layouts
let mut mainlayout = LinearLayout::vertical().with_name("main-layout");
mainlayout.get_mut().add_child(
Panel::new(
let node_events_view = Panel::new(
FlexiLoggerView::new_scrollable()
.with_name("node-events")
.full_screen(),
)
.title_position(HAlign::Left)
.title("Node Events"),
);
mainlayout.get_mut().add_child(
Panel::new(ScrollView::new(
TextView::new("Peer Table")
.title("Node Events");
let peers_table_view = PeersTableView::new()
.column(PeerTableColumn::NodeId, "Node Id", |c| c.width(43))
.column(PeerTableColumn::Address, "Address", |c| c)
.column(PeerTableColumn::LatencyAvg, "Ping", |c| c.width(8))
.column(PeerTableColumn::TransferDownAvg, "Down", |c| c.width(8))
.column(PeerTableColumn::TransferUpAvg, "Up", |c| c.width(8))
.with_name("peers")
.fixed_height(8)
.scrollable(),
))
.title_position(HAlign::Left)
.title("Peers"),
);
.full_width()
.min_height(8);
// attempt at using Mux. Mux has bugs, like resizing problems.
// let mut mux = Mux::new();
// let node_node_events_view = mux
// .add_below(node_events_view, mux.root().build().unwrap())
// .unwrap();
// let node_peers_table_view = mux
// .add_below(peers_table_view, node_node_events_view)
// .unwrap();
// mux.set_container_split_ratio(node_peers_table_view, 0.75)
// .unwrap();
// let mut mainlayout = LinearLayout::vertical();
// mainlayout.add_child(mux);
// Back to fixed layout
let mut mainlayout = LinearLayout::vertical();
mainlayout.add_child(node_events_view);
mainlayout.add_child(peers_table_view);
// ^^^ fixed layout
let mut command = StyledString::new();
command.append_styled("Command> ", ColorStyle::title_primary());
//
mainlayout.get_mut().add_child(
mainlayout.add_child(
LinearLayout::horizontal()
.child(TextView::new(command))
.child(
@ -738,7 +778,7 @@ impl UI {
ColorStyle::highlight_inactive(),
);
mainlayout.get_mut().add_child(
mainlayout.add_child(
LinearLayout::horizontal()
.color(Some(ColorStyle::highlight_inactive()))
.child(
@ -776,13 +816,20 @@ impl UI {
inner.ui_state.attachment_state.set(state);
let _ = inner.cb_sink.send(Box::new(UI::update_cb));
}
pub fn set_network_status(&mut self, started: bool, bps_down: u64, bps_up: u64) {
pub fn set_network_status(
&mut self,
started: bool,
bps_down: u64,
bps_up: u64,
peers: Vec<PeerTableData>,
) {
let mut inner = self.inner.borrow_mut();
inner.ui_state.network_started.set(started);
inner.ui_state.network_down_up.set((
((bps_down as f64) / 1000.0f64) as f32,
((bps_up as f64) / 1000.0f64) as f32,
));
inner.ui_state.peers_state.set(peers);
let _ = inner.cb_sink.send(Box::new(UI::update_cb));
}
pub fn set_connection_state(&mut self, state: ConnectionState) {
@ -790,6 +837,7 @@ impl UI {
inner.ui_state.connection_state.set(state);
let _ = inner.cb_sink.send(Box::new(UI::update_cb));
}
pub fn add_node_event(&self, event: String) {
let inner = self.inner.borrow();
let color = *inner.log_colors.get(&Level::Info).unwrap();

View File

@ -41,6 +41,7 @@ lazy_static = "^1"
directories = "^4"
once_cell = "^1"
json = "^0"
owning_ref = "^0"
flume = { version = "^0", features = ["async"] }
enumset = { version= "^1", features = ["serde"] }
backtrace = { version = "^0", optional = true }

View File

@ -1680,12 +1680,30 @@ impl NetworkManager {
started: true,
bps_down: inner.stats.self_stats.transfer_stats.down.average,
bps_up: inner.stats.self_stats.transfer_stats.up.average,
peers: {
let mut out = Vec::new();
let routing_table = inner.routing_table.as_ref().unwrap();
for (k, v) in routing_table.get_recent_peers() {
if let Some(nr) = routing_table.lookup_node_ref(k) {
let peer_stats = nr.peer_stats();
let peer = PeerTableData {
node_id: k,
peer_address: v.last_connection.remote(),
peer_stats,
};
out.push(peer);
}
}
out
},
}
} else {
VeilidStateNetwork {
started: false,
bps_down: 0,
bps_up: 0,
peers: Vec::new(),
}
}
}

View File

@ -29,7 +29,7 @@ const RECENT_PEERS_TABLE_SIZE: usize = 64;
#[derive(Debug, Clone, Copy)]
pub struct RecentPeersEntry {
last_connection: ConnectionDescriptor,
pub last_connection: ConnectionDescriptor,
}
/// RoutingTable rwlock-internal data
@ -776,13 +776,15 @@ impl RoutingTable {
descriptor: ConnectionDescriptor,
timestamp: u64,
) -> Option<NodeRef> {
self.create_node_ref(node_id, |e| {
// set the most recent node address for connection finding and udp replies
e.set_last_connection(descriptor, timestamp);
let out = self.create_node_ref(node_id, |e| {
// this node is live because it literally just connected to us
e.touch_last_seen(timestamp);
})
});
if let Some(nr) = &out {
// set the most recent node address for connection finding and udp replies
nr.set_last_connection(descriptor, timestamp);
}
out
}
// Ticks about once per second
@ -834,11 +836,8 @@ impl RoutingTable {
.collect()
}
fn touch_recent_peer(
inner: &mut RoutingTableInner,
node_id: DHTKey,
last_connection: ConnectionDescriptor,
) {
pub fn touch_recent_peer(&self, node_id: DHTKey, last_connection: ConnectionDescriptor) {
let mut inner = self.inner.write();
inner
.recent_peers
.insert(node_id, RecentPeersEntry { last_connection });

View File

@ -200,6 +200,9 @@ impl NodeRef {
pub fn state(&self, cur_ts: u64) -> BucketEntryState {
self.operate(|_rti, e| e.state(cur_ts))
}
pub fn peer_stats(&self) -> PeerStats {
self.operate(|_rti, e| e.peer_stats().clone())
}
// Per-RoutingDomain accessors
pub fn make_peer_info(&self, routing_domain: RoutingDomain) -> Option<PeerInfo> {
@ -322,7 +325,9 @@ impl NodeRef {
}
pub fn set_last_connection(&self, connection_descriptor: ConnectionDescriptor, ts: u64) {
self.operate_mut(|_rti, e| e.set_last_connection(connection_descriptor, ts))
self.operate_mut(|_rti, e| e.set_last_connection(connection_descriptor, ts));
self.routing_table
.touch_recent_peer(self.node_id(), connection_descriptor);
}
pub fn has_any_dial_info(&self) -> bool {

View File

@ -0,0 +1,53 @@
use super::*;
#[derive(Debug, Clone)]
pub enum Origin {
Sender,
PrivateRoute(PrivateRoute),
}
impl Origin {
pub fn sender() -> Self {
Self::Sender
}
pub fn private_route(private_route: PrivateRoute) -> Self {
Self::PrivateRoute(private_route)
}
pub fn into_respond_to(self, destination: &Destination) -> Result<RespondTo, RPCError> {
match self {
Self::Sender => {
let peer = match destination {
Destination::Direct {
target,
safety_route_spec,
} => todo!(),
Destination::Relay {
relay,
target,
safety_route_spec,
} => todo!(),
Destination::PrivateRoute {
private_route,
safety_route_spec,
} => todo!(),
};
let routing_table = peer.routing_table();
let routing_domain = peer.best_routing_domain();
// Send some signed node info along with the question if this node needs to be replied to
if routing_table.has_valid_own_node_info()
&& !peer.has_seen_our_node_info(routing_domain)
{
let our_sni = self
.routing_table()
.get_own_signed_node_info(routing_domain);
RespondTo::Sender(Some(our_sni))
} else {
RespondTo::Sender(None)
}
}
Self::PrivateRoute(pr) => RespondTo::PrivateRoute(pr),
}
}
}

View File

@ -215,22 +215,32 @@ impl fmt::Display for VeilidLogLevel {
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct VeilidStateLog {
pub log_level: VeilidLogLevel,
pub message: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct VeilidStateAttachment {
pub state: AttachmentState,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct PeerTableData {
pub node_id: DHTKey,
pub peer_address: PeerAddress,
pub peer_stats: PeerStats,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct VeilidStateNetwork {
pub started: bool,
#[serde(with = "json_as_string")]
pub bps_down: u64,
#[serde(with = "json_as_string")]
pub bps_up: u64,
pub peers: Vec<PeerTableData>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -706,6 +716,15 @@ impl Address {
}
}
impl fmt::Display for Address {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Address::IPV4(v4) => write!(f, "{}", v4),
Address::IPV6(v6) => write!(f, "{}", v6),
}
}
}
impl FromStr for Address {
type Err = VeilidAPIError;
fn from_str(host: &str) -> Result<Address, VeilidAPIError> {
@ -1447,6 +1466,7 @@ impl PeerInfo {
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
pub struct PeerAddress {
protocol_type: ProtocolType,
#[serde(with = "json_as_string")]
socket_address: SocketAddress,
}
@ -1565,41 +1585,52 @@ impl FromStr for NodeDialInfo {
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct LatencyStats {
#[serde(with = "json_as_string")]
pub fastest: u64, // fastest latency in the ROLLING_LATENCIES_SIZE last latencies
#[serde(with = "json_as_string")]
pub average: u64, // average latency over the ROLLING_LATENCIES_SIZE last latencies
#[serde(with = "json_as_string")]
pub slowest: u64, // slowest latency in the ROLLING_LATENCIES_SIZE last latencies
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct TransferStats {
#[serde(with = "json_as_string")]
pub total: u64, // total amount transferred ever
#[serde(with = "json_as_string")]
pub maximum: u64, // maximum rate over the ROLLING_TRANSFERS_SIZE last amounts
#[serde(with = "json_as_string")]
pub average: u64, // average rate over the ROLLING_TRANSFERS_SIZE last amounts
#[serde(with = "json_as_string")]
pub minimum: u64, // minimum rate over the ROLLING_TRANSFERS_SIZE last amounts
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct TransferStatsDownUp {
pub down: TransferStats,
pub up: TransferStats,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct RPCStats {
pub messages_sent: u32, // number of rpcs that have been sent in the total_time range
pub messages_rcvd: u32, // number of rpcs that have been received in the total_time range
pub questions_in_flight: u32, // number of questions issued that have yet to be answered
#[serde(with = "opt_json_as_string")]
pub last_question: Option<u64>, // when the peer was last questioned (either successfully or not) and we wanted an answer
#[serde(with = "opt_json_as_string")]
pub last_seen_ts: Option<u64>, // when the peer was last seen for any reason, including when we first attempted to reach out to it
#[serde(with = "opt_json_as_string")]
pub first_consecutive_seen_ts: Option<u64>, // the timestamp of the first consecutive proof-of-life for this node (an answer or received question)
pub recent_lost_answers: u32, // number of answers that have been lost since we lost reliability
pub failed_to_send: u32, // number of messages that have failed to send since we last successfully sent one
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct PeerStats {
#[serde(with = "json_as_string")]
pub time_added: u64, // when the peer was added to the routing table
pub rpc_stats: RPCStats, // information about RPCs
pub latency: Option<LatencyStats>, // latencies for communications with the peer

View File

@ -40,3 +40,59 @@ pub fn serialize_json<T: Serialize + Debug>(val: T) -> String {
}
}
}
pub mod json_as_string {
use std::fmt::Display;
use std::str::FromStr;
use serde::{de, Deserialize, Deserializer, Serializer};
pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
T: Display,
S: Serializer,
{
serializer.collect_str(value)
}
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
T: FromStr,
T::Err: Display,
D: Deserializer<'de>,
{
String::deserialize(deserializer)?
.parse()
.map_err(de::Error::custom)
}
}
pub mod opt_json_as_string {
use std::fmt::Display;
use std::str::FromStr;
use serde::{de, Deserialize, Deserializer, Serializer};
pub fn serialize<T, S>(value: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
where
T: Display,
S: Serializer,
{
match value {
Some(v) => serializer.collect_str(v),
None => serializer.serialize_none(),
}
}
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
where
T: FromStr,
T::Err: Display,
D: Deserializer<'de>,
{
match Option::<String>::deserialize(deserializer)? {
None => Ok(None),
Some(v) => Ok(Some(v.parse::<T>().map_err(de::Error::custom)?)),
}
}
}

View File

@ -3,7 +3,6 @@ import 'dart:typed_data';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:veilid/veilid.dart';
import 'package:flutter_loggy/flutter_loggy.dart';
@ -188,7 +187,7 @@ class _MyAppState extends State<MyApp> with UiLoggy {
if (update is VeilidUpdateLog) {
await processUpdateLog(update);
} else {
loggy.trace("Update: " + update.json.toString());
loggy.trace("Update: ${update.json}");
}
}
}

View File

@ -7,7 +7,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.2"
version: "2.9.0"
boolean_selector:
dependency: transitive
description:
@ -28,21 +28,14 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
version: "1.2.1"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.1"
collection:
dependency: transitive
description:
@ -63,21 +56,21 @@ packages:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.3.1"
ffi:
dependency: transitive
description:
name: ffi
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.0.1"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.2"
version: "6.1.4"
flutter:
dependency: "direct main"
description: flutter
@ -134,30 +127,30 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.11"
version: "0.12.12"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4"
version: "0.1.5"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
version: "1.8.0"
path:
dependency: transitive
dependency: "direct main"
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.1"
version: "1.8.2"
path_provider:
dependency: transitive
dependency: "direct main"
description:
name: path_provider
url: "https://pub.dartlang.org"
@ -169,14 +162,14 @@ packages:
name: path_provider_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.14"
version: "2.0.20"
path_provider_ios:
dependency: transitive
description:
name: path_provider_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.10"
version: "2.0.11"
path_provider_linux:
dependency: transitive
description:
@ -204,7 +197,7 @@ packages:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.3"
platform:
dependency: transitive
description:
@ -232,7 +225,7 @@ packages:
name: rxdart
url: "https://pub.dartlang.org"
source: hosted
version: "0.27.4"
version: "0.27.5"
sky_engine:
dependency: transitive
description: flutter
@ -244,7 +237,7 @@ packages:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.2"
version: "1.9.0"
stack_trace:
dependency: transitive
description:
@ -265,21 +258,21 @@ packages:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.9"
version: "0.4.12"
vector_math:
dependency: transitive
description:
@ -300,14 +293,14 @@ packages:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.7.0"
version: "3.0.0"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0+1"
version: "0.2.0+2"
sdks:
dart: ">=2.17.0 <3.0.0"
flutter: ">=3.0.0"

View File

@ -34,6 +34,8 @@ dependencies:
cupertino_icons: ^1.0.2
loggy: ^2.0.1+1
flutter_loggy: ^2.0.1
path_provider: ^2.0.11
path: ^1.8.1
dev_dependencies:
flutter_test:

View File

@ -987,6 +987,243 @@ class VeilidConfig {
network = VeilidConfigNetwork.fromJson(json['network']);
}
////////////
class LatencyStats {
BigInt fastest;
BigInt average;
BigInt slowest;
LatencyStats({
required this.fastest,
required this.average,
required this.slowest,
});
Map<String, dynamic> get json {
return {
'fastest': fastest.toString(),
'average': average.toString(),
'slowest': slowest.toString(),
};
}
LatencyStats.fromJson(Map<String, dynamic> json)
: fastest = BigInt.parse(json['fastest']),
average = BigInt.parse(json['average']),
slowest = BigInt.parse(json['slowest']);
}
////////////
class TransferStats {
BigInt total;
BigInt fastest;
BigInt average;
BigInt slowest;
TransferStats({
required this.total,
required this.fastest,
required this.average,
required this.slowest,
});
Map<String, dynamic> get json {
return {
'total': total.toString(),
'fastest': fastest.toString(),
'average': average.toString(),
'slowest': slowest.toString(),
};
}
TransferStats.fromJson(Map<String, dynamic> json)
: total = BigInt.parse(json['fastest']),
fastest = BigInt.parse(json['fastest']),
average = BigInt.parse(json['average']),
slowest = BigInt.parse(json['slowest']);
}
////////////
class TransferStatsDownUp {
TransferStats down;
TransferStats up;
TransferStatsDownUp({
required this.down,
required this.up,
});
Map<String, dynamic> get json {
return {
'down': down.toString(),
'up': up.toString(),
};
}
TransferStatsDownUp.fromJson(Map<String, dynamic> json)
: down = TransferStats.fromJson(json['down']),
up = TransferStats.fromJson(json['up']);
}
////////////
class RPCStats {
int messagesSent;
int messagesRcvd;
int questionsInFlight;
BigInt? lastQuestion;
BigInt? lastSeenTs;
BigInt? firstConsecutiveSeenTs;
int recentLostAnswers;
int failedToSend;
RPCStats({
required this.messagesSent,
required this.messagesRcvd,
required this.questionsInFlight,
required this.lastQuestion,
required this.lastSeenTs,
required this.firstConsecutiveSeenTs,
required this.recentLostAnswers,
required this.failedToSend,
});
Map<String, dynamic> get json {
return {
'messages_sent': messagesSent,
'messages_rcvd': messagesRcvd,
'questions_in_flight': questionsInFlight,
'last_question': lastQuestion?.toString(),
'last_seen_ts': lastSeenTs?.toString(),
'first_consecutive_seen_ts': firstConsecutiveSeenTs?.toString(),
'recent_lost_answers': recentLostAnswers,
'failed_to_send': failedToSend,
};
}
RPCStats.fromJson(Map<String, dynamic> json)
: messagesSent = json['messages_sent'],
messagesRcvd = json['messages_rcvd'],
questionsInFlight = json['questions_in_flight'],
lastQuestion = json['last_question'] != null
? BigInt.parse(json['last_question'])
: null,
lastSeenTs = json['last_seen_ts'] != null
? BigInt.parse(json['last_seen_ts'])
: null,
firstConsecutiveSeenTs = json['first_consecutive_seen_ts'] != null
? BigInt.parse(json['first_consecutive_seen_ts'])
: null,
recentLostAnswers = json['recent_lost_answers'],
failedToSend = json['failed_to_send'];
}
////////////
class PeerStats {
BigInt timeAdded;
RPCStats rpcStats;
LatencyStats? latency;
TransferStatsDownUp transfer;
PeerStats({
required this.timeAdded,
required this.rpcStats,
required this.latency,
required this.transfer,
});
Map<String, dynamic> get json {
return {
'time_added': timeAdded.toString(),
'rpc_stats': rpcStats.json,
'latency': latency?.json,
'transfer': transfer.json,
};
}
PeerStats.fromJson(Map<String, dynamic> json)
: timeAdded = BigInt.parse(json['time_added']),
rpcStats = RPCStats.fromJson(json['rpc_stats']),
latency = json['latency'] != null
? LatencyStats.fromJson(json['latency'])
: null,
transfer = TransferStatsDownUp.fromJson(json['transfer']);
}
////////////
class PeerTableData {
String nodeId;
PeerAddress peerAddress;
PeerStats peerStats;
PeerTableData({
required this.nodeId,
required this.peerAddress,
required this.peerStats,
});
Map<String, dynamic> get json {
return {
'node_id': nodeId,
'peer_address': peerAddress.json,
'peer_stats': peerStats.json,
};
}
PeerTableData.fromJson(Map<String, dynamic> json)
: nodeId = json['node_id'],
peerAddress = PeerAddress.fromJson(json['peer_address']),
peerStats = PeerStats.fromJson(json['peer_stats']);
}
//////////////////////////////////////
/// AttachmentState
enum ProtocolType {
udp,
tcp,
ws,
wss,
}
extension ProtocolTypeExt on ProtocolType {
String get json {
return name.toUpperCase();
}
}
ProtocolType protocolTypeFromJson(String j) {
return ProtocolType.values.byName(j.toLowerCase());
}
////////////
class PeerAddress {
ProtocolType protocolType;
String socketAddress;
PeerAddress({
required this.protocolType,
required this.socketAddress,
});
Map<String, dynamic> get json {
return {
'protocol_type': protocolType.json,
'socket_address': socketAddress,
};
}
PeerAddress.fromJson(Map<String, dynamic> json)
: protocolType = protocolTypeFromJson(json['protocol_type']),
socketAddress = json['socket_address'];
}
//////////////////////////////////////
/// VeilidUpdate
@ -996,16 +1233,17 @@ abstract class VeilidUpdate {
case "Log":
{
return VeilidUpdateLog(
veilidLogLevelFromJson(json["log_level"]), json["message"]);
logLevel: veilidLogLevelFromJson(json["log_level"]),
message: json["message"]);
}
case "Attachment":
{
return VeilidUpdateAttachment(attachmentStateFromJson(json["state"]));
return VeilidUpdateAttachment(
state: VeilidStateAttachment.fromJson(json));
}
case "Network":
{
return VeilidUpdateNetwork(
json["started"], json["bps_up"], json["bps_down"]);
return VeilidUpdateNetwork(state: VeilidStateNetwork.fromJson(json));
}
default:
{
@ -1021,7 +1259,10 @@ class VeilidUpdateLog implements VeilidUpdate {
final VeilidLogLevel logLevel;
final String message;
//
VeilidUpdateLog(this.logLevel, this.message);
VeilidUpdateLog({
required this.logLevel,
required this.message,
});
@override
Map<String, dynamic> get json {
@ -1034,34 +1275,28 @@ class VeilidUpdateLog implements VeilidUpdate {
}
class VeilidUpdateAttachment implements VeilidUpdate {
final AttachmentState state;
final VeilidStateAttachment state;
//
VeilidUpdateAttachment(this.state);
VeilidUpdateAttachment({required this.state});
@override
Map<String, dynamic> get json {
return {
'kind': "Attachment",
'state': state.json,
};
var jsonRep = state.json;
jsonRep['kind'] = "Attachment";
return jsonRep;
}
}
class VeilidUpdateNetwork implements VeilidUpdate {
final bool started;
final int bpsDown;
final int bpsUp;
final VeilidStateNetwork state;
//
VeilidUpdateNetwork(this.started, this.bpsDown, this.bpsUp);
VeilidUpdateNetwork({required this.state});
@override
Map<String, dynamic> get json {
return {
'kind': "Network",
'started': started,
'bps_down': bpsDown,
'bps_up': bpsUp
};
var jsonRep = state.json;
jsonRep['kind'] = "Network";
return jsonRep;
}
}
@ -1075,6 +1310,12 @@ class VeilidStateAttachment {
VeilidStateAttachment.fromJson(Map<String, dynamic> json)
: state = attachmentStateFromJson(json['state']);
Map<String, dynamic> get json {
return {
'state': state.json,
};
}
}
//////////////////////////////////////
@ -1082,11 +1323,30 @@ class VeilidStateAttachment {
class VeilidStateNetwork {
final bool started;
final int bpsDown;
final int bpsUp;
final List<PeerTableData> peers;
VeilidStateNetwork(this.started);
VeilidStateNetwork(
{required this.started,
required this.bpsDown,
required this.bpsUp,
required this.peers});
VeilidStateNetwork.fromJson(Map<String, dynamic> json)
: started = json['started'];
: started = json['started'],
bpsDown = json['bps_down'],
bpsUp = json['bps_up'],
peers = json['peers'].map((j) => PeerTableData.fromJson(j)).toList();
Map<String, dynamic> get json {
return {
'started': started,
'bps_down': bpsDown,
'bps_up': bpsUp,
'peers': peers.map((p) => p.json).toList(),
};
}
}
//////////////////////////////////////
@ -1096,11 +1356,13 @@ class VeilidState {
final VeilidStateAttachment attachment;
final VeilidStateNetwork network;
VeilidState(this.attachment, this.network);
VeilidState.fromJson(Map<String, dynamic> json)
: attachment = VeilidStateAttachment.fromJson(json['attachment']),
network = VeilidStateNetwork.fromJson(json['network']);
Map<String, dynamic> get json {
return {'attachment': attachment.json, 'network': network.json};
}
}
//////////////////////////////////////