Rust quickstart
Prepare, install, connect, exchange the first messages, and clean up.
Use Rust 1.86+, Tokio, and crates.io 0.1.0 for online messaging in native applications. Browser/WASM targets are not supported.
1. Prepare
Your backend returns the current user's uid, short-lived token and websocketUrl. Protect registration and rotation as described in authentication and tokens. Clients must not call Product HTTP management endpoints directly.
Auth::new defaults to PC/Desktop 2. Wire values are APP 0, WEB 1, PC 2; register the token under the same device category. If your native host uses APP, set auth.device_flag = DeviceFlag::App and match the backend registration.
Auth::new generates a device_id retained across that client's reconnects. Set your own persistent device ID when identity must survive process restarts. Create a Client per identity; clone() shares its connection across Tokio tasks.
To see messages first, follow the official example with two clients. The steps below integrate the SDK into your application.
2. Install the SDK
Official repository: WuKongIM/WuKongEasySDK-Rust. Version 0.1.0 is available on crates.io, requiring Rust 1.86+ and Tokio. Install the exact version below:
[dependencies]
wukong-easy-sdk = "=0.1.0"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
serde_json = "1"The package name is wukong-easy-sdk; the Rust import name is wukong_easy_sdk. Commit your application's Cargo.lock to retain resolved dependencies. This implementation supports native TCP/TLS; WSS uses rustls and WebPKI roots. Browser/WASM is not supported.
3. Connect and listen
This complete program subscribes first, connects, sends one message to Bob and cleans up. Set the environment variables from your backend. Alice and Bob must have different UIDs, and Bob must already be online.
use serde_json::json;
use wukong_easy_sdk::{Auth, ChannelType, Client, Event, Options};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new(
std::env::var("WK_WS_URL")?,
Auth::new(std::env::var("WK_UID")?, std::env::var("WK_TOKEN")?),
Options::default(),
)?;
let mut events = client.subscribe();
let listener = tokio::spawn(async move {
loop {
match events.recv().await {
Ok(Event::Message(message)) => {
// Render/store message.payload in your UI; do not log its body.
let _ = &message.payload;
}
Ok(Event::CustomEvent(event)) => {
// Your application defines event.event_type and event.data.
let _ = (&event.event_type, &event.data);
}
Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => {
// Events were lost; reconcile through your application backend.
break;
}
Err(tokio::sync::broadcast::error::RecvError::Closed) => break,
_ => {}
}
}
});
let result = async {
client.connect().await?;
let ack = client.send(
"bob", ChannelType::Person,
json!({"type": 1, "content": "Hello, Rust 🦀"}),
).await?;
// ack is server acceptance, not Bob reading or processing the message.
let _ = ack;
Ok::<_, wukong_easy_sdk::Error>(())
}.await;
client.destroy().await;
listener.abort();
let _ = listener.await;
result?;
Ok(())
}A successful send returns SendResult, including string message_id, u64 message_seq and reason_code. Business errors return Error::Server { code }, preserving the numeric code. SENDACK does not imply receipt, display or application completion; see messaging.
4. Exchange the first message
For ongoing bidirectional communication, use the repository's terminal example:
git clone https://github.com/WuKongIM/WuKongEasySDK-Rust.git
cd WuKongEasySDK-Rust
git checkout v0.1.0
cargo build --locked --example chatFrom a trusted development terminal, follow Run Official Examples to prepare credentials, setting both Alice and Bob's device_flag to 2. Run these commands in separate terminals:
# Alice
WK_WS_URL=ws://127.0.0.1:5200 WK_UID=alice WK_TOKEN=alice-token \
WK_PEER_UID=bob cargo run --locked --example chat
# Bob
WK_WS_URL=ws://127.0.0.1:5200 WK_UID=bob WK_TOKEN=bob-token \
WK_PEER_UID=alice cargo run --locked --example chatWait for both connections before typing messages. The example reports server acceptance, receipt and connection state without logging message bodies. Your application can read from_uid, Channel and Payload from Event::Message. Enter /quit or use Ctrl-C to clean up.
5. Clean up
| Task | Rust API and behavior |
|---|---|
| Subscribe/unsubscribe | subscribe() returns a Tokio broadcast receiver; drop it to unsubscribe |
| Concurrent connection | connect().await joins the current attempt; cancelling one future does not cancel it |
| Initial failure | Returns an error; the application decides whether to retry |
| Network reconnect | An established connection's failure gets at most 5 exponential retries with jitter |
| Manual disconnect | disconnect().await cancels authentication, I/O and retries; later connect is allowed |
| Account exit | destroy().await permanently closes every clone; also stop subscriber tasks |
| Last handle dropped | Cancels the worker; explicitly await shutdown when completion matters |
Authentication rejection, server disconnect and manual shutdown do not reconnect. Defaults are a 25-second heartbeat interval, 10-second pong deadline, 5-second connection timeout, 15-second total SEND timeout and 5-second write timeout.
Queued and pending SENDs share a default limit of 256; excess calls return Backpressure. Events retain 256 entries; slow observers get RecvError::Lagged. The default maximum complete JSON-RPC message is 1 MiB including Base64 overhead. Adjust Options for your measured workload.
Automatic RECVACK confirms network receipt, not observer processing. Messages are acknowledged even without observers or when an observer falls behind. EasySDK has no durable inbox; reliable recovery requires application storage, deduplication and reconciliation. Do not ignore Lagged.
Sends are never replayed automatically. Timeout, cancellation or transport loss may leave acceptance unknown; preserve SendOptions.client_msg_no if your application retries under the server's idempotency contract. SendOptions also supports Header, Setting and Topic. SEND red_dot defaults to true and respects explicit false. Use ChannelType::Group for group messages after the backend prepares membership and permissions.
6. Troubleshooting
Can I resend after a timeout or disconnect? The server may already have accepted the message. Keep the outcome unknown and reconcile using SendOptions.client_msg_no.
Why does a listener receive Lagged? Application consumption fell behind and events were lost. Bound the processing queue and reconcile through your backend; reconnect does not fetch history.
For private PKI, put DER root bytes in Options.additional_root_certificates.
This accepts at most 16 certificates of 64 KiB each, never private keys. Public
WebPKI roots remain trusted; hostname and expiry verification stay enabled.
let options = wukong_easy_sdk::Options {
additional_root_certificates: vec![std::fs::read("company-root.der")?],
..Default::default()
};Optional: group messaging
The trusted backend creates the group and manages members through Product HTTP.
After the backend confirms membership, use the group ID with ChannelType::Group:
let ack = client.send(
"project-team",
wukong_easy_sdk::ChannelType::Group,
serde_json::json!({"type": 1, "content": "Hello, team!"}),
).await?;The receiving side continues to use Event::Message; check channel_type,
channel_id, from_uid and payload. SENDACK confirms server acceptance, not
that every member has processed the message. For a group that rejects strangers,
a nonmember or removed member receives Error::Server { code: 3 }; a denylisted
member receives code 4. Report these permission failures to the application.
Membership management credentials belong on the trusted backend.
Next
Continue with messaging and production checks. For offline recovery, conversations, unread counts, or push, see SDK selection. Versions and validation records retain the exact environments and scope of past runs.