Skip to main content

v2_community_bot/
v2_community_bot.rs

1//! A bot that OWNS a Concord v2 community. On startup (with `VECTOR_CREATE=1`)
2//! it creates the community, prints a shareable invite link, optionally
3//! Direct-Invites an npub, then greets and echoes in its channels.
4//!
5//! Run:
6//! ```sh
7//! VECTOR_NSEC=nsec1... VECTOR_CREATE=1 cargo run -p vector-sdk --example v2_community_bot
8//! # optionally also: VECTOR_INVITE_NPUB=npub1...
9//! ```
10//!
11//! The community and its invites are on the modern protocol, byte-compatible
12//! with Soapbox/Armada — the exact same discord.js-style API as a v1 bot; the
13//! SDK routes to v2 under the hood.
14
15use vector_sdk::VectorBot;
16
17#[tokio::main]
18async fn main() -> vector_sdk::Result<()> {
19    let nsec = std::env::var("VECTOR_NSEC").expect("set VECTOR_NSEC to your bot's nsec");
20
21    let bot = VectorBot::builder().nsec(nsec).build().await?;
22    println!("v2 community bot online as {}", bot.npub());
23
24    // Create-and-invite is opt-in so a restart doesn't spawn a fresh community
25    // each time (a real bot persists its community id and reuses it).
26    if std::env::var("VECTOR_CREATE").is_ok() {
27        // Creation is one hop through the core facade (the ergonomic surface stays at
28        // the stable published API). A fresh community is created on the modern protocol.
29        let summary = bot.core().create_community_v2("Vector v2 Demo").await?;
30        let id = summary.get("community_id").and_then(|v| v.as_str()).unwrap_or_default().to_string();
31        let community = bot.community(id);
32        println!("created v2 community {}", community.id());
33
34        let url = community.create_invite().await?;
35        println!("shareable invite link: {url}");
36
37        if let Ok(guest) = std::env::var("VECTOR_INVITE_NPUB") {
38            community.invite(&guest).await?;
39            println!("direct-invited {guest}");
40        }
41    }
42
43    // One handler serves DMs and every Community channel — the SDK hides the
44    // transport (and the protocol) difference.
45    bot.on_message(|_bot, msg| async move {
46        if msg.is_mine() {
47            return; // never reply to our own messages (no echo loop)
48        }
49        let _ = msg.channel().typing().await;
50        let _ = msg.reply(&format!("v2 heard: {}", msg.text())).await;
51    })
52    .await?;
53
54    Ok(())
55}