| Crates.io | valinor-wire |
| lib.rs | valinor-wire |
| version | 0.1.0 |
| created_at | 2026-01-09 14:58:40.93746+00 |
| updated_at | 2026-01-09 14:58:40.93746+00 |
| description | Wire protocol and message encoding for MudWorld platform |
| homepage | |
| repository | https://github.com/douglance/mudworld |
| max_upload_size | |
| id | 2032216 |
| size | 24,180 |
Wire protocol codec for MudWorld client-server communication.
valinor-wire provides a transport-agnostic message envelope format and codec for encoding/decoding messages between MudWorld clients and servers. It abstracts the serialization format (JSON or binary) behind a unified API, enabling format negotiation during connection handshake.
Add to your Cargo.toml:
[dependencies]
valinor-wire = { path = "../valinor-wire" }
Or if published:
[dependencies]
valinor-wire = "0.1"
| Type | Description |
|---|---|
Envelope |
Message wrapper containing type, optional request ID, and JSON payload |
WireCodec |
Encoder/decoder supporting JSON and Protobuf formats |
WireFormat |
Format selection enum (Json, Protobuf) |
ContentType |
HTTP content-type header negotiation helper |
EnvelopeError |
Error type for encoding/decoding failures |
The Envelope struct is the standard message container:
pub struct Envelope {
pub msg_type: String, // Message type identifier (e.g., "chat.say")
pub request_id: Option<String>, // Present for request/response patterns
pub payload: serde_json::Value, // Message-specific data
}
Factory methods:
Envelope::request() - Create a request expecting a responseEnvelope::response() - Create a response to a requestEnvelope::event() - Create a fire-and-forget eventEnvelope::error() - Create an error responseThe codec handles serialization:
pub struct WireCodec { /* ... */ }
impl WireCodec {
pub fn json() -> Self;
pub fn protobuf() -> Self;
pub fn encode(&self, envelope: &Envelope) -> Result<Vec<u8>, EnvelopeError>;
pub fn decode(&self, data: &[u8]) -> Result<Envelope, EnvelopeError>;
}
use valinor_wire::{Envelope, WireCodec};
use serde_json::json;
// Create a chat message event
let envelope = Envelope::event("chat.say", json!({
"room_id": "tavern",
"text": "Hello, adventurers!"
}));
// Encode for transmission
let codec = WireCodec::json();
let bytes = codec.encode(&envelope).expect("encode failed");
// Send bytes over WebSocket...
use valinor_wire::{Envelope, WireCodec};
use serde_json::json;
// Create a request with correlation ID
let request = Envelope::request(
"room.join",
"req-123".to_string(),
json!({ "room_id": "tavern" })
);
let codec = WireCodec::json();
let bytes = codec.encode(&request).expect("encode failed");
// Later, when response arrives...
let response_bytes: &[u8] = /* received from server */;
let response = codec.decode(response_bytes).expect("decode failed");
if response.request_id == Some("req-123".to_string()) {
// This is our response
println!("Joined room: {:?}", response.payload);
}
use valinor_wire::Envelope;
use serde_json::json;
// Error with correlation to original request
let error = Envelope::error(
Some("req-123".to_string()),
"ROOM_FULL",
"The tavern is at capacity"
);
// Error without request context (e.g., protocol violation)
let protocol_error = Envelope::error(
None,
"INVALID_MESSAGE",
"Unrecognized message type"
);
use valinor_wire::{ContentType, WireCodec, WireFormat};
// Parse from HTTP header
let content_type = ContentType::from_header("application/json");
assert_eq!(content_type, Some(ContentType::Json));
// Create codec based on negotiated format
let codec = match content_type {
Some(ContentType::Json) => WireCodec::json(),
Some(ContentType::Protobuf) => WireCodec::protobuf(),
None => WireCodec::json(), // Default fallback
};
// Get header value for responses
let header = ContentType::Json.to_header();
assert_eq!(header, "application/json");
The binary format is optimized for game state updates where payload is already serialized protobuf:
use valinor_wire::{Envelope, WireCodec};
use base64::engine::general_purpose::STANDARD;
use base64::Engine;
// Binary payloads must be base64-encoded strings
let protobuf_bytes: Vec<u8> = vec![/* serialized protobuf */];
let payload_b64 = STANDARD.encode(&protobuf_bytes);
let envelope = Envelope::event(
"state.update",
serde_json::Value::String(payload_b64)
);
let codec = WireCodec::protobuf();
let wire_bytes = codec.encode(&envelope).expect("encode failed");
// Binary format: [2-byte type length][type bytes][payload bytes]
// More compact than JSON for binary payloads
Standard JSON serialization:
{
"type": "chat.say",
"request_id": "req-123",
"payload": { "text": "Hello!" }
}
Compact binary encoding for protobuf payloads:
[u16 big-endian: type length][type bytes][raw payload bytes]
Note: Binary format does not support request_id. Use JSON for request/response patterns.
| Crate | Relationship |
|---|---|
valinor-proto |
Protobuf message definitions used as payloads |
valinor-router |
Message routing that dispatches decoded envelopes |
valinor-session |
Session management using wire protocol |
valinor-worker |
Cloudflare Worker that uses this codec |
MIT