Skip to main content

libgrite_cli/
db.rs

1use std::collections::HashMap;
2
3use libgrite_core::{
4    config::list_actors,
5    integrity::{check_store_integrity, verify_store_signatures, CorruptionKind},
6    types::ids::id_to_hex,
7    GriteError,
8};
9
10use crate::context::GriteContext;
11use crate::types::*;
12
13/// Show database statistics.
14pub fn db_stats(ctx: &GriteContext) -> Result<DbStatsResult, GriteError> {
15    let store = ctx.open_store()?;
16    let sled_path = ctx.sled_path();
17
18    let stats = store.stats(&sled_path)?;
19
20    Ok(DbStatsResult {
21        path: sled_path,
22        size_bytes: stats.size_bytes,
23        event_count: stats.event_count,
24        issue_count: stats.issue_count,
25        last_rebuild_ts: stats.last_rebuild_ts,
26        events_since_rebuild: stats.events_since_rebuild,
27        days_since_rebuild: stats.days_since_rebuild,
28        rebuild_recommended: stats.rebuild_recommended,
29    })
30}
31
32/// Check database integrity.
33pub fn db_check(ctx: &GriteContext, opts: &DbCheckOptions) -> Result<DbCheckResult, GriteError> {
34    let store = ctx.open_store()?;
35
36    let report = check_store_integrity(&store, opts.verify_parents)?;
37
38    let hash_mismatches: Vec<String> = report
39        .corrupt_events
40        .iter()
41        .filter_map(|e| {
42            if let CorruptionKind::HashMismatch { expected, computed } = &e.kind {
43                Some(format!(
44                    "{}: hash mismatch expected {} computed {}",
45                    id_to_hex(&e.event_id),
46                    id_to_hex(expected),
47                    id_to_hex(computed)
48                ))
49            } else {
50                None
51            }
52        })
53        .collect();
54
55    let parent_errors: Vec<String> = report
56        .corrupt_events
57        .iter()
58        .filter_map(|e| {
59            if let CorruptionKind::MissingParent { parent_id } = &e.kind {
60                Some(format!(
61                    "{}: missing parent {}",
62                    id_to_hex(&e.event_id),
63                    id_to_hex(parent_id)
64                ))
65            } else {
66                None
67            }
68        })
69        .collect();
70
71    Ok(DbCheckResult {
72        checked_events: report.events_checked,
73        hash_mismatches,
74        parent_errors,
75    })
76}
77
78/// Verify event signatures.
79pub fn db_verify(
80    ctx: &GriteContext,
81    _opts: &DbVerifyOptions,
82) -> Result<DbVerifyResult, GriteError> {
83    let store = ctx.open_store()?;
84
85    let actors = list_actors(&ctx.git_dir)?;
86    let mut public_keys: HashMap<String, String> = HashMap::new();
87
88    for actor in &actors {
89        if let Some(pk) = &actor.public_key {
90            public_keys.insert(actor.actor_id.clone(), pk.clone());
91        }
92    }
93
94    let get_public_key = |actor_id: &str| -> Option<String> { public_keys.get(actor_id).cloned() };
95
96    let report = verify_store_signatures(&store, get_public_key)?;
97
98    let invalid_signatures: Vec<String> = report
99        .signature_errors
100        .iter()
101        .map(|e| {
102            format!(
103                "{} (actor {}): {}",
104                id_to_hex(&e.event_id),
105                e.actor_id,
106                e.error
107            )
108        })
109        .collect();
110
111    Ok(DbVerifyResult {
112        checked_events: report.events_checked,
113        invalid_signatures,
114    })
115}