Skip to main content

apply_text_fixture/
apply_text_fixture.rs

1//! Explicit stopped, disposable-clone validation. Input files are private; only
2//! aggregate outcomes are printed. Never use this helper on an active profile.
3use wechat_profile::*;
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}
64fn main() {
65    if let Err(e) = run() {
66        eprintln!("{e}");
67        std::process::exit(1);
68    }
69}