diff --git a/src/clash_conn_msg.rs b/src/clash_conn_msg.rs index 7d8d756..4f05d25 100644 --- a/src/clash_conn_msg.rs +++ b/src/clash_conn_msg.rs @@ -1,6 +1,6 @@ use serde::Deserialize; -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ClashConnectionMessage { pub id: String, @@ -9,7 +9,7 @@ pub struct ClashConnectionMessage { pub download: u64, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ClashConnectionsWrapper { pub connections: Vec, diff --git a/src/main.rs b/src/main.rs index cb05b83..287366d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,11 +64,14 @@ async fn main() { stdout() .write_all( format!( - "upload: {}, download: {}. speed_upload: {}, speed_download: {}\n", - wrapper.upload_total, - wrapper.download_total, + "len: {},speed_upload: {}, speed_download: {}, update_direct_speed: {}, download_direct_speed: {}, update_proxy_speed: {}, download_proxy_speed: {}\n", + state.connections, state.speed_upload, - state.speed_download + state.speed_download, + state.direct_upload_speed, + state.direct_download_speed, + state.proxy_upload_speed, + state.proxy_download_speed, ) .as_bytes(), ) diff --git a/src/statistics.rs b/src/statistics.rs index 86f7dcb..f69a7c3 100644 --- a/src/statistics.rs +++ b/src/statistics.rs @@ -1,8 +1,8 @@ -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; use tokio::sync::{Mutex, OnceCell}; -use crate::clash_conn_msg::ClashConnectionsWrapper; +use crate::clash_conn_msg::{ClashConnectionMessage, ClashConnectionsWrapper}; #[derive(Clone)] pub struct StatisticsState { @@ -11,6 +11,11 @@ pub struct StatisticsState { pub upload_total: u64, pub speed_upload: u64, pub speed_download: u64, + pub direct_upload_speed: u64, + pub direct_download_speed: u64, + pub proxy_upload_speed: u64, + pub proxy_download_speed: u64, + connection_map: Arc>>, } impl StatisticsState { @@ -21,14 +26,69 @@ impl StatisticsState { upload_total: 0, speed_upload: 0, speed_download: 0, + direct_upload_speed: 0, + direct_download_speed: 0, + proxy_upload_speed: 0, + proxy_download_speed: 0, + connection_map: Arc::new(Mutex::new(HashMap::new())), } } - pub fn update(&mut self, wrapper: &ClashConnectionsWrapper) { + pub async fn update(&mut self, wrapper: &ClashConnectionsWrapper) { self.connections = wrapper.connections.len(); self.update_speed(wrapper.upload_total, wrapper.download_total); self.download_total = wrapper.download_total; self.upload_total = wrapper.upload_total; + + self.reduce(&wrapper.connections).await; + } + + pub async fn reduce(&mut self, connections: &Vec) { + let mut direct_upload_speed = 0; + let mut direct_download_speed = 0; + let mut proxy_upload_speed = 0; + let mut proxy_download_speed = 0; + + let mut map = self.connection_map.lock().await; + let mut new_map = HashMap::new(); + + for connection in connections { + let id = &connection.id; + let prev = map.get(id); + new_map.insert(id.to_string(), connection.clone()); + + if prev.is_none() { + if connection.chains.len() >= 1 { + if connection.chains[0] == "DIRECT" { + direct_upload_speed += connection.upload; + direct_download_speed += connection.download; + } else { + proxy_upload_speed += connection.upload; + proxy_download_speed += connection.download; + } + } + continue; + } + + let prev = prev.unwrap(); + + if connection.chains.len() >= 1 { + if connection.chains[0] == "DIRECT" { + direct_upload_speed += connection.upload - prev.upload; + direct_download_speed += connection.download - prev.download; + } else { + proxy_upload_speed += connection.upload - prev.upload; + proxy_download_speed += connection.download - prev.download; + } + } + } + + *map = new_map; + + self.direct_download_speed = direct_download_speed; + self.direct_upload_speed = direct_upload_speed; + self.proxy_download_speed = proxy_download_speed; + self.proxy_upload_speed = proxy_upload_speed; } pub fn update_speed(&mut self, curr_upload: u64, curr_download: u64) { @@ -58,7 +118,7 @@ impl StatisticsManager { pub async fn update(&self, wrapper: &ClashConnectionsWrapper) { let mut state = self.state.lock().await; - state.update(wrapper); + state.update(wrapper).await; } pub async fn get_state(&self) -> StatisticsState {