Skip to main content

multi_echo/
multi_echo.rs

1use wx_bot_sdk::{
2    BotAccountOptions, MultiStartOptions, MultiWeixinBot, MultiWeixinBotOptions,
3    auth::accounts::list_weixin_account_ids, bot::handler, resolve_weixin_account,
4};
5
6#[tokio::main]
7async fn main() -> wx_bot_sdk::Result<()> {
8    let accounts = read_accounts();
9    if accounts.is_empty() {
10        eprintln!("Usage:");
11        eprintln!("  WEIXIN_BOT_TOKENS=\"token1,token2\" cargo run --example multi_echo");
12        eprintln!("  cargo run --example multi_echo -- token1 token2");
13        eprintln!("\n如果已通过扫码登录保存账号,也可以直接运行:");
14        eprintln!("  cargo run --example multi_echo");
15        std::process::exit(1);
16    }
17
18    let multi = MultiWeixinBot::new(MultiWeixinBotOptions {
19        accounts,
20        state_dir: None,
21    });
22
23    println!("starting accounts: {:?}", multi.account_ids());
24    multi
25        .start(MultiStartOptions {
26            long_poll_timeout_ms: None,
27            on_message: handler(|ctx| async move {
28                println!("[{}] 来自 {}: {}", ctx.account_id, ctx.from, ctx.body);
29                Ok(Some(format!("你说了: {}", ctx.body)))
30            }),
31        })
32        .await?;
33
34    tokio::signal::ctrl_c().await?;
35    println!("stopping all accounts...");
36    multi.stop().await?;
37    multi.join().await?;
38    Ok(())
39}
40
41fn read_accounts() -> Vec<BotAccountOptions> {
42    let tokens = read_tokens();
43    if !tokens.is_empty() {
44        return tokens
45            .into_iter()
46            .map(|token| BotAccountOptions {
47                token,
48                account_id: None,
49                base_url: None,
50                cdn_base_url: None,
51            })
52            .collect();
53    }
54
55    list_weixin_account_ids()
56        .into_iter()
57        .filter_map(|account_id| match resolve_weixin_account(&account_id) {
58            Ok(account) => account.token.map(|token| BotAccountOptions {
59                token,
60                account_id: Some(account.account_id),
61                base_url: Some(account.base_url),
62                cdn_base_url: Some(account.cdn_base_url),
63            }),
64            Err(err) => {
65                eprintln!("跳过账号 {account_id}: {err}");
66                None
67            }
68        })
69        .collect()
70}
71
72fn read_tokens() -> Vec<String> {
73    let mut tokens = std::env::args()
74        .skip(1)
75        .flat_map(|arg| split_tokens(&arg).collect::<Vec<_>>())
76        .collect::<Vec<_>>();
77
78    if tokens.is_empty()
79        && let Ok(raw) = std::env::var("WEIXIN_BOT_TOKENS")
80    {
81        tokens = split_tokens(&raw).collect();
82    }
83
84    tokens
85}
86
87fn split_tokens(raw: &str) -> impl Iterator<Item = String> + '_ {
88    raw.split(',')
89        .map(str::trim)
90        .filter(|s| !s.is_empty())
91        .map(ToOwned::to_owned)
92}