Implement net stats
This commit is contained in:
parent
a849904535
commit
82d3a22193
@ -12,3 +12,13 @@ mesh = SubResource("BoxMesh_m77kh")
|
|||||||
|
|
||||||
[node name="directional_light_3d" type="DirectionalLight3D" parent="." unique_id=75522463]
|
[node name="directional_light_3d" type="DirectionalLight3D" parent="." unique_id=75522463]
|
||||||
transform = Transform3D(0.61237246, -0.5, 0.61237246, 0.3535534, 0.8660254, 0.3535534, -0.7071068, 0, 0.7071068, 0, 1, 2)
|
transform = Transform3D(0.61237246, -0.5, 0.61237246, 0.3535534, 0.8660254, 0.3535534, -0.7071068, 0, 0.7071068, 0, 1, 2)
|
||||||
|
|
||||||
|
[node name="netstats" type="NetStatsLabel" parent="." unique_id=1366169487]
|
||||||
|
anchors_preset = 12
|
||||||
|
anchor_top = 1.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_top = -144.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 0
|
||||||
|
vertical_alignment = 2
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use std::net::SocketAddr;
|
|||||||
|
|
||||||
use godot::prelude::*;
|
use godot::prelude::*;
|
||||||
|
|
||||||
pub mod network_manager;
|
pub mod net;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
|
||||||
struct MyExtension;
|
struct MyExtension;
|
||||||
|
|||||||
2
rust/src/net/mod.rs
Normal file
2
rust/src/net/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod net_stats;
|
||||||
|
pub mod network_manager;
|
||||||
57
rust/src/net/net_stats.rs
Normal file
57
rust/src/net/net_stats.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use godot::prelude::*;
|
||||||
|
use teanet::stats::NetStats;
|
||||||
|
|
||||||
|
#[derive(GodotClass)]
|
||||||
|
#[class(base=Object, singleton)]
|
||||||
|
pub struct Stats {
|
||||||
|
pub statistics: Statistics,
|
||||||
|
last_update: Instant,
|
||||||
|
|
||||||
|
base: Base<Object>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[godot_api]
|
||||||
|
impl IObject for Stats {
|
||||||
|
fn init(base: Base<Object>) -> Self {
|
||||||
|
Stats {
|
||||||
|
statistics: Default::default(),
|
||||||
|
last_update: Instant::now(),
|
||||||
|
base,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stats {
|
||||||
|
pub fn update_stats(&mut self, stats: NetStats) {
|
||||||
|
let now = Instant::now();
|
||||||
|
|
||||||
|
let tx_diff =
|
||||||
|
stats.bytes_tx.max(self.statistics.total_bytes_tx) - self.statistics.total_bytes_tx;
|
||||||
|
let rx_diff =
|
||||||
|
stats.bytes_rx.max(self.statistics.total_bytes_rx) - self.statistics.total_bytes_rx;
|
||||||
|
|
||||||
|
self.statistics.total_bytes_rx = stats.bytes_rx;
|
||||||
|
self.statistics.total_bytes_tx = stats.bytes_tx;
|
||||||
|
self.statistics.packet_loss =
|
||||||
|
1. - ((stats.messages_received as f64) / (stats.messages_expected as f64));
|
||||||
|
|
||||||
|
let duration = now - self.last_update;
|
||||||
|
let tx_bps = tx_diff as f64 / duration.as_secs_f64();
|
||||||
|
let rx_bps = rx_diff as f64 / duration.as_secs_f64();
|
||||||
|
self.statistics.tx_bps = tx_bps as usize;
|
||||||
|
self.statistics.rx_bps = rx_bps as usize;
|
||||||
|
|
||||||
|
self.last_update = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Statistics {
|
||||||
|
pub total_bytes_tx: usize,
|
||||||
|
pub total_bytes_rx: usize,
|
||||||
|
pub tx_bps: usize,
|
||||||
|
pub rx_bps: usize,
|
||||||
|
pub packet_loss: f64,
|
||||||
|
}
|
||||||
@ -7,7 +7,10 @@ use godot::{prelude::*, tools::get_autoload_by_name};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use teanet::{Peer, PeerConfig};
|
use teanet::{Peer, PeerConfig};
|
||||||
|
|
||||||
use crate::ui::cli::{CLI_GLOBAL_NAME, CliColor, CommandLinePanel};
|
use crate::{
|
||||||
|
net::net_stats::Stats,
|
||||||
|
ui::cli::{CLI_GLOBAL_NAME, CliColor, CommandLinePanel},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(GodotClass)]
|
#[derive(GodotClass)]
|
||||||
#[class(base=Node)]
|
#[class(base=Node)]
|
||||||
@ -15,6 +18,7 @@ pub struct NetworkManager {
|
|||||||
peer: Option<PeerKind>,
|
peer: Option<PeerKind>,
|
||||||
|
|
||||||
last_hello: Instant,
|
last_hello: Instant,
|
||||||
|
last_netstat_update: Instant,
|
||||||
|
|
||||||
base: Base<Node>,
|
base: Base<Node>,
|
||||||
}
|
}
|
||||||
@ -25,8 +29,11 @@ pub const NETWORK_SINGLETON_NAME: &str = "NetworkManagerGlob";
|
|||||||
impl INode for NetworkManager {
|
impl INode for NetworkManager {
|
||||||
fn init(base: Base<Node>) -> Self {
|
fn init(base: Base<Node>) -> Self {
|
||||||
NetworkManager {
|
NetworkManager {
|
||||||
last_hello: Instant::now(),
|
|
||||||
peer: None,
|
peer: None,
|
||||||
|
|
||||||
|
last_hello: Instant::now(),
|
||||||
|
last_netstat_update: Instant::now(),
|
||||||
|
|
||||||
base,
|
base,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,10 +59,18 @@ impl INode for NetworkManager {
|
|||||||
if let Some(peer) = &mut self.peer {
|
if let Some(peer) = &mut self.peer {
|
||||||
let mut cli = get_autoload_by_name::<CommandLinePanel>(CLI_GLOBAL_NAME);
|
let mut cli = get_autoload_by_name::<CommandLinePanel>(CLI_GLOBAL_NAME);
|
||||||
|
|
||||||
|
let now = Instant::now();
|
||||||
|
if now - self.last_netstat_update > Duration::from_millis(1000) {
|
||||||
|
Stats::singleton().bind_mut().update_stats(match peer {
|
||||||
|
PeerKind::Client(peer, _) => peer.statistics(),
|
||||||
|
PeerKind::Server(peer, _) => peer.statistics(),
|
||||||
|
});
|
||||||
|
self.last_netstat_update = now;
|
||||||
|
}
|
||||||
|
|
||||||
match peer {
|
match peer {
|
||||||
PeerKind::Client(..) => {}
|
PeerKind::Client(..) => {}
|
||||||
PeerKind::Server(peer, _) => {
|
PeerKind::Server(peer, _) => {
|
||||||
let now = Instant::now();
|
|
||||||
if now - self.last_hello > Duration::from_millis(2000) {
|
if now - self.last_hello > Duration::from_millis(2000) {
|
||||||
self.last_hello = now;
|
self.last_hello = now;
|
||||||
peer.broadcast_reliable(Package::Hello);
|
peer.broadcast_reliable(Package::Hello);
|
||||||
@ -7,7 +7,7 @@ use godot::classes::{Engine, IPanel, Panel, RichTextLabel, ScrollContainer, Text
|
|||||||
use godot::prelude::*;
|
use godot::prelude::*;
|
||||||
use godot::tools::get_autoload_by_name;
|
use godot::tools::get_autoload_by_name;
|
||||||
|
|
||||||
use crate::network_manager::{NETWORK_SINGLETON_NAME, NetworkManager};
|
use crate::net::network_manager::{NETWORK_SINGLETON_NAME, NetworkManager};
|
||||||
|
|
||||||
pub enum CliColor {
|
pub enum CliColor {
|
||||||
Command,
|
Command,
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
pub mod cli;
|
pub mod cli;
|
||||||
|
pub mod net_stats;
|
||||||
|
|||||||
40
rust/src/ui/net_stats.rs
Normal file
40
rust/src/ui/net_stats.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
use godot::{
|
||||||
|
classes::{ILabel, Label},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::net::net_stats::Stats;
|
||||||
|
|
||||||
|
#[derive(GodotClass)]
|
||||||
|
#[class(base=Label)]
|
||||||
|
pub struct NetStatsLabel {
|
||||||
|
since_update: f64,
|
||||||
|
base: Base<Label>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[godot_api]
|
||||||
|
impl ILabel for NetStatsLabel {
|
||||||
|
fn init(base: Base<Self::Base>) -> Self {
|
||||||
|
NetStatsLabel {
|
||||||
|
since_update: 0.,
|
||||||
|
base,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process(&mut self, delta: f64) {
|
||||||
|
self.since_update += delta;
|
||||||
|
if self.since_update > 0.1 {
|
||||||
|
self.since_update = 0.;
|
||||||
|
let stats = Stats::singleton();
|
||||||
|
let statistics = &stats.bind().statistics;
|
||||||
|
self.base_mut().set_text(&format!(
|
||||||
|
"TX: {} ({} bps)\nRX: {} ({} bps)\nPacket Loss: {:.2}%",
|
||||||
|
statistics.total_bytes_tx,
|
||||||
|
statistics.tx_bps,
|
||||||
|
statistics.total_bytes_rx,
|
||||||
|
statistics.rx_bps,
|
||||||
|
statistics.packet_loss * 100.
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1 +1 @@
|
|||||||
Subproject commit 44122d77d6382043be85ff0a72398748b9ab3493
|
Subproject commit 3551d0e50b598e96fb3ffbb5cce5ad5792f891ae
|
||||||
Loading…
Reference in New Issue
Block a user