Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

This file was deleted.

102 changes: 86 additions & 16 deletions src/db/models/wireguard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1003,11 +1003,12 @@ impl WireguardNetwork<Id> {
let activity_stats = query_as!(
WireguardNetworkActivityStats,
"SELECT \
COALESCE(COUNT(DISTINCT(u.id)), 0) \"active_users!\", \
COALESCE(COUNT(DISTINCT(s.device_id)), 0) \"active_devices!\" \
FROM \"user\" u \
JOIN device d ON d.user_id = u.id \
JOIN wireguard_peer_stats s ON s.device_id = d.id \
COALESCE(COUNT(DISTINCT CASE WHEN d.device_type = 'user' THEN u.id END), 0) \"active_users!\", \
COALESCE(COUNT(DISTINCT CASE WHEN d.device_type = 'user' THEN d.id END), 0) \"active_user_devices!\", \
COALESCE(COUNT(DISTINCT CASE WHEN d.device_type = 'network' THEN d.id END), 0) \"active_network_devices!\" \
FROM wireguard_peer_stats s \
JOIN device d ON d.id = s.device_id \
LEFT JOIN \"user\" u ON u.id = d.user_id \
WHERE latest_handshake >= $1 AND s.network = $2",
from,
self.id,
Expand All @@ -1027,11 +1028,12 @@ impl WireguardNetwork<Id> {
let activity_stats = query_as!(
WireguardNetworkActivityStats,
"SELECT \
COALESCE(COUNT(DISTINCT(u.id)), 0) \"active_users!\", \
COALESCE(COUNT(DISTINCT(s.device_id)), 0) \"active_devices!\" \
FROM \"user\" u \
JOIN device d ON d.user_id = u.id \
JOIN wireguard_peer_stats s ON s.device_id = d.id \
COALESCE(COUNT(DISTINCT CASE WHEN d.device_type = 'user' THEN u.id END), 0) \"active_users!\", \
COALESCE(COUNT(DISTINCT CASE WHEN d.device_type = 'user' THEN d.id END), 0) \"active_user_devices!\", \
COALESCE(COUNT(DISTINCT CASE WHEN d.device_type = 'network' THEN d.id END), 0) \"active_network_devices!\" \
FROM wireguard_peer_stats s \
JOIN device d ON d.id = s.device_id \
LEFT JOIN \"user\" u ON u.id = d.user_id \
WHERE latest_handshake >= $1 AND s.network = $2",
from,
self.id
Expand Down Expand Up @@ -1082,10 +1084,12 @@ impl WireguardNetwork<Id> {
let current_activity = self.current_activity(conn).await?;
let transfer_series = self.transfer_series(conn, from, aggregation).await?;
Ok(WireguardNetworkStats {
current_active_users: current_activity.active_users,
current_active_devices: current_activity.active_devices,
active_users: total_activity.active_users,
active_devices: total_activity.active_devices,
active_network_devices: total_activity.active_network_devices,
active_user_devices: total_activity.active_user_devices,
current_active_network_devices: current_activity.active_network_devices,
current_active_user_devices: current_activity.active_user_devices,
current_active_users: current_activity.active_users,
upload: transfer_series.iter().filter_map(|t| t.upload).sum(),
download: transfer_series.iter().filter_map(|t| t.download).sum(),
transfer_series,
Expand Down Expand Up @@ -1181,7 +1185,8 @@ pub struct WireguardUserStatsRow {

pub struct WireguardNetworkActivityStats {
pub active_users: i64,
pub active_devices: i64,
pub active_user_devices: i64,
pub active_network_devices: i64,
}

pub struct WireguardNetworkTransferStats {
Expand All @@ -1192,14 +1197,79 @@ pub struct WireguardNetworkTransferStats {
#[derive(Deserialize, Serialize)]
pub struct WireguardNetworkStats {
pub current_active_users: i64,
pub current_active_devices: i64,
pub current_active_user_devices: i64,
pub current_active_network_devices: i64,
pub active_users: i64,
pub active_devices: i64,
pub active_user_devices: i64,
pub active_network_devices: i64,
pub upload: i64,
pub download: i64,
pub transfer_series: Vec<WireguardStatsRow>,
}

pub(crate) async fn networks_stats(
conn: &PgPool,
from: &NaiveDateTime,
aggregation: &DateTimeAggregation,
) -> Result<WireguardNetworkStats, SqlxError> {
let total_activity = query_as!(
WireguardNetworkActivityStats,
"SELECT \
COALESCE(COUNT(DISTINCT CASE WHEN d.device_type = 'user' THEN u.id END), 0) \"active_users!\", \
COALESCE(COUNT(DISTINCT CASE WHEN d.device_type = 'user' THEN d.id END), 0) \"active_user_devices!\", \
COALESCE(COUNT(DISTINCT CASE WHEN d.device_type = 'network' THEN d.id END), 0) \"active_network_devices!\" \
FROM wireguard_peer_stats s \
JOIN device d ON d.id = s.device_id \
LEFT JOIN \"user\" u ON u.id = d.user_id \
WHERE latest_handshake >= $1",
from
)
.fetch_one(conn)
.await?;
let current_activity_from = (Utc::now() - WIREGUARD_MAX_HANDSHAKE).naive_utc();
let current_activity = query_as!(
WireguardNetworkActivityStats,
"SELECT \
COALESCE(COUNT(DISTINCT CASE WHEN d.device_type = 'user' THEN u.id END), 0) \"active_users!\", \
COALESCE(COUNT(DISTINCT CASE WHEN d.device_type = 'user' THEN d.id END), 0) \"active_user_devices!\", \
COALESCE(COUNT(DISTINCT CASE WHEN d.device_type = 'network' THEN d.id END), 0) \"active_network_devices!\" \
FROM wireguard_peer_stats s \
JOIN device d ON d.id = s.device_id \
LEFT JOIN \"user\" u ON u.id = d.user_id \
WHERE latest_handshake >= $1",
current_activity_from
)
.fetch_one(conn)
.await?;
let transfer_series = query_as!(
WireguardStatsRow,
"SELECT \
date_trunc($1, collected_at) \"collected_at: NaiveDateTime\", \
cast(sum(upload) AS bigint) upload, cast(sum(download) AS bigint) download \
FROM wireguard_peer_stats_view \
WHERE collected_at >= $2 \
GROUP BY 1 \
ORDER BY 1 \
LIMIT $3",
aggregation.fstring(),
from,
PEER_STATS_LIMIT,
)
.fetch_all(conn)
.await?;
Ok(WireguardNetworkStats {
current_active_users: current_activity.active_users,
current_active_network_devices: current_activity.active_network_devices,
current_active_user_devices: current_activity.active_user_devices,
active_users: total_activity.active_users,
active_network_devices: total_activity.active_network_devices,
active_user_devices: total_activity.active_user_devices,
download: transfer_series.iter().filter_map(|t| t.download).sum(),
upload: transfer_series.iter().filter_map(|t| t.upload).sum(),
transfer_series,
})
}

#[cfg(test)]
mod test {
use chrono::{SubsecRound, TimeDelta};
Expand Down
18 changes: 17 additions & 1 deletion src/grpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ use proto::proxy::{
// Helper struct used to handle gateway state
// gateways are grouped by network
type GatewayHostname = String;
#[derive(Debug)]
#[derive(Debug, Serialize, Clone)]
pub struct GatewayMap(HashMap<Id, HashMap<GatewayHostname, GatewayState>>);

#[derive(Error, Debug)]
Expand Down Expand Up @@ -286,6 +286,22 @@ impl GatewayMap {
None => None,
}
}

/// Flattens the inner hashmap into an `Vec`
///
/// Since key information in inner hashmap is within `GatewayState` it's simpler to consume it as Vec on web.
///
/// # Returns
/// Returns `HashMap<i64, Vec<GatewayState>>` from `GatewayMap`
pub fn into_flattened(self) -> HashMap<Id, Vec<GatewayState>> {
self.0
.into_iter()
.map(|(id, inner_map)| {
let states: Vec<GatewayState> = inner_map.into_values().collect();
(id, states)
})
.collect()
}
}

impl Default for GatewayMap {
Expand Down
Loading