feat(jni): expose detailed peer metrics
This commit is contained in:
+98
-12
@@ -68,6 +68,16 @@ where
|
|||||||
std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)).map_err(panic_message)
|
std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)).map_err(panic_message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn encryption_state(local_key: Option<&str>, peer_key: Option<&str>) -> i32 {
|
||||||
|
match (local_key, peer_key) {
|
||||||
|
(Some(local), Some(peer)) if local == peer => 1,
|
||||||
|
(None, None) => 2,
|
||||||
|
(Some(_), None) => 3,
|
||||||
|
(None, Some(_)) => 4,
|
||||||
|
(Some(_), Some(_)) => 5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// JNI 导出函数的 panic 防护:panic 时向 JVM 抛出异常并返回默认值
|
/// JNI 导出函数的 panic 防护:panic 时向 JVM 抛出异常并返回默认值
|
||||||
macro_rules! jni_guard {
|
macro_rules! jni_guard {
|
||||||
($env:ident, $default_ret:expr, { $($body:tt)* }) => {{
|
($env:ident, $default_ret:expr, { $($body:tt)* }) => {{
|
||||||
@@ -479,21 +489,88 @@ pub extern "system" fn Java_com_vnt_VntApi_nativeGetClientList<'local>(
|
|||||||
) -> jstring {
|
) -> jstring {
|
||||||
jni_guard!(env, std::ptr::null_mut(), {
|
jni_guard!(env, std::ptr::null_mut(), {
|
||||||
let result: anyhow::Result<String> = (|| {
|
let result: anyhow::Result<String> = (|| {
|
||||||
let global_state = GLOBAL_STATE.lock();
|
let (api, runtime) = {
|
||||||
let state = global_state.as_ref().context("VNT not initialized")?;
|
let global_state = GLOBAL_STATE.lock();
|
||||||
|
let state = global_state.as_ref().context("VNT not initialized")?;
|
||||||
|
(
|
||||||
|
state
|
||||||
|
.vnt_apis
|
||||||
|
.get(&api_handle)
|
||||||
|
.context("Invalid API handle")?
|
||||||
|
.clone(),
|
||||||
|
state.runtime.clone(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let api = state
|
let local_clients: HashMap<_, _> = api
|
||||||
.vnt_apis
|
.client_ips()
|
||||||
.get(&api_handle)
|
|
||||||
.context("Invalid API handle")?;
|
|
||||||
|
|
||||||
let client_ips = api.client_ips();
|
|
||||||
let json_array: Vec<_> = client_ips
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|client| {
|
.map(|client| (client.ip, client.online))
|
||||||
|
.collect();
|
||||||
|
let server_clients: HashMap<_, _> = runtime
|
||||||
|
.block_on(api.server_rpc().client_list())
|
||||||
|
.map(|response| {
|
||||||
|
response
|
||||||
|
.list
|
||||||
|
.into_iter()
|
||||||
|
.map(|client| (Ipv4Addr::from(client.ip), client))
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
let local_key = api.get_config().and_then(|config| config.key_sign());
|
||||||
|
let mut ips: Vec<_> = local_clients
|
||||||
|
.keys()
|
||||||
|
.chain(server_clients.keys())
|
||||||
|
.copied()
|
||||||
|
.collect();
|
||||||
|
ips.sort_unstable();
|
||||||
|
ips.dedup();
|
||||||
|
|
||||||
|
let json_array: Vec<_> = ips
|
||||||
|
.into_iter()
|
||||||
|
.map(|ip| {
|
||||||
|
let server_client = server_clients.get(&ip);
|
||||||
|
let route = api.find_route(&ip);
|
||||||
|
let has_route = route.is_some();
|
||||||
|
let direct = route
|
||||||
|
.as_ref()
|
||||||
|
.map(|route| route.metric() == 1)
|
||||||
|
.unwrap_or(false);
|
||||||
|
let route_protocol = route
|
||||||
|
.as_ref()
|
||||||
|
.map(|route| route.route_key().protocol().to_string());
|
||||||
|
let route_metric = route.as_ref().map(|route| route.metric());
|
||||||
|
let rtt = route.as_ref().map(|route| route.rtt());
|
||||||
|
let online = local_clients.get(&ip).copied().unwrap_or(false)
|
||||||
|
|| server_client.map(|client| client.online).unwrap_or(false)
|
||||||
|
|| has_route;
|
||||||
|
let packet_loss = api.packet_loss_info(&ip).map(|info| {
|
||||||
|
serde_json::json!({
|
||||||
|
"sent": info.sent,
|
||||||
|
"received": info.received,
|
||||||
|
"loss_rate": info.loss_rate,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
let traffic = api.traffic_info(&ip).map(|info| {
|
||||||
|
serde_json::json!({
|
||||||
|
"tx_bytes": info.tx_bytes,
|
||||||
|
"rx_bytes": info.rx_bytes,
|
||||||
|
})
|
||||||
|
});
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"ip": client.ip.to_string(),
|
"ip": ip.to_string(),
|
||||||
"online": client.online,
|
"name": server_client.map(|client| client.name.as_str()).unwrap_or(""),
|
||||||
|
"version": server_client.map(|client| client.version.as_str()).unwrap_or(""),
|
||||||
|
"online": online,
|
||||||
|
"direct": direct,
|
||||||
|
"route_protocol": route_protocol,
|
||||||
|
"route_metric": route_metric,
|
||||||
|
"rtt": rtt,
|
||||||
|
"key_equal": server_client
|
||||||
|
.map(|client| encryption_state(local_key.as_deref(), client.key_sign.as_deref()))
|
||||||
|
.unwrap_or(0),
|
||||||
|
"packet_loss": packet_loss,
|
||||||
|
"traffic": traffic,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
@@ -1034,4 +1111,13 @@ mod tests {
|
|||||||
let result: Result<(), String> = catch_jni_panic(|| panic!("{}", "kaboom"));
|
let result: Result<(), String> = catch_jni_panic(|| panic!("{}", "kaboom"));
|
||||||
assert_eq!(result.unwrap_err(), "kaboom");
|
assert_eq!(result.unwrap_err(), "kaboom");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn maps_peer_encryption_states() {
|
||||||
|
assert_eq!(encryption_state(Some("same"), Some("same")), 1);
|
||||||
|
assert_eq!(encryption_state(None, None), 2);
|
||||||
|
assert_eq!(encryption_state(Some("local"), None), 3);
|
||||||
|
assert_eq!(encryption_state(None, Some("peer")), 4);
|
||||||
|
assert_eq!(encryption_state(Some("local"), Some("peer")), 5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user