~core/sage

ref: f11e86509b6263d2d92c20f8aefdc2472a1285bf sage/src/db.rs -rw-r--r-- 2.1 KiB
f11e8650 — core initial 21 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use std::path::{Path, PathBuf};
use dirs::config_dir;
use nucleo::{Config, Matcher, Utf32Str};
use serde::{Deserialize, Serialize};
use crate::identity::Identity;

#[derive(Serialize, Deserialize)]
pub struct Database {
    pub keys: Vec<Identity>
}
impl Database {
    pub fn load_or_create(path: &Path) -> anyhow::Result<Self> {
        if !database_exists(path) {
            let d = Database {
                keys: vec![]
            };
            write_database(d, path)?;
        }
        load_database(path)
    }
    pub fn write(self, path: &Path) -> anyhow::Result<()> {
        write_database(self, path)
    }
    pub fn fuzzy_search(&self, term: String) -> Vec<Identity> {
        if self.keys.is_empty() { return vec![] }
        let mut m = Matcher::new(Config::DEFAULT);

        let haystacks = self.keys.iter().map(|u| {
            (u.clone(), format!("{:?} {}", u, u.keys.pk().unwrap_or("<pk_unknown>".to_string())))
        }).collect::<Vec<_>>();

        let mut scores = haystacks.iter().map(|h| {
            (
                m.fuzzy_match(Utf32Str::Ascii(h.1.as_bytes()), Utf32Str::Ascii(term.as_bytes())).unwrap_or(0),
                h.0.clone()
            )
        }).collect::<Vec<_>>();

        scores.sort_by_key(|u| u.0);
        scores.reverse();

        let mut best_matches = vec![scores[0].clone()];
        for score in &scores[1..] {
            if score.0 == best_matches[0].0 {
                best_matches.push(score.clone());
            }
        }

        best_matches.iter().map(|u| u.1.clone()).collect()
    }
}

fn database_exists(path: &Path) -> bool {
    path.exists()
}
fn load_database(path: &Path) -> anyhow::Result<Database> {
    let f = std::fs::read_to_string(path)?;
    let data: Database = toml::from_str(&f)?;
    Ok(data)
}
fn write_database(d: Database, path: &Path) -> anyhow::Result<()> {
    let s = toml::to_string(&d)?;
    let s_with_warning = format!(
        "# This file is autogenerated; do not edit! sage v{}\n{}",
        env!("CARGO_PKG_VERSION"),
        s
    );
    std::fs::write(path, s_with_warning)?;
    Ok(())
}

pub fn db_default() -> PathBuf {
    config_dir().unwrap().join("sage.toml")
}