Skip to content

Commit 3e758b4

Browse files
chore: update deps, switch to upstream duckdb
Signed-off-by: Henry Gressmann <[email protected]>
1 parent 8968610 commit 3e758b4

File tree

20 files changed

+330
-365
lines changed

20 files changed

+330
-365
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ path="src/main.rs"
1818
# async/concurrency
1919
tokio={version="1.44", default-features=false, features=["macros", "rt-multi-thread", "signal"]}
2020
tokio-util={version="0.7", features=["io"]}
21-
futures-lite="2.6"
21+
futures-lite={version="2.6", default-features=false, features=["alloc"]}
2222
crossbeam-utils="0.8"
2323
crossbeam-channel="0.5"
2424
quick_cache="0.6"
@@ -35,10 +35,10 @@ sha3={version="0.10"}
3535
argon2={version="0.5"}
3636

3737
# general
38-
argh={version="0.1"}
38+
argh={version="0.1", default-features=false, features=["help"]}
3939
eyre={version="0.6"}
40-
rand={version="0.9"}
41-
time={version="0.3"}
40+
rand={version="0.9", default-features=false, features=["std", "thread_rng"]}
41+
chrono={version="0.4"}
4242
colored={version="3.0"}
4343
figment={version="0.10", features=["toml", "env"]}
4444
tracing={version="0.1", default-features=false, features=["std"]}
@@ -51,11 +51,10 @@ poem={version="3.1", default-features=false, features=[
5151
"compression",
5252
"tower-compat",
5353
]}
54-
poem-openapi={version="5.1", default-features=false, features=["time"]}
54+
poem-openapi={version="5.1", default-features=false, features=["chrono"]}
5555
tower={version="0.5", default-features=false, features=["limit"]}
5656
uaparser="0.6"
57-
mime_guess={version="2.0"}
58-
rust-embed={version="8.7"}
57+
rust-embed={version="8.7", features=["mime-guess"]}
5958
reqwest={version="0.12", default-features=false, features=[
6059
"json",
6160
"stream",
@@ -65,18 +64,13 @@ reqwest={version="0.12", default-features=false, features=[
6564
rustls={version="0.23", features=["aws_lc_rs"]}
6665

6766
# database
68-
duckdb={git="https://github.com/explodingcamera-contrib/duckdb-rs", features=[
69-
"buildtime_bindgen",
70-
"bundled",
71-
"time",
72-
"r2d2",
73-
]}
74-
rusqlite={version="0.35", features=["bundled", "modern_sqlite", "time"]}
75-
r2d2={version="0.8"}
76-
r2d2_sqlite="0.28"
67+
duckdb={version="1.3", features=["buildtime_bindgen", "bundled", "chrono", "r2d2"]}
68+
rusqlite={version="0.36", features=["bundled", "modern_sqlite", "chrono"]}
69+
r2d2={version="0.8", default-features=false}
70+
r2d2_sqlite="0.30"
7771
refinery={version="0.8", default-features=false}
7872
refinery-core={version="0.8", default-features=false}
79-
maxminddb={version="0.26", optional=true}
73+
maxminddb={version="0.26", optional=true, features=["simdutf8"]}
8074
ahash="0.8"
8175

8276
[target.'cfg(not(target_env = "msvc"))'.dependencies]

data/licenses-cargo.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

data/licenses-npm.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

src/app/core/events.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::sync::Arc;
22

3+
use chrono::{DateTime, Utc};
34
use crossbeam_channel::Receiver;
45
use crossbeam_utils::sync::ShardedLock;
56
use eyre::{Result, bail};
6-
use time::OffsetDateTime;
77

88
use crate::app::models::{Event, event_params};
99
use crate::app::{DuckDBPool, EVENT_BATCH_INTERVAL, SqlitePool};
@@ -13,12 +13,12 @@ use crate::utils::hash::generate_salt;
1313
pub struct LiwanEvents {
1414
duckdb: DuckDBPool,
1515
sqlite: SqlitePool,
16-
daily_salt: Arc<ShardedLock<(String, OffsetDateTime)>>,
16+
daily_salt: Arc<ShardedLock<(String, DateTime<Utc>)>>,
1717
}
1818

1919
impl LiwanEvents {
2020
pub fn try_new(duckdb: DuckDBPool, sqlite: SqlitePool) -> Result<Self> {
21-
let daily_salt: (String, OffsetDateTime) = {
21+
let daily_salt: (String, DateTime<Utc>) = {
2222
tracing::debug!("Loading daily salt");
2323
sqlite.get()?.query_row("select salt, updated_at from salts where id = 1", [], |row| {
2424
Ok((row.get(0)?, row.get(1)?))
@@ -35,10 +35,10 @@ impl LiwanEvents {
3535
};
3636

3737
// if the salt is older than 24 hours, replace it with a new one (utils::generate_salt)
38-
if (OffsetDateTime::now_utc() - updated_at) > time::Duration::hours(24) {
38+
if (Utc::now() - updated_at) > chrono::Duration::hours(24) {
3939
tracing::debug!("Daily salt expired, generating a new one");
4040
let new_salt = generate_salt();
41-
let now = OffsetDateTime::now_utc();
41+
let now = Utc::now();
4242
let conn = self.sqlite.get()?;
4343
conn.execute("update salts set salt = ?, updated_at = ? where id = 1", rusqlite::params![&new_salt, now])?;
4444

@@ -56,7 +56,7 @@ impl LiwanEvents {
5656
pub fn append(&self, events: impl Iterator<Item = Event>) -> Result<()> {
5757
let conn = self.duckdb.get()?;
5858
let mut appender = conn.appender("events")?;
59-
let mut first_event_time = OffsetDateTime::now_utc();
59+
let mut first_event_time = Utc::now();
6060
for event in events {
6161
appender.append_row(event_params![event])?;
6262
if first_event_time > event.created_at {
@@ -105,7 +105,7 @@ impl LiwanEvents {
105105

106106
use duckdb::{Connection, Result as DuckResult, params};
107107

108-
pub fn update_event_times(conn: &Connection, from_time: OffsetDateTime) -> DuckResult<()> {
108+
pub fn update_event_times(conn: &Connection, from_time: DateTime<Utc>) -> DuckResult<()> {
109109
// this can probably be simplified, sadly the where clause can't contain window functions
110110
let sql = "--sql
111111
with

src/app/core/reports.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::fmt::{Debug, Display};
33

44
use crate::app::DuckDBConn;
55
use crate::utils::duckdb::{ParamVec, repeat_vars};
6+
use chrono::{DateTime, Utc};
67
use duckdb::params_from_iter;
78
use eyre::{Result, bail};
89
use poem_openapi::{Enum, Object};
@@ -11,8 +12,8 @@ pub use super::reports_cached::*;
1112

1213
#[derive(Object, Debug, Clone, Hash, PartialEq, Eq)]
1314
pub struct DateRange {
14-
pub start: time::OffsetDateTime,
15-
pub end: time::OffsetDateTime,
15+
pub start: DateTime<Utc>,
16+
pub end: DateTime<Utc>,
1617
}
1718

1819
impl DateRange {
@@ -22,10 +23,10 @@ impl DateRange {
2223
}
2324

2425
pub fn ends_in_future(&self) -> bool {
25-
self.end > time::OffsetDateTime::now_utc()
26+
self.end > Utc::now()
2627
}
2728

28-
pub fn duration(&self) -> time::Duration {
29+
pub fn duration(&self) -> chrono::Duration {
2930
self.end - self.start
3031
}
3132
}
@@ -218,7 +219,7 @@ fn metric_sql(metric: Metric) -> String {
218219
.to_owned()
219220
}
220221

221-
pub fn earliest_timestamp(conn: &DuckDBConn, entities: &[String]) -> Result<Option<time::OffsetDateTime>> {
222+
pub fn earliest_timestamp(conn: &DuckDBConn, entities: &[String]) -> Result<Option<DateTime<Utc>>> {
222223
if entities.is_empty() {
223224
return Ok(None);
224225
}
@@ -233,7 +234,7 @@ pub fn earliest_timestamp(conn: &DuckDBConn, entities: &[String]) -> Result<Opti
233234

234235
let mut stmt = conn.prepare_cached(&query)?;
235236
let rows = stmt.query_map(params_from_iter(entities), |row| row.get(0))?;
236-
let earliest_timestamp = rows.collect::<Result<Vec<Option<time::OffsetDateTime>>, duckdb::Error>>()?;
237+
let earliest_timestamp = rows.collect::<Result<Vec<Option<DateTime<Utc>>>, duckdb::Error>>()?;
237238
Ok(earliest_timestamp[0])
238239
}
239240

src/app/core/reports_cached.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::reports::{DateRange, Dimension, DimensionFilter, Metric, ReportGraph,
22
use super::reports::{dimension_report, overall_report, overall_stats};
33

44
use crate::{app::DuckDBConn, utils::to_sorted};
5+
use chrono::{DateTime, Utc};
56
use eyre::Result;
67
use quick_cache::sync::Cache;
78
use std::sync::LazyLock;
@@ -50,13 +51,13 @@ type DimensionCacheKey = (
5051
Metric,
5152
);
5253

53-
static OVERALL_REPORT_CACHE: LazyLock<Cache<OverallReportCacheKey, (time::OffsetDateTime, ReportGraph)>> =
54+
static OVERALL_REPORT_CACHE: LazyLock<Cache<OverallReportCacheKey, (DateTime<Utc>, ReportGraph)>> =
5455
LazyLock::new(|| Cache::new(1024));
5556

56-
static OVERALL_STATS_CACHE: LazyLock<Cache<OverallStatsCacheKey, (time::OffsetDateTime, ReportStats)>> =
57+
static OVERALL_STATS_CACHE: LazyLock<Cache<OverallStatsCacheKey, (DateTime<Utc>, ReportStats)>> =
5758
LazyLock::new(|| Cache::new(1024));
5859

59-
static DIMENSION_CACHE: LazyLock<Cache<DimensionCacheKey, (time::OffsetDateTime, ReportTable)>> =
60+
static DIMENSION_CACHE: LazyLock<Cache<DimensionCacheKey, (DateTime<Utc>, ReportTable)>> =
6061
LazyLock::new(|| Cache::new(1024));
6162

6263
/// [super::reports::overall_report] with caching
@@ -121,19 +122,19 @@ pub fn dimension_report_cached(
121122
}
122123

123124
/// Check if a cache entry should be invalidated
124-
fn should_invalidate(range: &DateRange, last_update: time::OffsetDateTime) -> bool {
125+
fn should_invalidate(range: &DateRange, last_update: DateTime<Utc>) -> bool {
125126
if !range.ends_in_future() {
126127
return false;
127128
}
128129

129-
let now = time::OffsetDateTime::now_utc();
130+
let now = Utc::now();
130131
let diff = now - last_update;
131132

132-
match range.duration().whole_days() {
133-
0..=6 => diff.whole_minutes() >= 1,
134-
7..=31 => diff.whole_minutes() > 5,
135-
32..=365 => diff.whole_minutes() > 30,
136-
_ => diff.whole_hours() > 1,
133+
match range.duration().num_days() {
134+
0..=6 => diff.num_minutes() >= 1,
135+
7..=31 => diff.num_minutes() > 5,
136+
32..=365 => diff.num_minutes() > 30,
137+
_ => diff.num_hours() > 1,
137138
}
138139
}
139140

@@ -142,7 +143,7 @@ fn should_invalidate(range: &DateRange, last_update: time::OffsetDateTime) -> bo
142143
/// Like quick_cache::sync::Cache::get_or_insert_with, but with a timeout for the guard
143144
/// and invalidation logic to recompute when the data might be stale
144145
fn get_or_compute<T, K, F>(
145-
cache: &LazyLock<Cache<K, (time::OffsetDateTime, T)>>,
146+
cache: &LazyLock<Cache<K, (DateTime<Utc>, T)>>,
146147
cache_key: K,
147148
compute: F,
148149
range: &DateRange,
@@ -169,10 +170,10 @@ where
169170

170171
match guard {
171172
Some(guard) => {
172-
let _ = guard.insert((time::OffsetDateTime::now_utc(), result.clone()));
173+
let _ = guard.insert((Utc::now(), result.clone()));
173174
}
174175
None => {
175-
cache.insert(cache_key, (time::OffsetDateTime::now_utc(), result.clone()));
176+
cache.insert(cache_key, (Utc::now(), result.clone()));
176177
}
177178
}
178179

src/app/core/sessions.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::app::{SqlitePool, models};
2+
use chrono::{DateTime, Utc};
23
use eyre::Result;
34
use rusqlite::params;
4-
use time::OffsetDateTime;
55

66
#[derive(Clone)]
77
pub struct LiwanSessions {
@@ -14,7 +14,7 @@ impl LiwanSessions {
1414
}
1515

1616
/// Create a new session
17-
pub fn create(&self, session_id: &str, username: &str, expires_at: OffsetDateTime) -> Result<()> {
17+
pub fn create(&self, session_id: &str, username: &str, expires_at: DateTime<Utc>) -> Result<()> {
1818
let conn = self.pool.get()?;
1919
let mut stmt = conn.prepare_cached("insert into sessions (id, username, expires_at) values (?, ?, ?)")?;
2020
stmt.execute(rusqlite::params![session_id, username, expires_at])?;
@@ -38,7 +38,7 @@ impl LiwanSessions {
3838
"#,
3939
)?;
4040

41-
let user = stmt.query_row(params![session_id, time::OffsetDateTime::now_utc()], |row| {
41+
let user = stmt.query_row(params![session_id, Utc::now()], |row| {
4242
Ok(models::User {
4343
username: row.get("username")?,
4444
role: row.get::<_, String>("role")?.try_into().unwrap_or_default(),
@@ -62,7 +62,7 @@ impl LiwanSessions {
6262
pub fn delete(&self, session_id: &str) -> Result<()> {
6363
let conn = self.pool.get()?;
6464
let mut stmt = conn.prepare_cached("update sessions set expires_at = ? where id = ?")?;
65-
stmt.execute(rusqlite::params![OffsetDateTime::now_utc(), session_id])?;
65+
stmt.execute(rusqlite::params![Utc::now(), session_id])?;
6666
Ok(())
6767
}
6868
}

src/app/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ impl Liwan {
112112
#[cfg(any(debug_assertions, test, feature = "_enable_seeding"))]
113113
impl Liwan {
114114
pub fn seed_database(&self, count_per_entity: usize) -> Result<()> {
115+
use chrono::{Days, Utc};
115116
use models::UserRole;
116-
use time::OffsetDateTime;
117117

118118
let entities = vec![
119119
("entity-1", "Entity 1", "example.com", vec!["public-project".to_string(), "private-project".to_string()]),
@@ -139,8 +139,8 @@ impl Liwan {
139139
)?;
140140
}
141141

142-
let start = OffsetDateTime::now_utc().checked_sub(time::Duration::days(365)).unwrap();
143-
let end = OffsetDateTime::now_utc();
142+
let start = Utc::now().checked_sub_days(Days::new(365)).unwrap();
143+
let end = Utc::now();
144144
for (entity_id, display_name, fqdn, project_ids) in entities {
145145
self.entities.create(
146146
&models::Entity { id: entity_id.to_string(), display_name: display_name.to_string() },

src/app/models.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ pub struct Event {
33
pub entity_id: String,
44
pub visitor_id: String,
55
pub event: String,
6-
pub created_at: OffsetDateTime,
6+
pub created_at: DateTime<Utc>,
77
pub fqdn: Option<String>,
88
pub path: Option<String>,
99
pub referrer: Option<String>,
@@ -99,7 +99,7 @@ macro_rules! event_params {
9999
};
100100
}
101101

102+
use chrono::{DateTime, Utc};
102103
pub use event_params;
103104
use poem_openapi::Enum;
104105
use serde::{Deserialize, Serialize};
105-
use time::OffsetDateTime;

0 commit comments

Comments
 (0)