[Stats API] Add flat table to stats API (#6073)
* add flat table to stats API * remove day column
This commit is contained in:
Generated
+1
-1
@@ -7036,7 +7036,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-statistics-api"
|
||||
version = "0.1.5"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
|
||||
nym-statistics-api/.sqlx/query-c0c71601e6fb9d8746fb2cd5df11ac8ad9163f4de90c528ac62da8c47d108fa5.json
Generated
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO report_v1 (\n received_at,\n source_ip,\n device_id,\n from_mixnet,\n os_type,\n os_version,\n architecture,\n app_version,\n user_agent,\n connection_time_ms,\n two_hop,\n country_code)\n VALUES ($1::timestamptz, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Timestamptz",
|
||||
"Text",
|
||||
"Text",
|
||||
"Bool",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Int4",
|
||||
"Bool",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c0c71601e6fb9d8746fb2cd5df11ac8ad9163f4de90c528ac62da8c47d108fa5"
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-statistics-api"
|
||||
version = "0.1.5"
|
||||
version = "0.2.1"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
CREATE TABLE report_v1 (
|
||||
received_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
source_ip TEXT,
|
||||
device_id TEXT NOT NULL,
|
||||
from_mixnet BOOLEAN,
|
||||
os_type TEXT,
|
||||
os_version TEXT,
|
||||
architecture TEXT,
|
||||
app_version TEXT,
|
||||
user_agent TEXT,
|
||||
connection_time_ms INTEGER,
|
||||
two_hop BOOLEAN,
|
||||
country_code TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX idx_report_v1_received_at ON report_v1 (received_at);
|
||||
@@ -9,7 +9,7 @@ use crate::{
|
||||
error::{HttpError, HttpResult},
|
||||
state::AppState,
|
||||
},
|
||||
storage::models::{ConnectionInfoDto, DailyActiveDeviceDto},
|
||||
storage::models::{ConnectionInfoDto, DailyActiveDeviceDto, StatsReportV1Dto},
|
||||
};
|
||||
|
||||
pub(crate) fn routes() -> Router<AppState> {
|
||||
@@ -49,7 +49,7 @@ async fn submit_stats_report(
|
||||
debug!("Received a report from outside of the network");
|
||||
}
|
||||
|
||||
let active_device = DailyActiveDeviceDto::new(now, &report, user_agent, from_mixnet);
|
||||
let active_device = DailyActiveDeviceDto::new(now, &report, user_agent.clone(), from_mixnet);
|
||||
let maybe_connection_info = ConnectionInfoDto::maybe_new(
|
||||
now,
|
||||
&report,
|
||||
@@ -58,9 +58,24 @@ async fn submit_stats_report(
|
||||
from_mixnet,
|
||||
);
|
||||
|
||||
let stats_report = StatsReportV1Dto::new(
|
||||
now,
|
||||
&report,
|
||||
user_agent,
|
||||
from_mixnet,
|
||||
insecure_ip_addr.0,
|
||||
maybe_location,
|
||||
);
|
||||
|
||||
state
|
||||
.storage()
|
||||
.store_vpn_client_report(active_device, maybe_connection_info)
|
||||
.store_vpn_client_report(stats_report)
|
||||
.await
|
||||
.map_err(HttpError::internal_with_logging)?;
|
||||
|
||||
state
|
||||
.storage()
|
||||
.store_legacy_vpn_client_report(active_device, maybe_connection_info)
|
||||
.await
|
||||
.map_err(HttpError::internal_with_logging)?;
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ use sqlx::{
|
||||
};
|
||||
use std::{path::PathBuf, str::FromStr};
|
||||
|
||||
use crate::storage::models::StatsReportV1Dto;
|
||||
|
||||
pub(crate) mod models;
|
||||
|
||||
pub(crate) type DbPool = sqlx::PgPool;
|
||||
@@ -60,7 +62,7 @@ impl StatisticsStorage {
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) async fn store_vpn_client_report(
|
||||
pub(crate) async fn store_legacy_vpn_client_report(
|
||||
&mut self,
|
||||
active_device: DailyActiveDeviceDto,
|
||||
connection_info: Option<ConnectionInfoDto>,
|
||||
@@ -119,4 +121,41 @@ impl StatisticsStorage {
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn store_vpn_client_report(
|
||||
&mut self,
|
||||
report_v1: StatsReportV1Dto,
|
||||
) -> Result<()> {
|
||||
sqlx::query!(
|
||||
r#"INSERT INTO report_v1 (
|
||||
received_at,
|
||||
source_ip,
|
||||
device_id,
|
||||
from_mixnet,
|
||||
os_type,
|
||||
os_version,
|
||||
architecture,
|
||||
app_version,
|
||||
user_agent,
|
||||
connection_time_ms,
|
||||
two_hop,
|
||||
country_code)
|
||||
VALUES ($1::timestamptz, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)"#,
|
||||
report_v1.received_at as time::OffsetDateTime,
|
||||
report_v1.received_from,
|
||||
report_v1.stats_id,
|
||||
report_v1.from_mixnet,
|
||||
report_v1.os_type,
|
||||
report_v1.os_version,
|
||||
report_v1.os_arch,
|
||||
report_v1.app_version,
|
||||
report_v1.user_agent,
|
||||
report_v1.connection_time_ms,
|
||||
report_v1.two_hop,
|
||||
report_v1.country_code
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,3 +67,52 @@ impl ConnectionInfoDto {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// New structure. The two above will be removed when it is confirmed to work
|
||||
#[derive(Debug, Clone, sqlx::FromRow)]
|
||||
pub(crate) struct StatsReportV1Dto {
|
||||
pub(crate) received_at: OffsetDateTime,
|
||||
pub(crate) received_from: String,
|
||||
pub(crate) stats_id: StatsId,
|
||||
pub(crate) from_mixnet: bool,
|
||||
pub(crate) os_type: String,
|
||||
pub(crate) os_version: Option<String>,
|
||||
pub(crate) os_arch: String,
|
||||
pub(crate) app_version: String,
|
||||
pub(crate) user_agent: String,
|
||||
pub(crate) connection_time_ms: Option<i32>,
|
||||
pub(crate) two_hop: Option<bool>,
|
||||
pub(crate) country_code: Option<String>,
|
||||
}
|
||||
|
||||
impl StatsReportV1Dto {
|
||||
pub(crate) fn new(
|
||||
received_at: OffsetDateTime,
|
||||
stats_report: &VpnClientStatsReport,
|
||||
user_agent: UserAgent,
|
||||
from_mixnet: bool,
|
||||
received_from: IpAddr,
|
||||
maybe_country: Option<Country>,
|
||||
) -> Self {
|
||||
let mut report = Self {
|
||||
received_at,
|
||||
received_from: received_from.to_string(),
|
||||
stats_id: stats_report.stats_id.clone(),
|
||||
from_mixnet,
|
||||
os_type: stats_report.static_information.os_type.clone(),
|
||||
os_version: stats_report.static_information.os_version.clone(),
|
||||
os_arch: stats_report.static_information.os_arch.clone(),
|
||||
app_version: stats_report.static_information.app_version.clone(),
|
||||
user_agent: user_agent.to_string(),
|
||||
connection_time_ms: None,
|
||||
two_hop: None,
|
||||
country_code: maybe_country.map(|c| c.alpha2.into()),
|
||||
};
|
||||
if let Some(usage_report) = stats_report.basic_usage.as_ref() {
|
||||
report.connection_time_ms = usage_report.connection_time_ms;
|
||||
report.two_hop = Some(usage_report.two_hop);
|
||||
}
|
||||
|
||||
report
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user