pub struct WebsocketHandle { /* private fields */ }Expand description
Handle to an active WebSocket connection.
Provides methods to send messages and receive responses.
§Thread Safety
WebsocketHandle is Send but not Sync. The underlying WebSocket
transport contains non-thread-safe internal buffers.
If you need to share the handle across async tasks, wrap it in a
tokio::sync::Mutex:
use std::sync::Arc;
use tokio::sync::Mutex;
let ws = Arc::new(Mutex::new(client.connect_ws().call().await?));
// Receiving task
let ws_recv = ws.clone();
tokio::spawn(async move {
loop {
let msg = ws_recv.lock().await.recv().await;
// handle msg ...
}
});
// Sending task
ws.lock().await.subscribe([Topic::agg_trade("BTC-USD")], None).await?;For high-throughput bots, a common pattern is to dedicate one task to the
WebSocket and use tokio::sync::mpsc channels to communicate with other
tasks — this avoids lock contention on the hot path.
§Extracting the Inner Socket
If you need direct access to the underlying reqwest_websocket::WebSocket,
use the Deref implementation.
Implementations§
Source§impl WebsocketHandle
impl WebsocketHandle
Sourcepub async fn send(&mut self, msg: ClientMessage) -> SDKResult<(), WSErrors>
pub async fn send(&mut self, msg: ClientMessage) -> SDKResult<(), WSErrors>
Send a message to the server.
§Available Message Types
ClientMessage::Subscribe- Subscribe to market data streamsClientMessage::Unsubscribe- Unsubscribe from streamsClientMessage::ListSubscriptions- List active subscriptionsClientMessage::Ping- Manual ping (not needed for keepalive)ClientMessage::OrderPlace- Place an orderClientMessage::OrderCancel- Cancel an order
§Example
use bullet_rust_sdk::types::ClientMessage;
// Subscribe to aggregated trades
ws.send(ClientMessage::Subscribe {
id: Some(1.into()),
params: vec!["BTC-USD@aggTrade".to_string()],
})
.await?;
// Unsubscribe later
ws.send(ClientMessage::Unsubscribe {
id: Some(2.into()),
params: vec!["BTC-USD@aggTrade".to_string()],
})
.await?;Sourcepub async fn recv(&mut self) -> SDKResult<ServerMessage, WSErrors>
pub async fn recv(&mut self) -> SDKResult<ServerMessage, WSErrors>
Receive the next message from the server.
§Errors
WSErrors::WsClosed- Server closed the connection (includes close code and reason)WSErrors::WsStreamEnded- Connection ended unexpectedly without a close frameWSErrors::WsUpgradeError- WebSocket protocol error
§Parse Errors
If a message cannot be parsed into a known ServerMessage variant,
it returns ServerMessage::Unknown(error, raw_text) instead of failing.
This allows you to log or debug unexpected message formats.
§Example
use bullet_rust_sdk::errors::WSErrors;
use bullet_rust_sdk::types::ClientMessage;
use bullet_rust_sdk::ws::models::{ServerMessage, TaggedMessage};
let api = Client::mainnet().await?;
'reconnect: loop {
let mut ws = api.connect_ws().call().await?;
ws.send(ClientMessage::Subscribe {
id: Some(1.into()),
params: vec!["BTC-USD@aggTrade".to_string()],
})
.await?;
loop {
match ws.recv().await {
Ok(msg) => match msg {
ServerMessage::AggTrade(trade) => {
println!("Trade: {} @ {}", trade.symbol, trade.price);
}
ServerMessage::Tagged(TaggedMessage::Pong(_)) => {}
ServerMessage::Tagged(TaggedMessage::Error(err)) => {
eprintln!("Server error: {:?}", err);
}
_ => {}
},
Err(WSErrors::WsClosed { code, reason }) => {
eprintln!("Connection closed (code {:?}): {}", code, reason);
continue 'reconnect;
}
Err(WSErrors::WsStreamEnded) => {
eprintln!("Connection lost unexpectedly");
continue 'reconnect;
}
Err(e) => return Err(e.into()),
}
}
}Sourcepub async fn subscribe(
&mut self,
topics: impl IntoIterator<Item = Topic>,
id: Option<RequestId>,
) -> SDKResult<(), WSErrors>
pub async fn subscribe( &mut self, topics: impl IntoIterator<Item = Topic>, id: Option<RequestId>, ) -> SDKResult<(), WSErrors>
Subscribe to one or more topics.
§Arguments
topics- Topics to subscribe toid- Optional request ID for matching the server’s response
§Example
use bullet_rust_sdk::types::RequestId;
use bullet_rust_sdk::{Client, OrderbookDepth, Topic};
let api = Client::mainnet().await?;
let mut ws = api.connect_ws().call().await?;
// Subscribe to multiple topics using type-safe builders
ws.subscribe(
[
Topic::agg_trade("BTC-USD"),
Topic::depth("ETH-USD", OrderbookDepth::D10),
Topic::book_ticker("SOL-USD"),
],
Some(RequestId::new(1)),
)
.await?;
// Now receive market data
loop {
let msg = ws.recv().await?;
println!("{:?}", msg);
}Sourcepub async fn list_subscriptions(
&mut self,
id: Option<RequestId>,
) -> SDKResult<(), WSErrors>
pub async fn list_subscriptions( &mut self, id: Option<RequestId>, ) -> SDKResult<(), WSErrors>
Unsubscribe from one or more topics.
Unsubscribe is idempotent - unsubscribing from topics you’re not subscribed to will still succeed.
§Arguments
topics- Topics to unsubscribe fromid- Optional request ID for matching the server’s response
§Example
use bullet_rust_sdk::Client;
use bullet_rust_sdk::types::RequestId;
let api = Client::mainnet().await?;
let mut ws = api.connect_ws().call().await?;
ws.list_subscriptions(Some(RequestId::new(1))).await?;
// Match response by request_idSourcepub async fn order_place(
&mut self,
tx: impl Into<String>,
id: Option<RequestId>,
) -> SDKResult<(), WSErrors>
pub async fn order_place( &mut self, tx: impl Into<String>, id: Option<RequestId>, ) -> SDKResult<(), WSErrors>
Place an order via WebSocket.
§Arguments
tx- Base64-encoded raw transaction bytesid- Optional request ID for matching the server’s response
§Example
use bullet_rust_sdk::Client;
use bullet_rust_sdk::types::RequestId;
let api = Client::mainnet().await?;
let mut ws = api.connect_ws().call().await?;
let tx_bytes = "base64_encoded_transaction";
ws.order_place(tx_bytes, Some(RequestId::new(1))).await?;
// Match response by request_idSourcepub async fn order_cancel(
&mut self,
tx: impl Into<String>,
id: Option<RequestId>,
) -> SDKResult<(), WSErrors>
pub async fn order_cancel( &mut self, tx: impl Into<String>, id: Option<RequestId>, ) -> SDKResult<(), WSErrors>
Cancel an order via WebSocket.
§Arguments
tx- Base64-encoded raw transaction bytesid- Optional request ID for matching the server’s response
§Example
use bullet_rust_sdk::Client;
use bullet_rust_sdk::types::RequestId;
let api = Client::mainnet().await?;
let mut ws = api.connect_ws().call().await?;
let tx_bytes = "base64_encoded_cancel_transaction";
ws.order_cancel(tx_bytes, Some(RequestId::new(1))).await?;
// Match response by request_idSourcepub async fn place_order(
&mut self,
signed: &Transaction,
id: Option<RequestId>,
) -> SDKResult<(), WSErrors>
pub async fn place_order( &mut self, signed: &Transaction, id: Option<RequestId>, ) -> SDKResult<(), WSErrors>
Place an order via WebSocket using a signed transaction.
This is a convenience wrapper around order_place that
handles base64 encoding internally.
§Example
use bullet_rust_sdk::{Client, Transaction};
let signed = Transaction::builder()
.call_message(call_msg)
.client(&client)
.build()?;
ws.place_order(&signed, None).await?;Sourcepub async fn cancel_order(
&mut self,
signed: &Transaction,
id: Option<RequestId>,
) -> SDKResult<(), WSErrors>
pub async fn cancel_order( &mut self, signed: &Transaction, id: Option<RequestId>, ) -> SDKResult<(), WSErrors>
Cancel an order via WebSocket using a signed transaction.
This is a convenience wrapper around order_cancel that
handles base64 encoding internally.
§Example
use bullet_rust_sdk::{Client, Transaction};
let signed = Transaction::builder()
.call_message(cancel_msg)
.client(&client)
.build()?;
ws.cancel_order(&signed, None).await?;