pub struct BotBuilder<B = MissingBackend, T = MissingTransport, H = MissingHttpClient, R = MissingRuntime> { /* private fields */ }Expand description
Builder for Bot using the typestate pattern.
The four type parameters track whether the required fields (backend,
transport factory, HTTP client, runtime) have been provided: build() is
only available once all four are Provided, turning missing-field errors
into compile-time errors. With the default cargo features, transport, HTTP
client and runtime start Provided (Tokio WebSocket, ureq, Tokio), so
only the backend is required.
Implementations§
Source§impl<B, T, H, R> BotBuilder<B, T, H, R>
impl<B, T, H, R> BotBuilder<B, T, H, R>
Sourcepub fn with_backend(
self,
backend: impl Backend + 'static,
) -> BotBuilder<Provided, T, H, R>
pub fn with_backend( self, backend: impl Backend + 'static, ) -> BotBuilder<Provided, T, H, R>
Use a backend implementation for storage. This is the only required field when the default transport/HTTP/runtime features are enabled.
The backend is wrapped in an Arc internally; use
BotBuilder::with_backend_arc to pass an already-shared backend.
§Example
let bot = Bot::builder()
.with_backend(SqliteStore::new("whatsapp.db").await?)
.build()
.await?;Sourcepub fn with_backend_arc(
self,
backend: Arc<dyn Backend>,
) -> BotBuilder<Provided, T, H, R>
pub fn with_backend_arc( self, backend: Arc<dyn Backend>, ) -> BotBuilder<Provided, T, H, R>
BotBuilder::with_backend for an already-shared Arc<dyn Backend>.
Sourcepub fn with_transport_factory<F>(
self,
factory: F,
) -> BotBuilder<B, Provided, H, R>where
F: TransportFactory + 'static,
pub fn with_transport_factory<F>(
self,
factory: F,
) -> BotBuilder<B, Provided, H, R>where
F: TransportFactory + 'static,
Set the transport factory for creating network connections, replacing
the tokio-transport default when that feature is enabled.
Sourcepub fn with_http_client<C>(self, client: C) -> BotBuilder<B, T, Provided, R>where
C: HttpClient + 'static,
pub fn with_http_client<C>(self, client: C) -> BotBuilder<B, T, Provided, R>where
C: HttpClient + 'static,
Set the HTTP client used for media operations and version fetching,
replacing the ureq-client default when that feature is enabled.
Sourcepub fn with_runtime<Rt: Runtime>(
self,
runtime: Rt,
) -> BotBuilder<B, T, H, Provided>
pub fn with_runtime<Rt: Runtime>( self, runtime: Rt, ) -> BotBuilder<B, T, H, Provided>
Set the async runtime implementation, replacing the tokio-runtime
default when that feature is enabled.
Sourcepub fn with_task_instrument(self, instrument: Arc<dyn TaskInstrument>) -> Self
pub fn with_task_instrument(self, instrument: Arc<dyn TaskInstrument>) -> Self
Instrument the client’s internal tasks with a
TaskInstrument hook, called around
each poll (and around blocking work).
Runtime-agnostic: the hook wraps whatever runtime the client uses, so
every task spawned through the Runtime trait is covered, and
Bot::run meters the main run loop itself — the read loop reports
on either launch path (voip media tasks spawn directly on Tokio and
are not covered). Pass a
CpuMeter for per-session CPU accounting
(keep a clone to read snapshots), or a custom hook to scope
allocator-attribution or platform samplers to this client’s work.
Default: no hook — the runtime is used untouched.
Occupies the same single-instrument slot as
with_alloc_meter (last setter wins): calling
this after with_alloc_meter drops the typed alloc-meter handle, so
Client::resource_report’s alloc
field reverts to None.
§Example
use std::sync::Arc;
use wacore::stats::CpuMeter;
let cpu = Arc::new(CpuMeter::new());
let bot = Bot::builder()
.with_backend(backend)
.with_task_instrument(cpu.clone())
.build()
.await?;
// later: cpu.snapshot().busySourcepub fn with_alloc_meter(self, meter: Arc<AllocMeter>) -> Self
pub fn with_alloc_meter(self, meter: Arc<AllocMeter>) -> Self
Install an AllocMeter as this client’s
task instrument and keep a typed handle so Client::resource_report
folds in its allocation-churn snapshot.
Sugar over with_task_instrument: it
occupies the single instrument slot (so it’s mutually exclusive with a
CpuMeter or another hook — last setter wins). The host still installs a
#[global_allocator] that calls AllocMeter::on_alloc /
AllocMeter::on_dealloc; see examples/alloc_tracking.rs.
Sourcepub fn with_plugin<P: ClientPlugin>(self, plugin: P) -> Self
Available on crate feature plugins only.
pub fn with_plugin<P: ClientPlugin>(self, plugin: P) -> Self
plugins only.Register a native plugin without changing the builder’s typestate.
Sourcepub fn with_plugin_arc<P: ClientPlugin>(self, plugin: Arc<P>) -> Self
Available on crate feature plugins only.
pub fn with_plugin_arc<P: ClientPlugin>(self, plugin: Arc<P>) -> Self
plugins only.Register an already-shared native plugin without changing its marker type.
Sourcepub fn with_untyped_plugin<P: UntypedClientPlugin>(self, plugin: P) -> Self
Available on crate feature plugins only.
pub fn with_untyped_plugin<P: UntypedClientPlugin>(self, plugin: P) -> Self
plugins only.Register a manifest-ID-keyed plugin that exposes no Rust typed API.
Sourcepub fn with_untyped_plugin_arc<P: UntypedClientPlugin + ?Sized>(
self,
plugin: Arc<P>,
) -> Self
Available on crate feature plugins only.
pub fn with_untyped_plugin_arc<P: UntypedClientPlugin + ?Sized>( self, plugin: Arc<P>, ) -> Self
plugins only.Register an already-shared manifest-ID-keyed plugin.
Sourcepub fn with_plugin_host_config(self, config: PluginHostConfig) -> Self
Available on crate feature plugins only.
pub fn with_plugin_host_config(self, config: PluginHostConfig) -> Self
plugins only.Configure plugin lifecycle and tracked-task deadlines.
Sourcepub fn on_event<F, Fut>(self, handler: F) -> Self
pub fn on_event<F, Fut>(self, handler: F) -> Self
Register a handler that receives every event kind.
Sourcepub fn on_event_for<F, Fut>(self, kinds: &[EventKind], handler: F) -> Self
pub fn on_event_for<F, Fut>(self, kinds: &[EventKind], handler: F) -> Self
Register a handler that receives only the given event kinds. The bus skips materializing (and boxing the handler future for) every other kind, so a narrowly-scoped bot does not pay for events it ignores.
Sourcepub fn on_message<F, Fut>(self, handler: F) -> Self
pub fn on_message<F, Fut>(self, handler: F) -> Self
Run handler for every incoming message, with a ready
MessageContext (reply/react/edit helpers included).
Event::Messages batches (one per commit during an offline drain,
single-message on live traffic) are fanned out here in arrival order,
awaiting each handler before the next — per-message bots keep their
ergonomics and gain in-batch ordering.
The handler is CALLED for every message in the batch up front and the
returned futures then run in order (an async closure runs no body
code at call time, so for the typical handler this is unobservable).
Interleaving call+await instead would hold a MessageContext across
an await, which is not Send on wasm32.
Sourcepub fn on_qr_code<F, Fut>(self, handler: F) -> Self
pub fn on_qr_code<F, Fut>(self, handler: F) -> Self
Run handler with the QR payload (and validity window) each time a
pairing QR code is issued. Render code as a QR image for scanning.
Sourcepub fn on_pair_code<F, Fut>(self, handler: F) -> Self
pub fn on_pair_code<F, Fut>(self, handler: F) -> Self
Run handler with the 8-character pairing code (and validity window)
generated by BotBuilder::with_pair_code linking.
Sourcepub fn on_pair_code_error<F, Fut>(self, handler: F) -> Self
pub fn on_pair_code_error<F, Fut>(self, handler: F) -> Self
Run handler when a pair-code request fails, so no code will be issued
(Event::PairingCodeError).
The counterpart to BotBuilder::on_pair_code, and the only way to
observe the failure of a BotBuilder::with_pair_code request: that one
runs in a detached task, so its Err reaches no caller.
Branch on err.rejection rather than the message.
PairCodeRejection::is_throttled
is the case to slow down for — re-requesting on the original schedule
spends more of the budget the server just refused — and err.backoff
carries the server’s own delay when it named one.
Sourcepub fn on_pair_code_refresh<F, Fut>(self, handler: F) -> Self
pub fn on_pair_code_refresh<F, Fut>(self, handler: F) -> Self
Run handler when the server asks the companion to refresh an
in-progress pairing code (Event::PairingCodeRefresh). The bool is
force_manual. The typical reaction is to request a fresh code via
Client::pair_with_code with the same phone number.
Sourcepub fn on_connected<F, Fut>(self, handler: F) -> Self
pub fn on_connected<F, Fut>(self, handler: F) -> Self
Run handler once the client is connected and authenticated.
Sourcepub fn on_logged_out<F, Fut>(self, handler: F) -> Self
pub fn on_logged_out<F, Fut>(self, handler: F) -> Self
Run handler when the device is logged out (unlinked from the phone).
Sourcepub fn with_event_handler(self, handler: impl EventHandler + 'static) -> Self
pub fn with_event_handler(self, handler: impl EventHandler + 'static) -> Self
Register a struct-based EventHandler directly on the event bus.
Unlike the closure registrars, the handler keeps its state in &self
(no per-field clone dance) and handle_event runs inline on the
dispatch path: spawn your own task for slow work.
Sourcepub fn with_event_delivery(self, delivery: EventDelivery) -> Self
pub fn with_event_delivery(self, delivery: EventDelivery) -> Self
Choose how registered callbacks receive events. Defaults to
EventDelivery::Concurrent; use EventDelivery::Ordered for
in-arrival-order, bounded delivery. Only affects the closure-based
callbacks, not raw
with_event_handler handlers, which always
run inline on the dispatch path.
Sourcepub fn with_enc_handler<Eh>(
self,
enc_type: impl Into<String>,
handler: Eh,
) -> Selfwhere
Eh: EncHandler + 'static,
pub fn with_enc_handler<Eh>(
self,
enc_type: impl Into<String>,
handler: Eh,
) -> Selfwhere
Eh: EncHandler + 'static,
Register a custom handler for a specific encrypted message type
§Arguments
enc_type- The encrypted message type (e.g., “frskmsg”)handler- The handler implementation for this type
Sourcepub fn with_inbound_durability_hook<Dh>(self, hook: Dh) -> Selfwhere
Dh: InboundDurabilityHook + 'static,
pub fn with_inbound_durability_hook<Dh>(self, hook: Dh) -> Selfwhere
Dh: InboundDurabilityHook + 'static,
Register an inbound durability hook for at-least-once delivery.
By default the client acks a message as soon as it is decrypted
(at-most-once): a crash or failed commit before the consumer persists it
loses the message. With a hook registered, the ack is deferred until the
hook commits the message; on failure the message is redelivered on the
next connect. The hook must be idempotent (dedupe by (chat, sender, id),
since stanza ids are only unique within a chat/sender). See
InboundDurabilityHook for the full contract and caveats.
Sourcepub fn with_version(self, version: (u32, u32, u32)) -> Self
pub fn with_version(self, version: (u32, u32, u32)) -> Self
Override the WhatsApp version used by the client.
By default, the client will automatically fetch the latest version from WhatsApp’s servers. Use this method to force a specific version instead.
§Arguments
version- A tuple of (primary, secondary, tertiary) version numbers
Sourcepub fn with_device_props(self, override_: DevicePropsOverride) -> Self
pub fn with_device_props(self, override_: DevicePropsOverride) -> Self
Override the device properties sent to WhatsApp servers. This allows customizing how your device appears on the linked devices list.
platform_type controls the display name in Linked Devices; defaults
to Unknown (“Unknown device”). Only applied on the initial pairing.
§Example
use waproto::whatsapp::device_props::PlatformType;
use wacore::store::DevicePropsOverride;
Bot::builder()
.with_backend(backend)
.with_device_props(
DevicePropsOverride::new()
.with_os("macOS")
.with_platform_type(PlatformType::CHROME),
);Sourcepub fn with_pair_code(self, options: PairCodeOptions) -> Self
pub fn with_pair_code(self, options: PairCodeOptions) -> Self
Configure pair code authentication to run automatically after connecting.
When set, the pair code request will be sent automatically after establishing
a connection, and the pairing code will be dispatched via Event::PairingCode
(see BotBuilder::on_pair_code). This runs concurrently with QR code
pairing - whichever completes first wins.
The request runs in a detached task, so a failure cannot be returned to
the caller: it arrives as Event::PairingCodeError instead (see
BotBuilder::on_pair_code_error). Subscribe to it if the consumer must
distinguish “still waiting for the user” from “no code is coming” — a
rate-limited request is otherwise indistinguishable from the former.
§Example
use whatsapp_rust::pair_code::PairCodeOptions;
// Platform identity is derived from `DeviceProps` configured via
// `Bot::builder().with_device_props(...)`. Explicit overrides below
// are optional — omit them to let derivation do the right thing.
let bot = Bot::builder()
.with_backend(backend)
.with_pair_code(PairCodeOptions {
phone_number: "15551234567".to_string(),
custom_code: Some("ABCD1234".to_string()),
..Default::default()
})
.on_pair_code(|code, _timeout| async move {
println!("Enter this code on your phone: {code}");
})
.build()
.await?;Sourcepub fn skip_history_sync(self) -> Self
pub fn skip_history_sync(self) -> Self
Skip processing of history sync notifications from the phone.
When enabled, the client will acknowledge all incoming history sync notifications (so the phone considers them delivered) but will not download or process any historical data (INITIAL_BOOTSTRAP, RECENT, FULL, PUSH_NAME, etc.). A debug log entry is emitted for each skipped notification. This is useful for bot use cases where message history is not needed.
Default: false (history sync is processed normally).
Sourcepub fn with_wanted_pre_key_count(self, count: usize) -> Self
pub fn with_wanted_pre_key_count(self, count: usize) -> Self
Set how many one-time pre-keys are generated and uploaded per batch.
Defaults to WA Web’s UPLOAD_KEYS_COUNT (812). The value is clamped to the protocol-safe range at upload time. Useful for memory-constrained or embedded consumers that want a smaller batch.
Sourcepub fn with_resend_rate_limit(self, burst: u32, refill_per_min: u32) -> Self
pub fn with_resend_rate_limit(self, burst: u32, refill_per_min: u32) -> Self
Tune the per-chat outbound resend rate limiter.
Outbound retry resends to a chat are bounded by a token bucket: burst
is the instantaneous allowance, refill_per_min the sustained ceiling
per chat. This caps the aggregate resend rate WhatsApp’s anti-abuse
penalizes during a PN to LID migration fan-out, while throttled devices
still recover via the fresh-SKDM mark. A burst of 0 disables it.
Defaults are conservative (burst 20, refill 10/min) and apply without
calling this. Can also be retuned live via
Client::set_resend_rate_limit.
Sourcepub fn with_push_name(self, name: impl Into<String>) -> Self
pub fn with_push_name(self, name: impl Into<String>) -> Self
Set an initial push name on the device before connecting.
This is included in the ClientPayload during registration, allowing the
mock server to deterministically assign phone numbers based on push name
(same push name = same phone, enabling multi-device testing).
Sourcepub fn with_cache_config(self, config: CacheConfig) -> Self
pub fn with_cache_config(self, config: CacheConfig) -> Self
Configure cache TTL and capacity settings.
By default, all caches match WhatsApp Web behavior. Use this method to customize cache durations for your use case.
§Example
use whatsapp_rust::{CacheConfig, CacheEntryConfig};
// Disable TTL for group and device caches (good for bots with few groups)
let bot = Bot::builder()
.with_backend(backend)
.with_cache_config(CacheConfig {
group_cache: CacheEntryConfig::new(None, 1_000),
device_registry_cache: CacheEntryConfig::new(None, 5_000),
..Default::default()
})
.build()
.await?;Auto Trait Implementations§
impl<B = MissingBackend, T = MissingTransport, H = MissingHttpClient, R = MissingRuntime> !RefUnwindSafe for BotBuilder<B, T, H, R>
impl<B = MissingBackend, T = MissingTransport, H = MissingHttpClient, R = MissingRuntime> !UnwindSafe for BotBuilder<B, T, H, R>
impl<B, T, H, R> Freeze for BotBuilder<B, T, H, R>
impl<B, T, H, R> Send for BotBuilder<B, T, H, R>
impl<B, T, H, R> Sync for BotBuilder<B, T, H, R>
impl<B, T, H, R> Unpin for BotBuilder<B, T, H, R>
impl<B, T, H, R> UnsafeUnpin for BotBuilder<B, T, H, R>
Blanket Implementations§
Source§impl<T> AggregateExpressionMethods for T
impl<T> AggregateExpressionMethods for T
Source§fn aggregate_distinct(self) -> Self::Outputwhere
Self: DistinctDsl,
fn aggregate_distinct(self) -> Self::Outputwhere
Self: DistinctDsl,
DISTINCT modifier for aggregate functions Read moreSource§fn aggregate_all(self) -> Self::Outputwhere
Self: AllDsl,
fn aggregate_all(self) -> Self::Outputwhere
Self: AllDsl,
ALL modifier for aggregate functions Read moreSource§fn aggregate_filter<P>(self, f: P) -> Self::Output
fn aggregate_filter<P>(self, f: P) -> Self::Output
Source§fn aggregate_order<O>(self, o: O) -> Self::Outputwhere
Self: OrderAggregateDsl<O>,
fn aggregate_order<O>(self, o: O) -> Self::Outputwhere
Self: OrderAggregateDsl<O>,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> IntoSql for T
impl<T> IntoSql for T
Source§fn into_sql<T>(self) -> Self::Expression
fn into_sql<T>(self) -> Self::Expression
self to an expression for Diesel’s query builder. Read moreSource§fn as_sql<'a, T>(&'a self) -> <&'a Self as AsExpression<T>>::Expression
fn as_sql<'a, T>(&'a self) -> <&'a Self as AsExpression<T>>::Expression
&self to an expression for Diesel’s query builder. Read more