codetether_browser/browser/offline/
cookie_diff.rs1use anyhow::{Context, Result};
5use std::path::Path;
6
7use super::cookie_diff_index::index;
8use super::cookie_parse::CookieRecord;
9
10#[derive(Debug, serde::Serialize)]
11pub struct CookieDelta {
12 pub added: Vec<CookieRecord>,
13 pub removed: Vec<CookieRecord>,
14 pub changed: Vec<Changed>,
15 pub duplicates: Vec<String>,
17}
18
19#[derive(Debug, serde::Serialize)]
20pub struct Changed {
21 pub key: String,
22 pub before: CookieRecord,
23 pub after: CookieRecord,
24}
25
26pub fn run(before_path: &Path, after_path: &Path) -> Result<String> {
27 let before = load(before_path).with_context(|| format!("read {}", before_path.display()))?;
28 let after = load(after_path).with_context(|| format!("read {}", after_path.display()))?;
29 Ok(serde_json::to_string_pretty(&diff(&before, &after))?)
30}
31
32fn load(path: &Path) -> Result<Vec<CookieRecord>> {
33 Ok(serde_json::from_str(&std::fs::read_to_string(path)?)?)
34}
35
36pub fn diff(before: &[CookieRecord], after: &[CookieRecord]) -> CookieDelta {
37 let (bmap, mut duplicates) = index(before);
38 let (amap, adup) = index(after);
39 duplicates.extend(adup);
40 duplicates.sort();
41 duplicates.dedup();
42 let added = amap
43 .iter()
44 .filter(|(k, _)| !bmap.contains_key(*k))
45 .map(|(_, c)| (*c).clone())
46 .collect();
47 let removed = bmap
48 .iter()
49 .filter(|(k, _)| !amap.contains_key(*k))
50 .map(|(_, c)| (*c).clone())
51 .collect();
52 let changed = bmap
53 .iter()
54 .filter_map(|(k, b)| {
55 amap.get(k).and_then(|a| {
56 (a != b).then(|| Changed {
57 key: k.clone(),
58 before: (*b).clone(),
59 after: (*a).clone(),
60 })
61 })
62 })
63 .collect();
64 CookieDelta {
65 added,
66 removed,
67 changed,
68 duplicates,
69 }
70}