Reworked statistics

This commit is contained in:
Ultradesu
2026-07-26 01:41:16 +03:00
parent 17eb6a4fee
commit ada18a4583
14 changed files with 957 additions and 216 deletions
+146 -2
View File
@@ -957,6 +957,94 @@ impl DeviceSync {
Ok(())
}
pub fn record_leave_group_revoke(&self) -> Result<String> {
let op = self.record_local_op_generated(
|identity, seq| {
Ok(SyncOpPayload::DeviceRevoked {
target_device_id: identity.device_id.clone(),
target_max_seq_seen: seq,
})
},
false,
)?;
Ok(op.op_id)
}
pub fn cancel_leave_group_revoke(&self, op_id: &str) -> Result<()> {
let identity = self.ensure_identity()?;
let conn = lock(&self.conn);
conn.execute("DELETE FROM sync_ops WHERE op_id = ?1", [op_id])?;
conn.execute(
"UPDATE sync_devices
SET revoked_at_ms = NULL,
revoked_by = NULL,
revoke_cutoff_seq = NULL
WHERE device_id = ?1",
[&identity.device_id],
)?;
Ok(())
}
pub fn finish_leave_group_reset(&self) -> Result<String> {
let identity = self.ensure_identity()?;
let new_group_id = format!(
"grp_{}",
&blake3::hash(random_hex(32).as_bytes()).to_hex()[..24]
);
let now = now_ms();
{
let conn = lock(&self.conn);
set_meta(&conn, "group_id", &new_group_id)?;
set_meta(&conn, "last_sync", "left previous device group")?;
delete_meta(&conn, "last_error")?;
conn.execute("DELETE FROM sync_invites", [])?;
conn.execute("DELETE FROM sync_pending_pairing", [])?;
conn.execute("DELETE FROM sync_ops", [])?;
conn.execute("DELETE FROM sync_vectors", [])?;
conn.execute("DELETE FROM sync_peer_acks", [])?;
conn.execute("DELETE FROM sync_compacted", [])?;
conn.execute("DELETE FROM sync_playback_applied", [])?;
conn.execute(
"DELETE FROM sync_devices WHERE device_id != ?1",
[&identity.device_id],
)?;
conn.execute(
"INSERT INTO sync_devices
(device_id, name, client_version, protocol_version, endpoint_id,
endpoint_ticket, trusted_at_ms, last_seen_ms, revoked_at_ms,
revoked_by, revoke_cutoff_seq)
VALUES (?1, ?2, ?3, ?4, '', '', ?5, ?5, NULL, NULL, NULL)
ON CONFLICT(device_id) DO UPDATE SET
name = excluded.name,
client_version = excluded.client_version,
protocol_version = excluded.protocol_version,
trusted_at_ms = excluded.trusted_at_ms,
last_seen_ms = excluded.last_seen_ms,
revoked_at_ms = NULL,
revoked_by = NULL,
revoke_cutoff_seq = NULL",
params![
identity.device_id,
identity.name,
CLIENT_VERSION,
PROTOCOL_VERSION,
now,
],
)?;
let local_seq = get_meta(&conn, "local_seq")?
.and_then(|value| value.parse::<i64>().ok())
.unwrap_or(0);
conn.execute(
"INSERT INTO sync_vectors (device_id, max_seq)
VALUES (?1, ?2)
ON CONFLICT(device_id) DO UPDATE SET max_seq = excluded.max_seq",
params![identity.device_id, local_seq],
)?;
}
lock(&self.playback).remote.clear();
Ok(new_group_id)
}
pub fn record_content_like(&self, content_id: &str, liked: bool) -> Result<()> {
let Some(content_id) = music_dht::normalize_content_id(content_id) else {
return Ok(());
@@ -1269,6 +1357,15 @@ impl DeviceSync {
}
fn record_local_op(&self, payload: SyncOpPayload) -> Result<()> {
self.record_local_op_generated(|_, _| Ok(payload), true)
.map(|_| ())
}
fn record_local_op_generated(
&self,
make_payload: impl FnOnce(&LocalIdentity, i64) -> Result<SyncOpPayload>,
gc_after_record: bool,
) -> Result<SyncOpWire> {
let identity = self.ensure_identity()?;
let (op, payload_json, tombstone) = {
let conn = lock(&self.conn);
@@ -1281,6 +1378,7 @@ impl DeviceSync {
.unwrap_or(0);
let hlc_ms = now_ms().max(last_hlc + 1);
let op_id = format!("{}:{seq}", identity.device_id);
let payload = make_payload(&identity, seq)?;
let payload_json = serde_json::to_string(&payload)?;
let tombstone = payload.is_tombstone();
conn.execute(
@@ -1327,8 +1425,10 @@ impl DeviceSync {
payload = %payload_json,
"recorded personal-sync op"
);
let _ = self.gc_tombstones();
Ok(())
if gc_after_record {
let _ = self.gc_tombstones();
}
Ok(op)
}
fn apply_ops(&self, ops: Vec<SyncOpWire>) -> Result<()> {
@@ -3588,6 +3688,50 @@ mod tests {
assert!(!device_known(&sync, device_id));
}
#[test]
fn leave_group_self_revokes_then_resets_to_new_group() {
let sync = test_sync();
let identity = sync.ensure_identity().unwrap();
let old_group = identity.group_id.clone();
sync.apply_device_trusted("dev_peer", 10).unwrap();
let op_id = sync.record_leave_group_revoke().unwrap();
assert!(device_revoked(&sync, &identity.device_id));
{
let conn = lock(&sync.conn);
let payload_json: String = conn
.query_row(
"SELECT payload_json FROM sync_ops WHERE op_id = ?1",
[&op_id],
|row| row.get(0),
)
.unwrap();
let payload: SyncOpPayload = serde_json::from_str(&payload_json).unwrap();
match payload {
SyncOpPayload::DeviceRevoked {
target_device_id,
target_max_seq_seen,
} => {
assert_eq!(target_device_id, identity.device_id);
assert_eq!(target_max_seq_seen, 1);
}
other => panic!("unexpected payload: {other:?}"),
}
}
let new_group = sync.finish_leave_group_reset().unwrap();
assert_ne!(old_group, new_group);
let status = sync.status();
assert_eq!(status.group_id, new_group);
assert_eq!(status.active_devices, 1);
assert_eq!(status.devices.len(), 1);
assert!(status.devices[0].is_self);
assert!(!status.devices[0].revoked);
assert_eq!(status.ops_total, 0);
assert_eq!(status.outbox_ops, 0);
assert!(!device_known(&sync, "dev_peer"));
}
#[test]
fn playback_command_is_targeted_and_deduplicated() {
let sync = test_sync();