repos
/ analytics-rust master

analytics-rust

mirror archived upstream

Single-binary self-hosted website analytics on Rust axum: collector API, dashboards, world map, and PDF reports.

analyticsaxumdockerrustself-hostedsqliteviteweb-analytics

2.2 KB · 70 lines · Rust Raw History
 1use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions, SqliteSynchronous};
 2use sqlx::SqlitePool;
 3use std::path::Path;
 4use std::str::FromStr;
 5use std::time::Duration;
 6use uuid::Uuid;
 7
 8pub async fn init(data_dir: &Path) -> anyhow::Result<SqlitePool> {
 9    let db_path = data_dir.join("db.sqlite3");
10    let url = format!("sqlite://{}", db_path.display());
11
12    // Ensure file exists so sqlx can attach.
13    if !db_path.exists() {
14        std::fs::File::create(&db_path)?;
15    }
16
17    let opts = SqliteConnectOptions::from_str(&url)?
18        .create_if_missing(true)
19        .journal_mode(SqliteJournalMode::Wal)
20        .synchronous(SqliteSynchronous::Normal)
21        .busy_timeout(Duration::from_secs(5))
22        .foreign_keys(true);
23
24    let pool = SqlitePoolOptions::new()
25        .max_connections(8)
26        .connect_with(opts)
27        .await?;
28
29    sqlx::migrate!("./migrations").run(&pool).await?;
30    Ok(pool)
31}
32
33pub async fn ensure_proprium(pool: &SqlitePool) -> anyhow::Result<Uuid> {
34    let existing: Option<(String,)> =
35        sqlx::query_as("SELECT value FROM meta WHERE key = 'proprium_id'")
36            .fetch_optional(pool)
37            .await?;
38
39    if let Some((s,)) = existing {
40        if let Ok(uuid) = Uuid::parse_str(&s) {
41            // Make sure the property still exists (db could have been wiped).
42            let row: Option<(Vec<u8>,)> =
43                sqlx::query_as("SELECT id FROM properties WHERE id = ?")
44                    .bind(uuid.as_bytes().to_vec())
45                    .fetch_optional(pool)
46                    .await?;
47            if row.is_some() {
48                return Ok(uuid);
49            }
50        }
51    }
52
53    let id = Uuid::new_v4();
54    let now = chrono::Utc::now().timestamp_millis();
55    sqlx::query(
56        r#"INSERT INTO properties (id, name, custom_cards, is_protected, is_public, created_at, updated_at)
57           VALUES (?, 'Proprium', '[]', 1, 0, ?, ?)"#,
58    )
59    .bind(id.as_bytes().to_vec())
60    .bind(now)
61    .bind(now)
62    .execute(pool)
63    .await?;
64    sqlx::query("INSERT OR REPLACE INTO meta (key, value) VALUES ('proprium_id', ?)")
65        .bind(id.to_string())
66        .execute(pool)
67        .await?;
68    Ok(id)
69}