| Crates.io | moo-transport |
| lib.rs | moo-transport |
| version | 0.1.0 |
| created_at | 2026-01-16 04:48:55.594822+00 |
| updated_at | 2026-01-16 04:48:55.594822+00 |
| description | Implementation of the MOO protocol, an HTTP-like bidirectional message protocol |
| homepage | https://github.com/dannydulai/moo-transport |
| repository | https://github.com/dannydulai/moo-transport |
| max_upload_size | |
| id | 2047917 |
| size | 104,674 |
A Rust implementation of the MOO protocol, an HTTP-like bidirectional message protocol designed for reliable, ordered communication over TCP or WebSockets.
The MOO protocol uses a text-based header section followed by an optional binary body, similar to HTTP:
MOO/1 <VERB> <NAME>
Request-Id: <id>
Header1: Value1
Content-Type: application/json
Content-Length: <bytes>
<body content>
Verbs:
REQUEST: Initial request messageCONTINUE: Streaming response (can be sent multiple times)COMPLETE: Final response messageAdd this to your Cargo.toml:
[dependencies]
moo-transport = "0.1"
Or add it via cargo:
cargo add moo-transport
use moo_transport::{MooConnection, Result};
use futures::StreamExt;
#[tokio::main]
async fn main() -> Result<()> {
// Connect to a MOO server via TCP
let conn = MooConnection::new_tcp("192.168.1.100:9100").await?;
// Send a request and receive responses
let mut responses = conn.send_request(
"com.roon.app/ping",
Some(serde_json::json!({"message": "hello"}))
).await?;
// Process responses
while let Some(result) = responses.next().await {
match result {
Ok(msg) => println!("Received: {}", msg.name),
Err(e) => eprintln!("Error: {}", e),
}
}
Ok(())
}
use moo_transport::{MooConnection, Result};
#[tokio::main]
async fn main() -> Result<()> {
// Connect via WebSocket
let conn = MooConnection::new_websocket("ws://192.168.1.100:9100/api").await?;
// Use the connection as normal
let mut responses = conn.send_request("com.example/test", None).await?;
Ok(())
}
use moo_transport::{MooConnection, MooRequest, Result};
#[tokio::main]
async fn main() -> Result<()> {
let conn = MooConnection::new_tcp("192.168.1.100:9100").await?;
// Register a handler for incoming requests
conn.register_request_handler("com.myservice/ping", |req: MooRequest| async move {
// Send a COMPLETE response
req.send_complete("Success", Some(serde_json::json!({"pong": true}))).await
}).await;
// Keep connection alive
tokio::time::sleep(tokio::time::Duration::from_secs(3600)).await;
Ok(())
}
The MOO protocol supports streaming responses where a single REQUEST can receive multiple CONTINUE messages followed by a final COMPLETE message:
use moo_transport::{MooConnection, Result};
use futures::StreamExt;
#[tokio::main]
async fn main() -> Result<()> {
let conn = MooConnection::new_tcp("192.168.1.100:9100").await?;
let mut responses = conn.send_request(
"com.roon.app/subscribe_zones",
None
).await?;
// Receive streaming updates
while let Some(result) = responses.next().await {
match result {
Ok(msg) => {
println!("Update: {}", msg.name);
if let Some(body_result) = msg.body_json() {
match body_result {
Ok(body) => println!(" Body: {:?}", body),
Err(e) => eprintln!(" Error parsing body: {}", e),
}
}
}
Err(e) => eprintln!("Error: {}", e),
}
}
Ok(())
}
The library supports the following cargo features:
websocket (enabled by default): Enables WebSocket transport support via tokio-tungsteniteTo disable WebSocket support:
[dependencies]
moo-transport = { version = "0.1", default-features = false }
Every MOO message consists of:
First Line: MOO/1 VERB NAME
MOO/1)REQUEST, CONTINUE, or COMPLETE)com.roon.app/ping)Required Headers:
Request-Id: Unique identifier for matching responses to requestsOptional Headers:
Content-Type: MIME type of body (required if body present)Content-Length: Size of body in bytes (required if body present)Blank Line: Separates headers from body
Body (optional): JSON or binary data, see Content-Type for format
Client Server
| |
|--- REQUEST (Request-Id: 1) -->|
| |
|<-- CONTINUE (Request-Id: 1) --| (optional, repeatable)
|<-- CONTINUE (Request-Id: 1) --|
| |
|<-- COMPLETE (Request-Id: 1) --|
Both client and server can send REQUEST messages and handle incoming requests, making the protocol fully bidirectional.
Full API documentation is available by running:
cargo doc --open
Key types:
MooConnection: High-level connection managerMooMessage: Represents a complete MOO messageMooRequest: Incoming request with methods to send responsesMooVerb: Enum for REQUEST, CONTINUE, COMPLETEResponseStream: Stream of responses for a requestMooParser: Low-level parser for MOO protocolMooMessageBuilder: Builder for constructing MOO messagesThe library uses a custom Result<T> type alias with MooError for error handling:
use moo_transport::{MooConnection, MooError, Result};
match conn.send_request("test", None).await {
Ok(mut stream) => { /* handle responses */ }
Err(MooError::ConnectionClosed) => eprintln!("Connection closed"),
Err(MooError::InvalidVerb(v)) => eprintln!("Invalid verb: {}", v),
Err(e) => eprintln!("Other error: {}", e),
}
Run the test suite:
cargo test
Run tests with logging:
RUST_LOG=debug cargo test
The library is designed for high performance:
bytes crateMIT License - see LICENSE file for details
Contributions are welcome! Please feel free to submit issues or pull requests.