audit_counts/
audit_counts.rs1use wechat_profile::*;
4fn run() -> Result<()> {
5 let mut args = std::env::args().skip(1);
6 let path = args.next().ok_or(ProfileError::InvalidQuery)?;
7 let keys = args.next();
8 let location = ProfileLocation::new(path)?;
9 let (keys, plaintext) = if let Some(path) = keys {
10 (KeyFile::load(path)?, false)
11 } else {
12 (KeyFile::empty(location.account_directory()), true)
13 };
14 let r = ProfileReader::open(
15 location,
16 keys,
17 ReadOptions {
18 stopped_or_consistent_snapshot: true,
19 allow_plaintext: plaintext,
20 ..Default::default()
21 },
22 )?;
23 let mut contacts = 0;
24 let mut avatars = 0;
25 let mut q = ListQuery {
26 limit: Some(200),
27 ..Default::default()
28 };
29 loop {
30 let p = r.contacts(&q)?;
31 for c in &p.items {
32 if r.avatar(&c.username).is_ok() {
33 avatars += 1;
34 }
35 }
36 contacts += p.items.len();
37 q.cursor = p.next_cursor;
38 if q.cursor.is_none() {
39 break;
40 }
41 }
42 let mut threads = 0;
43 let mut q = ListQuery {
44 limit: Some(200),
45 ..Default::default()
46 };
47 loop {
48 let p = r.threads(&q)?;
49 threads += p.items.len();
50 q.cursor = p.next_cursor;
51 if q.cursor.is_none() {
52 break;
53 }
54 }
55 let mut groups = 0;
56 let mut members = 0;
57 let mut q = ListQuery {
58 limit: Some(200),
59 ..Default::default()
60 };
61 loop {
62 let p = r.groups(&q)?;
63 for g in &p.items {
64 let mut mq = ListQuery {
65 limit: Some(200),
66 ..Default::default()
67 };
68 loop {
69 let mp = r.group_members(&g.username, &mq)?;
70 members += mp.items.len();
71 mq.cursor = mp.next_cursor;
72 if mq.cursor.is_none() {
73 break;
74 }
75 }
76 }
77 groups += p.items.len();
78 q.cursor = p.next_cursor;
79 if q.cursor.is_none() {
80 break;
81 }
82 }
83 let mut messages = 0;
84 let mut unresolved = 0;
85 let mut decoded = 0;
86 let mut q = MessageQuery {
87 limit: Some(200),
88 ..Default::default()
89 };
90 loop {
91 let p = r.messages(&q)?;
92 for m in &p.items {
93 unresolved += usize::from(m.peer.is_none());
94 decoded += usize::from(m.content.text.is_some());
95 }
96 messages += p.items.len();
97 q.cursor = p.next_cursor;
98 if q.cursor.is_none() {
99 break;
100 }
101 }
102 println!(
103 "{}",
104 serde_json::json!({"databases":r.inventory().len(),"partial":r.coverage().partial,"contacts":contacts,"threads":threads,"groups":groups,"groupMembers":members,"cachedAvatars":avatars,"messages":messages,"decodedBodies":decoded,"unresolvedMessages":unresolved,"writesPerformed":false})
105 );
106 Ok(())
107}
108fn main() {
109 if let Err(e) = run() {
110 eprintln!("{e}");
111 std::process::exit(1);
112 }
113}