pub struct ProfileLocation { /* private fields */ }Implementations§
Source§impl ProfileLocation
impl ProfileLocation
Sourcepub fn new(path: impl AsRef<Path>) -> Result<Self>
pub fn new(path: impl AsRef<Path>) -> Result<Self>
Select one account root containing db_storage, or db_storage itself. A whole WeChat home with multiple accounts is never resolved implicitly.
Examples found in repository?
examples/contacts.rs (line 9)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 let args: Vec<_> = std::env::args().skip(1).collect();
6 if args.len() != 3 || args[0] != "--stopped-or-consistent-copy" {
7 return Err("usage: contacts --stopped-or-consistent-copy ACCOUNT_ROOT KEYS_FILE".into());
8 }
9 let location = ProfileLocation::new(&args[1])?;
10 let keys = KeyFile::load(&args[2])?;
11 let reader = ProfileReader::open(
12 location,
13 keys,
14 ReadOptions {
15 stopped_or_consistent_snapshot: true,
16 ..Default::default()
17 },
18 )?;
19 println!(
20 "{} contacts",
21 reader.contacts(&ListQuery::default())?.items.len()
22 );
23 Ok(())
24}More examples
examples/apply_text_fixture.rs (line 9)
4fn run() -> Result<()> {
5 let a = std::env::args().skip(1).collect::<Vec<_>>();
6 if a.len() != 3 {
7 return Err(ProfileError::InvalidQuery);
8 }
9 let location = ProfileLocation::new(&a[0])?;
10 let keys = KeyFile::load(&a[1])?;
11 let input: IncomingText =
12 serde_json::from_slice(&std::fs::read(&a[2])?).map_err(|_| ProfileError::InvalidQuery)?;
13 let options = WriteOptions {
14 exclusive_ownership_confirmed: true,
15 allow_plaintext: false,
16 durable_intent_id: "explicit-disposable-fixture-validation".into(),
17 };
18 let first = apply_incoming_text(&location, &keys, &input, &options)?;
19 let retry = apply_incoming_text(&location, &keys, &input, &options)?;
20 let read = mark_read_messages(
21 &location,
22 &keys,
23 &input.peer,
24 std::slice::from_ref(&first.source_id),
25 &options,
26 )?;
27 let read_retry = mark_read_messages(
28 &location,
29 &keys,
30 &input.peer,
31 std::slice::from_ref(&first.source_id),
32 &options,
33 )?;
34 let reader = ProfileReader::open(
35 location,
36 keys,
37 ReadOptions {
38 stopped_or_consistent_snapshot: true,
39 ..Default::default()
40 },
41 )?;
42 let page = reader.messages(&MessageQuery {
43 chat: Some(input.peer),
44 limit: Some(200),
45 ..Default::default()
46 })?;
47 let found = page
48 .items
49 .iter()
50 .find(|v| v.id == first.source_id)
51 .ok_or(ProfileError::InvalidMetadata)?;
52 let exact = found.content.text.as_deref() == Some(input.content.as_str())
53 && found.source.text.as_deref() == Some(input.source_xml.as_str())
54 && found.server_message_id.as_deref() == Some(input.server_message_id.as_str());
55 if !exact || retry.message_inserted || read_retry.removed_unread_rows != 0 {
56 return Err(ProfileError::InvalidMetadata);
57 }
58 println!(
59 "{}",
60 serde_json::json!({"newTextInserted":first.message_inserted,"retryInsertedDuplicate":retry.message_inserted,"exactBodySourceAndServerIdentity":exact,"removedUnreadRows":read.removed_unread_rows,"readRetryRemovedRows":read_retry.removed_unread_rows,"unreadBefore":read.unread_count_before,"unreadAfter":read.unread_count_after,"crossDatabaseAtomic":first.cross_database_atomic,"networkUsed":false,"officialRuntimeUsed":false})
61 );
62 Ok(())
63}examples/audit_counts.rs (line 8)
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}pub fn root(&self) -> &Path
Sourcepub fn account_directory(&self) -> &str
pub fn account_directory(&self) -> &str
Examples found in repository?
examples/audit_counts.rs (line 12)
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}Trait Implementations§
Source§impl Clone for ProfileLocation
impl Clone for ProfileLocation
Auto Trait Implementations§
impl Freeze for ProfileLocation
impl RefUnwindSafe for ProfileLocation
impl Send for ProfileLocation
impl Sync for ProfileLocation
impl Unpin for ProfileLocation
impl UnsafeUnpin for ProfileLocation
impl UnwindSafe for ProfileLocation
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more