Official Rust SDK for OddSockets - a high-performance real-time messaging platform.
- High Performance: Built on Tokio for maximum async performance with zero-cost abstractions
- Type Safety: Full Rust type safety with comprehensive error handling using
thiserror - Real-time Messaging: WebSocket-based real-time communication with automatic reconnection
- Bulk Publishing: Efficient multi-message publishing for high-throughput scenarios
- Presence Tracking: Real-time user presence information with channel-level granularity
- Message History: Retrieve historical messages with flexible filtering options
- Auto Reconnection: Intelligent reconnection with exponential backoff and jitter
- Zero-Copy: Efficient message handling with minimal allocations
- Production Ready: Comprehensive error handling, logging, and monitoring support
Add this to your Cargo.toml:
[dependencies]
oddsockets = "0.1.0-beta.1"
tokio = { version = "1.0", features = ["full"] }use oddsockets::{OddSocketsClient, OddSocketsConfig, message_types};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create and configure client
let config = OddSocketsConfig::new("ak_your_api_key_here");
let client = OddSocketsClient::new(config).await?;
// Connect to OddSockets
client.connect().await?;
// Get a channel
let channel = client.channel("my-channel");
// Subscribe to messages
let mut message_stream = channel.subscribe(Default::default()).await?;
// Publish a message
let message = message_types::chat_message("Hello, Rust!", "user123", None);
channel.publish(message, Default::default()).await?;
// Listen for messages
while let Some(message) = message_stream.recv().await {
println!("Received: {:?}", message);
}
Ok(())
}use oddsockets::OddSocketsConfig;
let config = OddSocketsConfig::new("ak_your_api_key_here");use oddsockets::OddSocketsConfig;
use std::time::Duration;
let config = OddSocketsConfig::builder("ak_your_api_key_here")
.manager_url("https://your-manager1.oddsockets.tyga.network")
.user_id("user123")
.auto_connect(true)
.heartbeat_interval(Duration::from_secs(30))
.reconnect_attempts(5)
.timeout(Duration::from_secs(10))
.build()?;// Development environment
let config = OddSocketsConfig::builder("ak_your_api_key_here")
.development()
.build()?;
// Production environment
let config = OddSocketsConfig::builder("ak_your_api_key_here")
.production()
.build()?;
// High-performance scenarios
let config = OddSocketsConfig::builder("ak_your_api_key_here")
.high_performance()
.build()?;use oddsockets::{PublishOptions, message_types};
// Simple message
let message = message_types::chat_message("Hello!", "user123", None);
let result = channel.publish(message, PublishOptions::default()).await?;
// Message with options
let message = message_types::notification_message(
"Alert",
"Something happened",
Some("system"),
Some("high"),
None
);
let options = PublishOptions::system_message();
let result = channel.publish(message, options).await?;use oddsockets::{BulkMessage, message_types};
let messages = vec![
BulkMessage::new(
"channel1",
message_types::chat_message("Hello", "user1", None),
None
),
BulkMessage::new(
"channel2",
message_types::chat_message("World", "user2", None),
None
),
];
let results = client.publish_bulk(messages).await?;
for result in results {
if result.is_successful() {
println!("Message published successfully");
} else {
println!("Failed: {}", result.error_message("Unknown error"));
}
}use oddsockets::SubscribeOptions;
let mut message_stream = channel.subscribe(SubscribeOptions::default()).await?;
while let Some(message) = message_stream.recv().await {
println!("Received: {:?}", message);
}// Chat channel with presence and history
let options = SubscribeOptions::chat_channel();
let mut stream = channel.subscribe(options).await?;
// Notification channel (minimal options)
let options = SubscribeOptions::notification_channel();
let mut stream = channel.subscribe(options).await?;
// Data channel with history
let options = SubscribeOptions::data_channel();
let mut stream = channel.subscribe(options).await?;use oddsockets::HistoryOptions;
// Get recent messages
let history = channel.get_history(HistoryOptions::recent(50)).await?;
// Get messages from the last hour
let history = channel.get_history(HistoryOptions::last_hour(None)).await?;
// Get messages from the last day
let history = channel.get_history(HistoryOptions::last_day(Some(1000))).await?;
// Custom time range
let options = HistoryOptions {
limit: Some(100),
start: Some(chrono::Utc::now() - chrono::Duration::hours(2)),
end: Some(chrono::Utc::now()),
reverse: true,
};
let history = channel.get_history(options).await?;// Get current presence
let presence = channel.get_presence().await?;
println!("Channel has {} users", presence.count);
for user in &presence.users {
println!("User: {}", user);
}
// Check if specific user is present
if presence.is_user_present("user123") {
println!("User123 is online");
}// Connect
client.connect().await?;
// Check connection state
if client.is_connected() {
println!("Connected!");
}
// Disconnect
client.disconnect().await?;use oddsockets::ConnectionState;
let mut state_stream = client.connection_state_stream();
while let Some(state) = state_stream.recv().await {
match state {
ConnectionState::Connected => println!("Connected!"),
ConnectionState::Disconnected => println!("Disconnected"),
ConnectionState::Reconnecting => println!("Reconnecting..."),
_ => {}
}
}The SDK provides convenient message type constructors:
use oddsockets::message_types;
// Chat message
let chat = message_types::chat_message("Hello!", "user123", Some("general"));
// Notification
let notification = message_types::notification_message(
"Alert",
"Something happened",
Some("system"),
Some("high"),
Some(serde_json::json!({"extra": "data"}))
);
// System message
let system = message_types::system_message(
"user_joined",
"User joined the channel",
Some(serde_json::json!({"userId": "user123"}))
);
// Data event
let data_event = message_types::data_event(
"sensor_reading",
serde_json::json!({"temperature": 23.5, "humidity": 45.2}),
Some("sensor_01")
);The SDK uses comprehensive error types with recovery suggestions:
use oddsockets::{OddSocketsError, OddSocketsResultExt};
match client.connect().await {
Ok(_) => println!("Connected successfully"),
Err(OddSocketsError::InvalidApiKey { message }) => {
println!("Invalid API key: {}", message);
for suggestion in error.recovery_suggestions() {
println!(" - {}", suggestion);
}
}
Err(OddSocketsError::ConnectionFailed { message }) => {
println!("Connection failed: {}", message);
if error.should_reconnect() {
// Implement retry logic
}
}
Err(e) => println!("Other error: {}", e),
}use tokio::spawn;
let mut message_stream = channel.subscribe(SubscribeOptions::default()).await?;
spawn(async move {
while let Some(message) = message_stream.recv().await {
// Process message in background
process_message(message).await;
}
});use futures::future::join_all;
let channels = vec!["channel1", "channel2", "channel3"];
let mut streams = Vec::new();
for channel_name in channels {
let channel = client.channel(channel_name);
let stream = channel.subscribe(SubscribeOptions::default()).await?;
streams.push(stream);
}
// Handle all streams concurrently
let handlers: Vec<_> = streams.into_iter().map(|mut stream| {
spawn(async move {
while let Some(message) = stream.recv().await {
println!("Received on {}: {:?}", message.channel, message);
}
})
}).collect();
join_all(handlers).await;use tokio::signal;
// Set up graceful shutdown
let shutdown = async {
signal::ctrl_c().await.expect("Failed to listen for Ctrl+C");
println!("Shutting down gracefully...");
};
tokio::select! {
_ = shutdown => {
// Cleanup
client.disconnect().await?;
println!("Shutdown complete");
}
_ = message_handler => {
// Message handling completed
}
}#[cfg(test)]
mod tests {
use super::*;
use oddsockets::{OddSocketsConfig, OddSocketsClient};
#[tokio::test]
async fn test_client_creation() {
let config = OddSocketsConfig::new("ak_test_key");
let client = OddSocketsClient::new(config).await.unwrap();
assert!(!client.is_connected());
}
#[tokio::test]
async fn test_message_creation() {
let message = message_types::chat_message("test", "user", None);
assert_eq!(message["text"], "test");
assert_eq!(message["username"], "user");
}
}The Rust SDK is designed for high performance:
- Zero-copy message handling where possible
- Efficient WebSocket implementation using
tokio-tungstenite - Minimal allocations in hot paths
- Async-first design for maximum concurrency
- Connection pooling and reuse
- Batch operations for bulk publishing
cargo benchEnable logging to debug issues:
env_logger::init();Or with custom configuration:
use log::LevelFilter;
env_logger::Builder::from_default_env()
.filter_level(LevelFilter::Debug)
.init();cargo buildcargo testcargo run --example basic_usage
cargo run --example bulk_publishing
cargo run --example chat_applicationcargo doc --open- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Run
cargo testandcargo clippy - Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
AI agents can sign up with a verified email in two steps — no dashboard, no human required.
Step 1: Request a verification code
curl -X POST https://oddsockets.com/api/agent-signup \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "agentName": "my-agent", "platform": "rust"}'Step 2: Verify the 6-digit code from your email and get your API key
curl -X POST https://oddsockets.com/api/agent-signup/verify \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "code": "123456", "agentName": "my-agent"}'| Free | Starter | Pro | |
|---|---|---|---|
| Price | $0/mo | $49.99/mo | $299/mo |
| MAU | 100 | 1,000 | 50,000 |
| Concurrent connections | 50 | 1,000 | Unlimited |
| Messages/day | 10,000 | 4,320,000 | Unlimited |
| Messages/minute | 100 | 3,000 | Unlimited |
| Channels | 10 | Unlimited | Unlimited |
| Storage | 100MB (24h) | 50GB (6 months) | Unlimited |
All limits are enforced in real time.
MIT License - Copyright (c) 2026 Joe Wee, Tyga.Cloud Ltd. See LICENSE for details.