Skip to content
This repository was archived by the owner on Oct 21, 2025. It is now read-only.

Commit 61ed674

Browse files
committed
add /api/stats/versions
1 parent fc06627 commit 61ed674

File tree

9 files changed

+116
-17
lines changed

9 files changed

+116
-17
lines changed

.sqlx/query-46c6123ada38b3b7b0f8dc9cf6dbe3a8111f5af189a55179d15163c871e4a67a.json

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.lock

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "api"
3-
version = "2.1.6"
3+
version = "2.2.0"
44
edition = "2024"
55

66
[dependencies]

migrations/0006_sail_the_ship.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
DROP INDEX IF EXISTS "telemetry_data_data_idx";
2+
CREATE INDEX IF NOT EXISTS "telemetry_data_data_idx" ON "telemetry_data" USING gin ("data");

src/routes/latest.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::State;
22
use utoipa_axum::{router::OpenApiRouter, routes};
33

4-
mod index {
4+
mod get {
55
use crate::routes::GetState;
66
use serde::Serialize;
77
use utoipa::ToSchema;
@@ -28,6 +28,6 @@ mod index {
2828

2929
pub fn router(state: &State) -> OpenApiRouter<State> {
3030
OpenApiRouter::new()
31-
.routes(routes!(index::route))
31+
.routes(routes!(get::route))
3232
.with_state(state.clone())
3333
}

src/routes/stats/flags.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::State;
22
use utoipa_axum::{router::OpenApiRouter, routes};
33

4-
mod index {
4+
mod get {
55
use crate::routes::GetState;
66
use serde::{Deserialize, Serialize};
77
use std::collections::BTreeMap;
@@ -72,6 +72,6 @@ mod index {
7272

7373
pub fn router(state: &State) -> OpenApiRouter<State> {
7474
OpenApiRouter::new()
75-
.routes(routes!(index::route))
75+
.routes(routes!(get::route))
7676
.with_state(state.clone())
7777
}

src/routes/stats/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod flags;
22
mod panels;
3+
mod versions;
34

45
use super::State;
56
use utoipa_axum::router::OpenApiRouter;
@@ -8,5 +9,6 @@ pub fn router(state: &State) -> OpenApiRouter<State> {
89
OpenApiRouter::new()
910
.nest("/flags", flags::router(state))
1011
.nest("/panels", panels::router(state))
12+
.nest("/versions", versions::router(state))
1113
.with_state(state.clone())
1214
}

src/routes/stats/panels.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::State;
22
use utoipa_axum::{router::OpenApiRouter, routes};
33

4-
mod index {
4+
mod get {
55
use crate::routes::GetState;
66
use serde::{Deserialize, Serialize};
77
use utoipa::ToSchema;
@@ -72,6 +72,6 @@ mod index {
7272

7373
pub fn router(state: &State) -> OpenApiRouter<State> {
7474
OpenApiRouter::new()
75-
.routes(routes!(index::route))
75+
.routes(routes!(get::route))
7676
.with_state(state.clone())
7777
}

src/routes/stats/versions.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
use super::State;
2+
use utoipa_axum::{router::OpenApiRouter, routes};
3+
4+
mod get {
5+
use crate::routes::GetState;
6+
use indexmap::IndexMap;
7+
8+
#[utoipa::path(get, path = "/", responses(
9+
(status = OK, body = inline(HashMap<String, f64>)),
10+
))]
11+
pub async fn route(state: GetState) -> axum::Json<serde_json::Value> {
12+
let versions = state
13+
.cache
14+
.cached("stats::versions", 3600, || async {
15+
let mut versions: IndexMap<String, f64> = IndexMap::new();
16+
17+
let data = sqlx::query!(
18+
r#"
19+
SELECT version, percentage
20+
FROM (
21+
SELECT
22+
data->'blueprint'->>'version' AS version,
23+
(COUNT(*) * 100.0 / (
24+
SELECT COUNT(*)
25+
FROM telemetry_data
26+
WHERE id IN (
27+
SELECT latest_telemetry_data_id
28+
FROM telemetry_panels_with_latest
29+
)
30+
AND created > NOW() - INTERVAL '2 days'
31+
))::float8 AS percentage
32+
FROM telemetry_data
33+
WHERE
34+
id IN (
35+
SELECT latest_telemetry_data_id
36+
FROM telemetry_panels_with_latest
37+
)
38+
AND created > NOW() - INTERVAL '2 days'
39+
GROUP BY version
40+
) x
41+
WHERE x.version LIKE 'beta-202_-__'
42+
ORDER BY x.percentage DESC
43+
"#,
44+
)
45+
.fetch_all(state.database.read())
46+
.await
47+
.unwrap();
48+
49+
for row in data {
50+
versions.insert(
51+
row.version.unwrap(),
52+
(row.percentage.unwrap() * 100.0).round() / 100.0,
53+
);
54+
}
55+
56+
Ok(versions)
57+
})
58+
.await
59+
.unwrap();
60+
61+
axum::Json(serde_json::to_value(versions).unwrap())
62+
}
63+
}
64+
65+
pub fn router(state: &State) -> OpenApiRouter<State> {
66+
OpenApiRouter::new()
67+
.routes(routes!(get::route))
68+
.with_state(state.clone())
69+
}

0 commit comments

Comments
 (0)