Skip to main content

wake_test_sender/
wake_test_sender.rs

1//! Live wake check: a throwaway session writes one encrypted DM to a nick.
2//!
3//! Registers a fresh session (display name `WakeTestSender`, nick
4//! `waketestsender`, session id `wake-test-sender-<unix secs>`) with a store
5//! under a temp directory, opens the encrypted DM with the target nick,
6//! drives until the target joins (its web client accepts the invite), and
7//! sends one text. Prints room id and event id only.
8//!
9//! `M4A_HOMESERVER_URL` is required; `M4A_TEST_TARGET` defaults to
10//! `alice`; `M4A_TEST_WAIT_SECS` (default 90) bounds the wait for the join.
11//!
12//! cargo run -p mail4agent-messenger-shell --example wake_test_sender
13
14use mail4agent_messenger_shell::{OpenedStore, SessionConfig};
15use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
16
17fn now_ms() -> i64 {
18    SystemTime::now()
19        .duration_since(UNIX_EPOCH)
20        .map(|elapsed| elapsed.as_millis() as i64)
21        .unwrap_or(0)
22}
23
24fn fail(step: &str, err: impl std::fmt::Display) -> ! {
25    eprintln!("{step} failed: {err}");
26    std::process::exit(1);
27}
28
29fn main() {
30    let homeserver = std::env::var("M4A_HOMESERVER_URL")
31        .unwrap_or_else(|_| fail("env", "M4A_HOMESERVER_URL is not set"));
32    let target = std::env::var("M4A_TEST_TARGET").unwrap_or_else(|_| "alice".to_string());
33    let wait_secs: u64 = std::env::var("M4A_TEST_WAIT_SECS")
34        .ok()
35        .and_then(|value| value.parse().ok())
36        .unwrap_or(90);
37    let stamp = now_ms() / 1000;
38    let session_id = format!("wake-test-sender-{stamp}");
39    let store_root = std::env::temp_dir().join(format!("m4a-wake-test-{stamp}"));
40    let config = SessionConfig::new(
41        &homeserver,
42        "WakeTestSender",
43        &session_id,
44        &store_root,
45        None,
46    )
47    .unwrap_or_else(|err| fail("config", err));
48    let mut store = OpenedStore::connect(&config).unwrap_or_else(|err| fail("register", err));
49    println!("registered nick={} session={session_id}", config.nick());
50    let room_id = store
51        .ensure_dm(&target, now_ms())
52        .unwrap_or_else(|err| fail("ensure_dm", err));
53    println!("dm room={room_id}");
54    let started = Instant::now();
55    let peer = store
56        .find_nick(&target, now_ms())
57        .unwrap_or_else(|err| fail("find_nick", err))
58        .user_id;
59    loop {
60        if store.member_joined(&room_id, &peer) {
61            break;
62        }
63        if started.elapsed().as_secs() >= wait_secs {
64            fail(
65                "join wait",
66                format!("{target} did not join in {wait_secs}s"),
67            );
68        }
69        store
70            .drive(now_ms(), false)
71            .unwrap_or_else(|err| fail("drive", err));
72        std::thread::sleep(Duration::from_millis(500));
73    }
74    println!("peer joined user={peer}");
75    let encrypted = store
76        .rooms()
77        .into_iter()
78        .any(|room| room.room_id == room_id && room.encrypted);
79    println!("room encrypted={encrypted}");
80    let text = format!("wake test {stamp}");
81    store
82        .write_to_nick(&target, &text, now_ms())
83        .unwrap_or_else(|err| fail("write_to_nick", err));
84    let event_id = store
85        .texts()
86        .into_iter()
87        .find(|row| row.room_id == room_id && row.body == text)
88        .and_then(|row| row.event_id)
89        .unwrap_or_default();
90    println!("sent event={event_id}");
91}