### Spawn Bot Example Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Start the bot on its runtime and return a BotHandle for background control. This example shows how to spawn the bot and then wait for a shutdown signal. ```rust let handle = bot.spawn(); tokio::signal::ctrl_c().await?; handle.shutdown().await; ``` -------------------------------- ### Install and Run evcxr REPL Source: https://github.com/oxidezap/whatsapp-rust/blob/main/agent_docs/debugging.md Install the evcxr_repl tool using cargo binstall and run it from the project root for interactive debugging. ```bash cargo binstall evcxr_repl -y evcxr # run from project root ``` -------------------------------- ### Get User Info Example Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md Demonstrates how to retrieve detailed profile information for a specific user using their JID. Requires an active client connection. ```rust let info = client.contacts().get_user_info(&user_jid).await?; println!("Platform: {:?}", info.platform); println!("Status: {:?}", info.status); ``` -------------------------------- ### BotBuilder Example: Building a Bot with SqliteStore Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Demonstrates how to create a Bot instance by providing a SqliteStore as the backend using the BotBuilder. ```rust let bot = Bot::builder() .with_backend(SqliteStore::new("whatsapp.db").await?) .build() .await?; ``` -------------------------------- ### Run Bot Example Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Run the bot on the current task until it shuts down. This example shows how to build and run a bot with a message handler. ```rust #[tokio::main] async fn main() -> Result<()> { let bot = Bot::builder() .with_backend(SqliteStore::new("whatsapp.db").await?) .on_message(|ctx| async move { let _ = ctx.reply("Hello!").await; }) .build() .await?; bot.run().await; Ok(()) } ``` -------------------------------- ### Get Blocklist Example Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md Retrieves the current blocklist and iterates through each entry, printing the blocked JID and timestamp. Ensure the client is initialized. ```rust let blocklist = client.blocking().get_blocklist().await?; for entry in blocklist { println!("Blocked: {} at {}", entry.jid, entry.blocked_at); } ``` -------------------------------- ### Minimal Bot Configuration Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/configuration-errors.md Sets up a basic bot with a SQLite storage backend and a simple message handler. This is a good starting point for new bots. ```rust let bot = Bot::builder() .with_backend(SqliteStore::new("bot.db").await?) .on_message(|ctx| async move { println!("Got message from {}", ctx.info.source.sender); }) .build() .await?; bot.run().await; ``` -------------------------------- ### Custom Backend Implementation Example Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md Provides a template for implementing a custom storage backend by fulfilling the `Backend` trait. Ensure thread/async safety and handle serialization/encoding as per notes. ```rust #[async_trait] impl Backend for MyCustomStore { async fn get_device(&self) -> Result, StoreError> { // Query your database } async fn put_device(&self, device: &Device) -> Result<(), StoreError> { // Persist to your database } // ... implement all other trait methods ... } // Use with the bot let store = MyCustomStore::new()?; let bot = Bot::builder() .with_backend(store) .build() .await?; ``` -------------------------------- ### Upload and Send Media Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md This example demonstrates how to upload media files (like images) and then send them as messages. Ensure the media file exists and is readable. The `upload_media` function handles encryption and returns necessary metadata for constructing the message. ```rust let image_bytes = std::fs::read("photo.jpg").await?; let uploaded = client.upload_media( &image_bytes, UploadOptions { file_size: image_bytes.len() as u64, media_type: MediaType::Image, ..Default::default() } ).await?; let msg = wa::Message { image_message: Some(Box::new(wa::message::ImageMessage { url: Some(uploaded.url), file_length: Some(image_bytes.len() as u64), media_key: Some(uploaded.media_key.into()), mime_type: Some("image/jpeg".to_string()), sha256: Some(uploaded.file_sha256.into()), file_sha256: Some(uploaded.file_sha256.into()), ..Default::default() })), ..Default::default() }; client.send_message(&chat, msg).await?; ``` -------------------------------- ### Minimal whatsapp-rust Dependency Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md Example of how to configure the whatsapp-rust dependency in Cargo.toml with minimal features enabled. ```toml [dependencies] whatsapp-rust = { version = "0.6", default-features = false, features = ["tokio-runtime"] } ``` -------------------------------- ### Lookup Contacts and Presence Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md This example covers checking if a phone number is on WhatsApp, retrieving user information (like status and platform), subscribing to presence updates, setting your own presence status, and fetching profile pictures. It utilizes `client.contacts()` and `client.presence()` accessors. ```rust // Check if number is on WhatsApp let is_registered = client.contacts().is_on_whatsapp(&phone_jid).await?; // Get user info let info = client.contacts().get_user_info(&user_jid).await?; println!("Platform: {:?}", info.platform); println!("Status: {:?}", info.status); // Subscribe to presence updates client.presence().subscribe_presence(&user_jid).await?; // Set your presence client.presence().set_presence(PresenceStatus::Online).await?; // Get profile picture if let Some(pic) = client.contacts().get_profile_picture(&jid, true).await? { println!("Picture URL: {}", pic.url); } ``` -------------------------------- ### Implementing a Custom Storage Backend Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md Implement the `Backend` trait to provide a custom storage solution, such as persisting data to PostgreSQL. This involves defining methods for getting and putting device information. ```rust #[async_trait] impl Backend for MyPostgresStore { async fn get_device(&self) -> Result, StoreError> { // Query PostgreSQL } async fn put_device(&self, device: &Device) -> Result<(), StoreError> { // Persist to PostgreSQL } // ... implement all other methods ... } let store = MyPostgresStore::new(connection_pool)?; let bot = Bot::builder() .with_backend(store) .build() .await?; ``` -------------------------------- ### Query Group Info Example Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md Queries and retrieves metadata for a specific group. Results are cached and returned as an Arc-wrapped GroupInfo object. Ensure the JID is correctly formatted. ```rust let group_info = client.groups().query_info(&group_jid).await?; println!("Group: {}", group_info.subject); println!("Participants: {}", group_info.participants.len()); ``` -------------------------------- ### Enable Metrics Support Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/configuration-errors.md Add the 'metrics' feature to your Cargo.toml and install a metrics recorder, such as Prometheus, to emit counters and histograms. This allows for monitoring application performance. ```toml whatsapp-rust = { version = "0.6", features = ["metrics"] } ``` ```rust use metrics_exporter_prometheus::formatting::PrometheusBuilder; PrometheusBuilder::new() .install_recorder() .unwrap(); ``` -------------------------------- ### Nibble Encoding Examples Source: https://github.com/oxidezap/whatsapp-rust/blob/main/agent_docs/debugging.md Illustrates the expected input and output for nibble encoding, a method used for numeric strings in WhatsApp's binary protocol. Refer to `wacore/binary/src/nibble.rs` for the implementation. ```rust // Decode: "100000000000001f" -> "100000000000001" // Encode: "100000000000001" -> "100000000000001f" ``` -------------------------------- ### Enable Tracing Support Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/configuration-errors.md Add the 'tracing' feature to your Cargo.toml and install a tracing subscriber to emit structured logs. The subscriber can be configured using environment variables. ```toml whatsapp-rust = { version = "0.6", features = ["tracing"] } ``` ```rust use tracing_subscriber::filter::EnvFilter; tracing_subscriber::fmt() .with_env_filter(EnvFilter::from_default_env()) .init(); ``` -------------------------------- ### Shutdown BotHandle Example Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Gracefully stop the bot by calling the shutdown method on the BotHandle. This disconnects, flushes state, and waits for the run loop to exit. ```rust let handle = bot.spawn(); // ... later ... handle.shutdown().await; ``` -------------------------------- ### Build and Launch Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Finalize configuration and construct the Bot instance. ```APIDOC ## async fn build(self) -> Result ### Description Finalize configuration and construct the `Bot`. Only available when all required fields are `Provided`. ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Returns - `Result` ### Errors - `BotBuilderError::Store` — device store initialization failed ### Example ```rust let bot = Bot::builder() .with_backend(SqliteStore::new("whatsapp.db").await?) .build() .await?; ``` ``` -------------------------------- ### Build and Verify Project Source: https://github.com/oxidezap/whatsapp-rust/blob/main/AGENTS.md Commands to format, lint, test, and run end-to-end tests for the project. Ensure the mock server is running for e2e tests. ```bash cargo fmt --all cargo clippy --all --tests cargo test --all cargo test -p e2e-tests # requires mock server running ``` -------------------------------- ### Get Blocklist Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md Retrieve the current list of blocked users. ```APIDOC ## get_blocklist ### Description Get the current blocklist. ### Method `async fn get_blocklist(&self) -> Result, BlockingError>` ### Response #### Success Response (200) - **blocklist** (`Vec`) - A list of blocked users, each with their JID and the timestamp they were blocked. #### Response Example ```json { "blocklist": [ { "jid": "user@example.com", "blocked_at": 1678886400 } ] } ``` #### Error Response - `BlockingError` - Possible errors include IQ errors, invalid requests, or internal errors. ### Example ```rust let blocklist = client.blocking().get_blocklist().await?; for entry in blocklist { println!("Blocked: {} at {}", entry.jid, entry.blocked_at); } ``` ``` -------------------------------- ### Initialize and Run Bot with Tokio in Rust Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md Demonstrates setting up the bot with a persistence backend and running it within the Tokio async runtime. The `bot.run()` method blocks until the bot disconnects. ```rust #[tokio::main] async fn main() { let bot = Bot::builder() .with_backend(store) .build() .await?; bot.run().await; // Blocks until disconnect } ``` -------------------------------- ### Get Status Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md Retrieves the client's current status text. ```APIDOC ## get_status ### Description Get the client's status text. ### Method `async fn get_status(&self) -> Result, ProfileError>` ### Response #### Success Response - `Option` - The current status text, or None if no status is set. ``` -------------------------------- ### Get Invite Link Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md Retrieves the current invite link for a given group. ```APIDOC ## get_invite_link ### Description Get the group's invite link. ### Method ```rust async fn get_invite_link(&self, jid: &Jid) -> Result ``` ### Parameters #### Path Parameters - **jid** (`&Jid`) - Required - Group JID ### Returns - `Result` - full invite URL ``` -------------------------------- ### Initialize SQLite Store and Bot Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md Initializes the SQLite storage backend and the Bot with the configured store. Requires an async context. ```rust use whatsapp_rust::store::SqliteStore; let store = SqliteStore::new("whatsapp.db").await?; let bot = Bot::builder() .with_backend(store) .build() .await?; ``` -------------------------------- ### message_key Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Gets the referential `MessageKey` for reactions, omitting the participant for 1-on-1 chats. ```APIDOC ## fn message_key(&self) -> wa::MessageKey ### Description Get the referential `MessageKey` for reactions. Omits participant for 1-on-1 chats. ### Parameters * None ### Returns * **wa::MessageKey** - The message key for reactions. ``` -------------------------------- ### Get Membership Requests Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md Retrieves a list of pending join requests for approval groups. ```APIDOC ## get_membership_requests ### Description Get pending join requests (approval groups only). ### Method ```rust async fn get_membership_requests(&self, jid: &Jid) -> Result, GroupError> ``` ### Parameters #### Path Parameters - **jid** (`&Jid`) - Required - Group JID ### Returns - `Result, GroupError>` ``` -------------------------------- ### Get User Info Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md Retrieves detailed profile information for a given user JID. ```APIDOC ## get_user_info ### Description Get detailed profile information for a user. ### Method `async fn get_user_info(&self, jid: &Jid) -> Result` ### Parameters #### Path Parameters - **jid** (`&Jid`) - Required - User JID or phone number JID ### Response #### Success Response (UserInfo) - **jid** (`Jid`) - User JID (@s.whatsapp.net) - **phone_number** (`Option`) - Phone number JID (PN addressing) - **platform** (`Option`) - "android", "iphone", "web", etc. - **exists_on_whatsapp** (`bool`) - Whether the number is registered - **status** (`Option`) - User bio/status text - **status_timestamp** (`Option`) - When status was set (Unix seconds) - **verified_name** (`Option`) - Verified business name - **business_profile** (`Option`) - Business account information ### Request Example ```rust let info = client.contacts().get_user_info(&user_jid).await?; println!("Platform: {:?}", info.platform); println!("Status: {:?}", info.status); ``` ``` -------------------------------- ### Run Included Demo Bot Source: https://github.com/oxidezap/whatsapp-rust/blob/main/README.md These bash commands show how to run the included demo bot from the command line with different options for pairing. ```bash cargo run --example demo # QR code only ``` ```bash cargo run --example demo -- -p 15551234567 # Pair code + QR code ``` ```bash cargo run --example demo -- -p 15551234567 -c MYCODE # Custom pair code ``` -------------------------------- ### Simplified IQ Execution Source: https://github.com/oxidezap/whatsapp-rust/blob/main/agent_docs/protocol_architecture.md Shows how to use `Client::execute()` for a single-call IQ request and response handling, replacing manual build, send, and parse steps. ```rust // Single call replaces manual build + send + parse let response = client.execute(GroupQueryIq::new(&jid)).await?; ``` -------------------------------- ### Get Invite Info Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md Retrieves group metadata using an invite code without joining the group. ```APIDOC ## get_invite_info ### Description Get group info from an invite code (without joining). ### Method ```rust async fn get_invite_info(&self, invite_code: &str) -> Result ``` ### Parameters #### Path Parameters - **invite_code** (`&str`) - Required - Invite code ### Returns - `Result` - group metadata ``` -------------------------------- ### Get Profile Picture Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md Retrieves a user's profile picture, with an option to request the highest quality. ```APIDOC ## get_profile_picture ### Description Get a user's profile picture. ### Method `async fn get_profile_picture(&self, jid: &Jid, highest_quality: bool) -> Result, ContactError>` ### Parameters #### Path Parameters - **jid** (`&Jid`) - Required - User JID - **highest_quality** (`bool`) - Required - Request highest resolution ### Response #### Success Response (Option) - The profile picture URL and ID, or None if no picture is available. #### Response Example `Option` ``` -------------------------------- ### Get Identity Key Pair Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md Retrieves the long-lived identity key pair used for signing pre-keys. ```rust let ikp = backend.get_identity_key_pair().await?; ``` -------------------------------- ### Initialize SQLite Store with Custom Path Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md Initializes the SQLite storage backend using a custom file path for the database. ```rust let store = SqliteStore::new("/path/to/custom/location.db").await?; ``` -------------------------------- ### Initialize SQLite Persistence Store in Rust Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md Demonstrates how to initialize the `SqliteStore` for persisting WhatsApp data, such as Signal sessions and group metadata. The database schema is automatically created on the first run. ```rust let store = SqliteStore::new("whatsapp.db").await?; ``` -------------------------------- ### Get Profile Pictures Batch Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md Retrieves profile pictures for multiple users in a batch, with an option for highest quality. ```APIDOC ## get_profile_pictures_batch ### Description Get profile pictures for multiple users. ### Method `async fn get_profile_pictures_batch(&self, jids: Vec, highest_quality: bool) -> Result)>, ContactError>` ### Parameters #### Path Parameters - **jids** (`Vec`) - Required - User JIDs - **highest_quality** (`bool`) - Required - Request highest resolution ### Response #### Success Response (Vec<(Jid, Option)`) - A vector of tuples, where each tuple contains a user JID and their profile picture information (or None). #### Response Example `Vec<(Jid, Option)>` ``` -------------------------------- ### Get Signed Pre-Key Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md Retrieves the signed pre-key and its identifier. This special pre-key is renewed periodically for signature verification. ```rust let (spk_id, spk_bytes) = backend.get_signed_pre_key().await?; ``` -------------------------------- ### Bot with Custom Transport and HTTP Client Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/configuration-errors.md Illustrates how to integrate custom implementations for transport, HTTP client, and the async runtime. Replace `MyCustomTransport`, `MyHttpClient`, and `MyCustomRuntime` with your specific types. ```rust let bot = Bot::builder() .with_backend(SqliteStore::new("bot.db").await?) .with_transport_factory(MyCustomTransport) .with_http_client(MyHttpClient) .with_runtime(MyCustomRuntime) .build() .await?; ``` -------------------------------- ### Bot::builder() Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Creates a new BotBuilder with default transport, HTTP client, and runtime. The storage backend is always required and must be provided explicitly. ```APIDOC ## Bot::builder() ### Description Creates a new builder with default transport (Tokio WebSocket), HTTP client (ureq), and runtime (Tokio) if their features are enabled. The storage backend is always required and must be provided explicitly. ### Returns `BotBuilder` - A new builder instance. ### Example ```rust let bot = Bot::builder() .with_backend(SqliteStore::new("whatsapp.db").await?) .build() .await?; ``` ``` -------------------------------- ### Get Participating Groups Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md Retrieves a list of JIDs for all groups the client is currently a member of. This is useful for iterating through accessible groups. ```rust let participating_groups = client.groups().participating_groups().await?; ``` -------------------------------- ### Basic Bot Implementation with QR Code Source: https://github.com/oxidezap/whatsapp-rust/blob/main/README.md This Rust code sets up a basic WhatsApp bot using the whatsapp-rust library. It configures a SQLite store, provides a callback for QR code generation, and handles incoming messages to reply 'pong' to 'ping'. The bot runs until explicitly logged out or shut down. ```rust use whatsapp_rust::prelude::*; #[tokio::main] async fn main() -> Result<(), Box> { let bot = Bot::builder() .with_backend(SqliteStore::new("whatsapp.db").await?) .on_qr_code(|code, _timeout| async move { println!("Scan to pair:\n{code}"); }) .on_message(|ctx| async move { if ctx.message.text_content() == Some("ping") { let _ = ctx.reply("pong").await; } }) .build() .await?; // Runs until logout or shutdown; a single await. bot.run().await; Ok(()) } ``` -------------------------------- ### Get Group Profile Picture Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md Retrieves the group's profile picture. You can specify whether to request the highest quality available. ```APIDOC ## get_profile_picture ### Description Get the group's profile picture. ### Method `async fn get_profile_picture(&self, jid: &Jid, highest_quality: bool) -> Result, GroupError>` ### Parameters #### Path Parameters - **jid** (`&Jid`) - Required - Group JID - **highest_quality** (`bool`) - Required - Request highest resolution ### Returns - **Result, GroupError>** — picture URL and ID ``` -------------------------------- ### Build WhatsApp Messages Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/types-reference.md Shows how to construct various types of WhatsApp messages, including text, images, and replies with context. ```rust use wacore::proto_helpers::MessageBuilderExt; let msg = wa::Message::text("Hello"); let msg = wa::Message::image( "https://...".to_string(), vec![/* 32-byte media key */], vec![/* SHA256 hash */], 12345, // file size ); let quoted_msg = wa::Message::text_with_context( "Reply text", wa::ContextInfo { stanza_id: Some("original_msg_id".to_string()), participant: Some(original_sender.to_string()), ..Default::default() } ); ``` -------------------------------- ### Get Group Metadata from Backend Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md Retrieves group metadata from the backend and deserializes it from JSON. Ensure the backend implementation supports this operation. ```rust let metadata: GroupInfo = serde_json::from_slice( &backend.get_group_metadata("group@g.us").await? )?; ``` -------------------------------- ### Build a Simple Bot with Message Reply Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md Use this snippet to create a basic bot that responds to messages. It requires setting up a storage backend and defining a message handler. The bot will reply 'pong' if it receives the message 'ping'. ```rust use whatsapp_rust::prelude::*; #[tokio::main] async fn main() -> Result<()> { let bot = Bot::builder() .with_backend(SqliteStore::new("bot.db").await?) .on_message(|ctx| async move { if ctx.message.text_content() == Some("ping") { let _ = ctx.reply("pong").await; } }) .build() .await?; bot.run().await; Ok(()) } ``` -------------------------------- ### Handle SendMessage Errors with Match Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/types-reference.md Provides a comprehensive example of using a match statement to handle various potential errors when sending a message. ```rust match client.send_message(&chat, msg).await { Ok(result) => { println!("Sent: {}", result.message_id); } Err(SendError::NotLoggedIn) => { eprintln!("Not logged in, pairing required"); } Err(SendError::Client(ClientError::NotConnected)) => { eprintln!("No connection, retrying..."); } Err(SendError::Iq(IqError::Timeout)) => { eprintln!("Server timeout, message lost"); } Err(SendError::InvalidRequest(msg)) => { eprintln!("Invalid: {}", msg); } Err(e) => { eprintln!("Unknown error: {}", e); } } ``` -------------------------------- ### Get Message Key for Reactions Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Retrieves the `MessageKey` for the incoming message, which is used for operations like reactions. It omits the participant for 1-on-1 chats. ```rust fn message_key(&self) -> wa::MessageKey ``` -------------------------------- ### Configuration Methods Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Methods to configure the bot's behavior, including cache, rate limits, and device properties. ```APIDOC ## with_cache_config(config: CacheConfig) -> Self ### Description Configure in-memory cache behavior (TTLs, capacity bounds, secret retention). ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Parameters - **config** (`CacheConfig`) - Required - Cache configuration object ### Returns - `Self` ``` ```APIDOC ## with_wanted_pre_key_count(count: usize) -> Self ### Description Set the target Signal pre-key count to maintain (default 20). ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Parameters - **count** (`usize`) - Required - Target Signal pre-key count ### Returns - `Self` ``` ```APIDOC ## with_resend_rate_limit(max_resends: u32, window_secs: u32) -> Self ### Description Limit outbound resends per chat to prevent flooding on network recovery. ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Parameters - **max_resends** (`u32`) - Required - Maximum number of resends allowed - **window_secs** (`u32`) - Required - Time window in seconds for rate limiting ### Returns - `Self` ``` ```APIDOC ## with_pair_code(options: PairCodeOptions) -> Self ### Description Enable pair-code linking instead of QR-only pairing. ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Parameters - **options** (`PairCodeOptions`) - Required - Options for pair-code linking ### Returns - `Self` ``` ```APIDOC ## with_device_props_override(props: DevicePropsOverride) -> Self ### Description Override device properties like model, manufacturer, and OS version reported to the server. ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Parameters - **props** (`DevicePropsOverride`) - Required - Overridden device properties ### Returns - `Self` ``` ```APIDOC ## skip_history_sync() -> Self ### Description Skip history sync on connection (useful for bots that don't need chat backlog). ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Returns - `Self` ``` ```APIDOC ## with_initial_push_name(name: String) -> Self ### Description Set the initial push name (display name) sent to the server on first connection. ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Parameters - **name** (`String`) - Required - Initial push name ### Returns - `Self` ``` -------------------------------- ### Spawn Bot in Background with Tokio in Rust Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md Shows how to spawn the bot to run in the background, allowing the main thread to continue. Includes handling graceful shutdown using Tokio signals. ```rust let handle = bot.spawn(); // Returns immediately, bot runs on runtime tokio::signal::ctrl_c().await?; handle.shutdown().await; // Graceful shutdown ``` -------------------------------- ### HttpClient Trait Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/types-reference.md Abstraction for HTTP clients, providing methods for making GET and POST requests, essential for media upload and download operations. ```APIDOC ## HttpClient Trait ### Description Provides an abstraction for HTTP clients, used for operations like media upload and download. ### Methods - **get(url: &str)**: Performs an HTTP GET request to the specified URL. - **post(url: &str, body: Vec)**: Performs an HTTP POST request to the specified URL with the given request body. ### Implementations - `UreqHttpClient`: An implementation using the `ureq` library, with blocking I/O handled via `tokio::spawn_blocking`. ``` -------------------------------- ### IqNamespace Enum Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/types-reference.md Defines the different types of IQ (Information Query) namespaces used for XMPP communication, such as get, set, result, and error. ```APIDOC ## IqNamespace Enum ### Description Represents the different types of IQ (Information Query) requests in XMPP communication. ### Enum Variants - **Get**: Represents an IQ request to retrieve information. - **Set**: Represents an IQ request to set information. - **Result**: Represents the result of an IQ request. - **Error**: Represents an error response to an IQ request. ``` -------------------------------- ### create Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md Creates a new group with the specified options, including name, participants, and description. ```APIDOC ## create ### Description Create a new group. ### Method POST ### Endpoint /groups ### Parameters #### Request Body - **subject** (string) - Required - The name of the group. - **participants** (array of Jid) - Required - Initial participants for the group. - **description** (string) - Optional - A description for the group. ### Response #### Success Response (200) - **metadata** (CreateGroupResult) - Metadata of the created group, including its ID. ### Errors - `GroupError::InvalidRequest` — invalid options (empty name, duplicate participants) - `GroupError::Iq` — server rejected creation ``` -------------------------------- ### HTTP Client Trait Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/types-reference.md Abstract trait for HTTP clients, defining methods for GET and POST requests. Used for media upload/download operations. ```rust #[async_trait] pub trait HttpClient: Send + Sync { async fn get(&self, url: &str) -> Result; async fn post(&self, url: &str, body: Vec) -> Result; } ``` -------------------------------- ### Get Device Snapshot Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md Retrieves a cached snapshot of the device state. Snapshots are refcount-efficient (Arc) and safe to clone across tasks. ```rust let snapshot = client.get_device_snapshot().await; let jid = &snapshot.jid; ``` -------------------------------- ### UploadOptions Struct for Media Uploads Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/media-upload-download.md Defines the configuration options for uploading media files. Specify file size, media type, and optionally filename or a custom thumbnail. ```rust pub struct UploadOptions { pub file_size: u64, pub media_type: MediaType, pub file_name: Option, pub thumbnail: Option>, pub generate_missing_thumbnail: bool, } ``` -------------------------------- ### Bot::builder() Constructor Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Creates a new BotBuilder instance with default configurations for transport, HTTP client, and runtime. The storage backend must always be explicitly provided. ```rust pub fn builder() -> BotBuilder ``` -------------------------------- ### Bot Methods Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Provides access to the underlying client and methods to run or spawn the bot. ```APIDOC ## Bot The main client entry point after configuration. ```rust pub struct Bot { client: Arc, // ... internal fields } ``` ### Methods #### `fn client(&self) -> Arc` Access the underlying `Client` for direct API calls (messaging, contacts, groups, etc.). #### `async fn run(self)` Run the bot on the current task until it shuts down (logout or `Client::disconnect()` from another task). **Example:** ```rust #[tokio::main] async fn main() -> Result<()> { let bot = Bot::builder() .with_backend(SqliteStore::new("whatsapp.db").await?) .on_message(|ctx| async move { let _ = ctx.reply("Hello!").await; }) .build() .await?; bot.run().await; Ok(()) } ``` #### `fn spawn(self) -> BotHandle` Start the bot on its runtime and return a `BotHandle` for background control. **Returns:** `BotHandle` — handle for awaiting, graceful shutdown, or abort **Example:** ```rust let handle = bot.spawn(); tokio::signal::ctrl_c().await?; handle.shutdown().await; ``` ``` -------------------------------- ### Check if User is on WhatsApp Example Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md Shows how to check if a given phone number is registered on WhatsApp. This is useful for verifying user existence before sending messages. ```rust if client.contacts().is_on_whatsapp(&phone_jid).await? { println!("User is on WhatsApp!"); } ``` -------------------------------- ### Project Structure Overview Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md This is a visual representation of the whatsapp-rust project's directory structure, outlining the location of key modules and components. ```text whatsapp-rust/ ├── src/ │ ├── bot.rs # BotBuilder, Bot, MessageContext │ ├── client.rs # Client core and lifecycle │ ├── client/ │ │ ├── messaging.rs # send_message, reactions, edits │ │ ├── sessions.rs # Signal protocol session management │ │ ├── device_registry.rs # Device list caching │ │ └── ... │ ├── features/ │ │ ├── groups.rs # Groups API │ │ ├── contacts.rs # Contacts API │ │ ├── presence.rs # Presence API │ │ ├── profile.rs # Profile API │ │ ├── blocking.rs # Blocking API │ │ └── ... │ ├── upload.rs # Media upload │ ├── download.rs # Media download │ ├── store/ # Backend trait and persistence │ ├── types/ │ │ └── events.rs # Event types │ └── ... ├── wacore/ # Platform-agnostic core │ ├── binary/ # WABinary protocol │ ├── libsignal/ # Signal Protocol │ ├── appstate/ # App state sync │ └── ... ├── waproto/ # Protocol Buffers definitions ├── storages/sqlite-storage/ # SQLite Backend ├── transports/tokio-transport/ # WebSocket transport ├── http_clients/ureq-client/ # HTTP client └── tests/ ├── e2e/ # End-to-end tests └── bench-integration/ # Benchmarks ``` -------------------------------- ### Create and Parse JIDs in Rust Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md Demonstrates how to create JIDs for users, groups, and newsletters, and how to parse them from strings. Ensure JID strings are correctly formatted. ```rust let user_jid = Jid::user("1234567890"); // @s.whatsapp.net let group_jid = Jid::group("120363xyz"); // @g.us let newsletter_jid = Jid::newsletter("123456@newsletter"); // Parse from string let jid: Jid = "1234567890@s.whatsapp.net".parse()?; ``` -------------------------------- ### BotBuilder::with_runtime Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Overrides the default async runtime implementation. ```APIDOC ## BotBuilder::with_runtime ### Description Overrides the async runtime implementation. Replaces the Tokio default. ### Parameters #### Path Parameters - **runtime** (impl Runtime + 'static) - Required - Async runtime for spawning tasks ### Returns `BotBuilder` - Builder with Runtime marked as Provided. ``` -------------------------------- ### Handling PresenceChange Events Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/events-lifecycle.md Example of an event handler for PresenceChange events. It filters for the specific event kind and prints the user's JID and new status. ```rust .on_event_for(&[EventKind::PresenceChange], |event, _| async move { if let Event::PresenceChange(pce) = &*event { println!("{} is now {:?}", pce.jid, pce.status); } }) ``` -------------------------------- ### Construct and Use MessageKey in Rust Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/INDEX.md Illustrates how to create a `MessageKey` for identifying messages, used for actions like sending reactions or quoting. Ensure `remote_jid`, `id`, and `participant` (for groups) are correctly set. ```rust let key = wa::MessageKey { remote_jid: Some(chat.to_string()), from_me: Some(false), id: Some("message_id_123".to_string()), participant: Some(sender.to_string()), // groups only }; // React client.send_reaction(&chat, key, "👍").await?; // Quote let quoted = wa::Message::text_with_context( "Reply", wa::ContextInfo { stanza_id: Some(key.id.clone()), ..Default::default() } ); ``` -------------------------------- ### Get Client's Status Text Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md Retrieves the client's current status text. Returns an Option which may be None if no status is set. ```rust client.profile().get_status().await?; ``` -------------------------------- ### Registering Custom Event Handlers Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/events-lifecycle.md Demonstrates how to integrate custom event handlers by implementing the `EventHandler` trait and registering them with the bot. ```APIDOC ## Integrating with Custom Event Handlers ### Description This section shows how to create and register custom event handlers to process specific events from the WhatsApp client. ### Handler Implementation Implement the `EventHandler` trait, defining `handle_event` for processing events and `interest` to specify which events to subscribe to. ```rust use whatsapp_rust::types::events::{Event, EventHandler, EventInterest, EventKind}; use std::sync::Arc; struct MyHandler; impl EventHandler for MyHandler { fn handle_event(&self, event: Arc) { match &*event { Event::Message(msg, info) => { println!("Got message: {:?}", info.id); } _ => {} } } fn interest(&self) -> EventInterest { EventInterest::of(&[EventKind::Message]) } } ``` ### Registration Register the custom handler using `register_raw_handler` during bot configuration. ```rust // Register bot = Bot::builder() // ... other config ... .register_raw_handler(Arc::new(MyHandler)) .build() .await?; ``` ``` -------------------------------- ### Thread-Safe Client Sharing Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/configuration-errors.md Demonstrates how to safely clone and use the `Client` across multiple Tokio tasks. The `Client` is `Send + Sync`, allowing it to be shared. ```rust let bot = bot.spawn(); let client = bot.client(); // Safe to clone and use across tasks: let client2 = client.clone(); tokio::spawn(async move { let _ = client2.send_text(&jid, "hello").await; }); // Main task can also send: let _ = client.send_text(&jid, "hi").await; ``` -------------------------------- ### Handshake Log Messages Source: https://github.com/oxidezap/whatsapp-rust/blob/main/agent_docs/protocol_architecture.md Examples of log output during the Noise handshake process, including full handshakes, resumption attempts, and fallback scenarios. Useful for debugging connection issues. ```text [socket] doFullHandshake: openChatSocket send hello [socket] resumeNoiseHandshake started [socket] resumeNoiseHandshake send hello [socket] resumeNoiseHandshake rcv hello [socket] resumeNoiseHandshake deriving secrets [socket] resumeNoiseHandshake failed: serverStaticCiphertext not null — doFallbackHandshake continuing handshake with given server hello [socket] continueFullHandshakeCore client finish and deriving secrets ``` -------------------------------- ### BotBuilder: with_backend Method Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Sets the storage backend implementation for the BotBuilder. This is a required field when default features are enabled. ```rust pub fn with_backend(backend: impl Backend + 'static) -> BotBuilder ``` -------------------------------- ### CreateGroupOptions Structure Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/groups-api.md Defines the configuration options available when creating a new group. Includes subject, participants, and optional description or ephemeral settings. ```rust pub struct CreateGroupOptions { pub subject: String, pub participants: Vec, pub description: Option, pub ephemeral_expiration: Option, // ... other options } ``` -------------------------------- ### ProtocolNode Trait Definition Source: https://github.com/oxidezap/whatsapp-rust/blob/main/agent_docs/protocol_architecture.md Defines the interface for mapping Rust structs to WhatsApp protocol nodes, including methods for getting the tag, converting to a Node, and attempting conversion from a Node. ```rust pub trait ProtocolNode: Sized { fn tag(&self) -> &'static str; fn into_node(self) -> Node; fn try_from_node(node: &Node) -> Result; } ``` -------------------------------- ### Handle PairingQrCode Event Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/events-lifecycle.md Use this handler to display the QR code and its timeout for pairing. ```rust .on_qr_code(|code, timeout| async move { println!("Scan within {:?}: {}", timeout, code); }) ``` -------------------------------- ### Register Message Handler Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Register a handler specifically for message events, providing a convenient `MessageContext` for easier message processing and replies. Example shows replying 'pong' to a 'ping' message. ```rust .on_message(|ctx| async move { if ctx.message.text_content() == Some("ping") { let _ = ctx.reply("pong").await; } }) ``` -------------------------------- ### Customizing Cache Configuration with Builder Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/configuration-errors.md Demonstrates how to override default cache settings using the `Bot::builder()` pattern. This allows for fine-tuning cache behavior for specific needs, such as increasing group cache capacity or altering TTLs. ```Rust let bot = Bot::builder() .with_cache_config(CacheConfig { group_cache_capacity: 5000, // Cache up to 5000 groups lid_pn_cache_ttl: Duration::from_secs(3600 * 48), // 48 hour TTL msg_secret_policy: MsgSecretPolicy::Discard, ..Default::default() }) .build() .await?; ``` -------------------------------- ### Get User Presence Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/contacts-presence-api.md Retrieves a user's current presence information. It takes a user's JID as input and returns an Option containing Presence information or None if the user's presence is unavailable. ```rust client.presence().get_user_presence(&user_jid).await?; ``` -------------------------------- ### BotBuilder::with_backend Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Sets the storage backend implementation, which is required for persisting data. ```APIDOC ## BotBuilder::with_backend ### Description Sets the storage backend implementation. This is the only required field when default features are enabled. ### Parameters #### Path Parameters - **backend** (impl Backend + 'static) - Required - Storage backend for persisting device state, sessions, and app state ### Returns `BotBuilder` - Builder with Backend marked as Provided. ``` -------------------------------- ### download_media_with_progress Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/media-upload-download.md Downloads media from a URL with progress tracking. It accepts the media URL, media key, encryption type, and a callback function to report download progress. ```APIDOC ## download_media_with_progress ### Description Download with progress tracking. ### Method `async fn` ### Parameters #### Path Parameters - **url** (`&str`) - Required - Media URL - **media_key** (`&[u8]`) - Required - Media encryption key - **enc_type** (`&str`) - Required - Encryption type - **progress_callback** (`F: Fn(DownloadProgress)`) - Required - Called as download progresses ### Response #### Success Response - **Result, MediaError>** ``` -------------------------------- ### Upload Sticker Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/media-upload-download.md Uploads a sticker file and sends it as a WhatsApp message. Ensure the sticker file is in webp format and specify the correct MIME type. ```rust let sticker_bytes = std::fs::read("sticker.webp").await?; let uploaded = client.upload_media( &sticker_bytes, UploadOptions { file_size: sticker_bytes.len() as u64, media_type: MediaType::Sticker, ..Default::default() } ).await?; let sticker_msg = wa::Message { sticker_message: Some(Box::new(wa::message::StickerMessage { url: Some(uploaded.url), file_length: Some(sticker_bytes.len() as u64), media_key: Some(uploaded.media_key.into()), mime_type: Some("image/webp".to_string()), sha256: Some(uploaded.file_sha256.into()), file_sha256: Some(uploaded.file_sha256.into()), ..Default::default() })), ..Default::default() }; client.send_message(&chat, sticker_msg).await?; ``` -------------------------------- ### Create Audio Message Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/media-upload-download.md Use this method to create an audio message. Requires URL, media key, file SHA256, file length, MIME type, audio length, and a boolean indicating if it's a voice message. ```rust let audio_msg = wa::Message::audio( url, media_key, file_sha256, file_length, Some(mime_type), audio_length_secs, false, // is_voicemessage ); ``` -------------------------------- ### BotBuilder: with_backend_arc Method Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Provides an alternative way to set the storage backend using an already shared Arc. ```rust pub fn with_backend_arc(backend: Arc) -> BotBuilder ``` -------------------------------- ### SQLite Performance Tuning PRAGMAs Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/storage-backend.md Configure SQLite cache size and memory-mapped I/O for high-throughput bots. Ensure writes are enabled by setting query_only to false. ```sql PRAGMA cache_size = 10000; -- 40 MB page cache PRAGMA mmap_size = 268435456; -- 256 MB memory-mapped I/O PRAGMA query_only = false; -- Enable writes ``` -------------------------------- ### Initializing Test Environment Source: https://github.com/oxidezap/whatsapp-rust/blob/main/agent_docs/e2e_testing.md Initialize logging for tests using `env_logger` to enable debug output. Ensure it's configured for test environments using `is_test(true)`. ```rust let _ = env_logger::builder().is_test(true).try_init(); ``` -------------------------------- ### BotBuilder::with_http_client Source: https://github.com/oxidezap/whatsapp-rust/blob/main/_autodocs/bot-api.md Overrides the default HTTP client used for media operations. ```APIDOC ## BotBuilder::with_http_client ### Description Overrides the HTTP client used for media uploads/downloads and version fetching. Replaces the ureq-client default. ### Parameters #### Path Parameters - **client** (impl HttpClient + 'static) - Required - HTTP client for media operations ### Returns `BotBuilder` - Builder with HttpClient marked as Provided. ```