Skip to main content

sync_once/support/
mod.rs

1//! Shared ephemeral login for the network examples. Never serialize credentials.
2use anyhow::{bail, ensure, Result};
3use std::{
4    io::Write,
5    thread,
6    time::{Duration, Instant},
7};
8use wechat_protocol::{
9    is_retryable_login_poll_error, AccountState, DeviceProfile, LoginStatus, NativeClient,
10    NativeOptions,
11};
12
13pub fn login() -> Result<(NativeClient, AccountState)> {
14    let client = NativeClient::new(NativeOptions::default())?;
15    let device = DeviceProfile::generate("UnifiedPCLinux x86_64".into())?;
16    let qr_directory = wechat_platform::private_tempdir("wechat-protocol-example-")?;
17    let qr_path = qr_directory.path().join("login.png");
18    let mut attempt = client.start_qr_login(device, "Rust protocol example")?;
19    let mut qr = wechat_platform::OpenOptions::new()
20        .write(true)
21        .create_new(true)
22        .mode(0o600)
23        .open(&qr_path)?;
24    qr.write_all(&attempt.qr_png)?;
25    drop(qr);
26    eprintln!("Scan the private QR image: {}", qr_path.display());
27    eprintln!("Approve this example on the test account's phone.");
28    let deadline = Instant::now() + Duration::from_secs(600);
29    loop {
30        ensure!(Instant::now() < deadline, "Login example timed out");
31        match client.poll_login_guarded(&mut attempt, deadline, || false) {
32            Ok(LoginStatus::Approved) => {
33                let state = client.complete_login(&mut attempt)?;
34                eprintln!("Login complete; credentials remain in memory.");
35                return Ok((client, state));
36            }
37            Ok(LoginStatus::Pending | LoginStatus::Scanned) => {}
38            Ok(status) => bail!("Login stopped: {status:?}"),
39            Err(error) if is_retryable_login_poll_error(&error) => {}
40            Err(error) => return Err(error),
41        }
42        // Only polling an already issued challenge is repeated. QR creation,
43        // credential exchange and sends are never automatically resubmitted.
44        thread::sleep(Duration::from_secs(2));
45    }
46}