Compare commits

..

3 Commits

Author SHA1 Message Date
Hocuri
0dd4edd4e6 clippy 2026-05-07 12:18:32 +02:00
Hocuri
0df7cc2612 test: Adapt test_stats_key_creation_timestamp() 2026-05-05 23:10:36 +02:00
Hocuri
24876f92aa feat: Reduce resolution of key_create_timestamps in the statistics
Right now, I'm reducing the resolution to 4 weeks (i.e. the timestamp is
rounded to the next multiple of 4 weeks); we could change this.
2026-05-05 23:01:12 +02:00
6 changed files with 29 additions and 21 deletions

View File

@@ -66,7 +66,7 @@ impl WebxdcMessageInfo {
self_addr,
is_app_sender,
is_broadcast,
send_update_interval_ms,
send_update_interval,
send_update_max_size,
} = message.get_webxdc_info(context).await?;
@@ -80,7 +80,7 @@ impl WebxdcMessageInfo {
self_addr,
is_app_sender,
is_broadcast,
send_update_interval: send_update_interval_ms,
send_update_interval,
send_update_max_size,
})
}

View File

@@ -91,9 +91,9 @@ impl Ratelimit {
self.until_can_send_at(SystemTime::now())
}
/// Returns the minimum possible sending interval.
pub fn min_send_interval(&self) -> Duration {
self.window.div_f64(self.quota)
/// Returns minimum possible update interval in milliseconds.
pub fn update_interval(&self) -> usize {
(self.window.as_millis() as f64 / self.quota) as usize
}
}
@@ -107,7 +107,7 @@ mod tests {
let mut ratelimit = Ratelimit::new_at(Duration::new(60, 0), 3.0, now);
assert!(ratelimit.can_send_at(now));
assert_eq!(ratelimit.min_send_interval(), Duration::new(20, 0));
assert_eq!(ratelimit.update_interval(), 20_000);
// Send burst of 3 messages.
ratelimit.send_at(now);

View File

@@ -29,6 +29,7 @@ const STATISTICS_BOT_VCARD: &str = include_str!("../assets/statistics-bot.vcf");
const SENDING_INTERVAL_SECONDS: i64 = 3600 * 24 * 7; // 1 week
// const SENDING_INTERVAL_SECONDS: i64 = 60; // 1 minute (for testing)
const MESSAGE_STATS_UPDATE_INTERVAL_SECONDS: i64 = 4 * 60; // 4 minutes (less than the lowest ephemeral messages timeout)
const KEY_CREATE_TIMESTAMP_RESOLUTION: u32 = 3600 * 24 * 7 * 4; // 4 weeks
#[derive(Serialize)]
struct Statistics {
@@ -348,7 +349,13 @@ async fn get_stats(context: &Context) -> Result<String> {
let key_create_timestamps: Vec<u32> = load_self_public_keyring(context)
.await?
.iter()
.map(|k| k.created_at().as_secs())
.map(|k| {
k.created_at()
.as_secs()
.div_ceil(KEY_CREATE_TIMESTAMP_RESOLUTION)
.checked_mul(KEY_CREATE_TIMESTAMP_RESOLUTION)
.unwrap_or(0)
})
.collect();
let sending_enabled_timestamps =

View File

@@ -486,6 +486,17 @@ async fn test_stats_key_creation_timestamp() -> Result<()> {
// Alice uses a pregenerated key. It was created at this timestamp:
const ALICE_KEY_CREATION_TIME: u128 = 1582855645;
// The key creation time's resolution is reduced in order to prevent deanonymization:
const CENSORED_KEY_CREATION_TIME: u128 = 1584576000;
assert!(CENSORED_KEY_CREATION_TIME.is_multiple_of(u128::from(KEY_CREATE_TIMESTAMP_RESOLUTION)));
const {
assert!(CENSORED_KEY_CREATION_TIME > ALICE_KEY_CREATION_TIME);
}
assert!(
CENSORED_KEY_CREATION_TIME - ALICE_KEY_CREATION_TIME
< u128::from(KEY_CREATE_TIMESTAMP_RESOLUTION)
);
let alice = &TestContext::new_alice().await;
alice.set_config_bool(Config::StatsSending, true).await?;
@@ -495,7 +506,7 @@ async fn test_stats_key_creation_timestamp() -> Result<()> {
assert_eq!(
key_create_timestamps,
&vec![Value::Number(
Number::from_u128(ALICE_KEY_CREATION_TIME).unwrap()
Number::from_u128(CENSORED_KEY_CREATION_TIME).unwrap()
)]
);

View File

@@ -21,7 +21,6 @@ mod maps_integration;
use std::cmp::max;
use std::collections::HashMap;
use std::path::Path;
use std::time::Duration;
use anyhow::{Context as _, Result, anyhow, bail, ensure, format_err};
@@ -120,7 +119,7 @@ pub struct WebxdcInfo {
/// Milliseconds to wait before calling `sendUpdate()` again since the last call.
/// Should be exposed to `window.sendUpdateInterval` in JS land.
pub send_update_interval_ms: usize,
pub send_update_interval: usize,
/// Maximum number of bytes accepted for a serialized update object.
/// Should be exposed to `window.sendUpdateMaxSize` in JS land.
@@ -975,16 +974,7 @@ impl Message {
self_addr,
is_app_sender,
is_broadcast,
send_update_interval_ms: context
.ratelimit
.read()
.await
.min_send_interval()
// Round the value up so that it's not 0 at least.
.checked_add(Duration::from_nanos(999_999))
.context("Overflow occurred")?
.as_millis()
.try_into()?,
send_update_interval: context.ratelimit.read().await.update_interval(),
send_update_max_size: RECOMMENDED_FILE_SIZE as usize,
})
}

View File

@@ -1226,7 +1226,7 @@ async fn test_get_webxdc_info() -> Result<()> {
let info = instance.get_webxdc_info(&t).await?;
assert_eq!(info.name, "minimal.xdc");
assert_eq!(info.icon, WEBXDC_DEFAULT_ICON.to_string());
assert_eq!(info.send_update_interval_ms, 1000);
assert_eq!(info.send_update_interval, 1000);
assert_eq!(info.send_update_max_size, RECOMMENDED_FILE_SIZE as usize);
let mut instance = create_webxdc_instance(