16 stable releases
| new 4.5.0 | Mar 30, 2026 |
|---|---|
| 4.4.0 | Mar 29, 2026 |
| 4.0.3 | Feb 22, 2026 |
| 3.5.0 | Feb 19, 2026 |
| 0.1.8 | Jan 22, 2026 |
#44 in WebSocket
Used in 2 crates
630KB
14K
SLoC
clasp-router
Message router and server for CLASP (Creative Low-Latency Application Streaming Protocol).
Features
- Message Routing - Route messages between connected clients
- Pattern Matching - Wildcard subscriptions with
*and** - State Management - Parameter state with revision tracking
- Session Management - Track client connections and subscriptions
- Multiple Transports - WebSocket, QUIC, TCP
- Protocol Adapters - Accept MQTT and OSC clients directly (optional features)
- Rate Limiting - Configurable per-client message rate limits
- Gesture Coalescing - Reduce bandwidth for high-frequency gesture streams
Installation
[dependencies]
clasp-router = "3.5"
# Optional: Enable protocol adapters
clasp-router = { version = "3.5", features = ["mqtt-server", "osc-server"] }
Feature Flags
| Feature | Description |
|---|---|
websocket |
WebSocket transport (default) |
quic |
QUIC transport with built-in TLS |
tcp |
Raw TCP transport |
mqtt-server |
Accept MQTT clients directly |
osc-server |
Accept OSC clients via UDP |
journal |
State persistence and replay via clasp-journal |
rules |
Server-side automation via clasp-rules |
federation |
Accept inbound federation peers |
metrics |
Prometheus-compatible instrumentation via metrics crate |
full |
All features enabled |
Basic Usage
use clasp_router::{Router, RouterConfig};
use clasp_core::SecurityMode;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let router = Router::new(RouterConfig {
name: "My Router".into(),
max_sessions: 100,
session_timeout: 60,
features: vec!["param".into(), "event".into()],
security_mode: SecurityMode::Open,
max_subscriptions_per_session: 100,
gesture_coalescing: true,
gesture_coalesce_interval_ms: 16,
max_messages_per_second: 1000,
rate_limiting_enabled: true,
});
// Serve on WebSocket
router.serve_websocket("0.0.0.0:7330").await?;
Ok(())
}
Multi-Protocol Server
Serve multiple protocols simultaneously with shared state:
use clasp_router::{Router, RouterConfig, MultiProtocolConfig};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let router = Router::new(RouterConfig::default());
let config = MultiProtocolConfig {
websocket_addr: Some("0.0.0.0:7330".into()),
#[cfg(feature = "mqtt-server")]
mqtt: Some(clasp_router::MqttServerConfig {
bind_addr: "0.0.0.0:1883".into(),
namespace: "/mqtt".into(),
..Default::default()
}),
#[cfg(feature = "osc-server")]
osc: Some(clasp_router::OscServerConfig {
bind_addr: "0.0.0.0:8000".into(),
namespace: "/osc".into(),
..Default::default()
}),
..Default::default()
};
// All protocols share the same router state
router.serve_all(config).await?;
Ok(())
}
Protocol Adapters
MQTT Server Adapter
Accept MQTT clients directly without an external broker:
use clasp_router::MqttServerConfig;
let mqtt_config = MqttServerConfig {
bind_addr: "0.0.0.0:1883".into(),
namespace: "/mqtt".into(), // MQTT topic "sensors/temp" -> CLASP "/mqtt/sensors/temp"
require_auth: false,
max_clients: 100,
session_timeout_secs: 300,
..Default::default()
};
MQTT to CLASP mapping:
| MQTT | CLASP |
|---|---|
| CONNECT | Hello -> Session |
SUBSCRIBE sensors/# |
Subscribe /mqtt/sensors/** |
PUBLISH sensors/temp |
Set /mqtt/sensors/temp |
| QoS 0 | Fire-and-forget |
| QoS 1 | With acknowledgment |
OSC Server Adapter
Accept OSC clients via UDP with automatic session tracking:
use clasp_router::OscServerConfig;
let osc_config = OscServerConfig {
bind_addr: "0.0.0.0:8000".into(),
namespace: "/osc".into(), // OSC "/synth/volume" -> CLASP "/osc/synth/volume"
session_timeout_secs: 30, // Sessions expire after 30s of inactivity
auto_subscribe: false,
..Default::default()
};
Configuration Reference
RouterConfig
| Field | Type | Default | Description |
|---|---|---|---|
name |
String | "CLASP Router" | Server name shown to clients |
max_sessions |
usize | 1000 | Maximum concurrent connections |
session_timeout |
u64 | 300 | Session timeout in seconds |
security_mode |
SecurityMode | Open | Authentication mode |
max_subscriptions_per_session |
usize | 1000 | Max subscriptions per client |
gesture_coalescing |
bool | true | Enable gesture move coalescing |
gesture_coalesce_interval_ms |
u64 | 16 | Coalesce interval (16ms = 60fps) |
max_messages_per_second |
u32 | 1000 | Rate limit per client (0 = unlimited) |
rate_limiting_enabled |
bool | true | Enable rate limiting |
state_config |
RouterStateConfig | Default (1h TTL) | State store configuration |
State Configuration (TTL)
Parameters and signals can be configured to expire after a time-to-live period:
use clasp_router::{RouterConfig, RouterStateConfig};
use std::time::Duration;
let config = RouterConfig {
state_config: RouterStateConfig {
param_config: clasp_core::state::StateStoreConfig {
max_params: Some(100_000),
param_ttl: Some(Duration::from_secs(3600)), // 1 hour
eviction: clasp_core::state::EvictionStrategy::Lru,
},
signal_ttl: Some(Duration::from_secs(3600)), // 1 hour
max_signals: Some(100_000),
},
..Default::default()
};
// Or use unlimited (no expiration):
let unlimited_config = RouterConfig {
state_config: RouterStateConfig::unlimited(),
..Default::default()
};
Rate Limiting
Rate limiting prevents clients from overwhelming the router:
let config = RouterConfig {
rate_limiting_enabled: true,
max_messages_per_second: 500, // 500 msg/s per client
..Default::default()
};
When a client exceeds the rate limit, excess messages are dropped and a warning is logged.
Buffer Overflow Notifications
When a client's receive buffer fills and messages are dropped, the router sends an ERROR 503 notification after 100 drops within 10 seconds. This helps slow clients detect they're missing messages. Notifications are rate-limited to 1 per 10 seconds per session.
Journal Integration
Enable state persistence with the journal feature. The router records all SET and PUBLISH operations to an append-only journal for crash recovery and replay:
use clasp_journal::SqliteJournal;
use std::sync::Arc;
let journal = Arc::new(SqliteJournal::new("state.db")?);
let router = Router::new(config).with_journal(journal);
On restart, state can be replayed from the journal. Clients can request replay of missed messages using the Replay handler.
Rules Engine
Enable server-side automation with the rules feature. Rules are evaluated after state changes:
use clasp_rules::{Rule, Trigger, RuleAction, RulesEngine};
The router evaluates matching rules on each SET/PUBLISH, executing actions like setting values, publishing events, or copying values with transforms. See clasp-rules for rule definition syntax.
Federation
Enable router-to-router state sharing with the federation feature. The router accepts inbound federation peers that advertise "federation" in their HELLO features.
Federation operations handled by the router:
| Operation | Description |
|---|---|
DeclareNamespaces |
Peer declares owned namespace patterns, router auto-subscribes |
RequestSync |
Peer requests state snapshot for a pattern range |
RevisionVector |
Peer exchanges revision vectors for delta sync |
SyncComplete |
Marks sync as complete |
Security: In authenticated mode, federation peers must have scopes covering their declared namespaces. RequestSync and RevisionVector are validated against declared namespaces (peers cannot request data outside their declared scope). Resource limits prevent exhaustion: max 1,000 patterns per peer, max 10,000 entries per revision vector.
Non-federation sessions that attempt FederationSync receive a 403 error.
Architecture
┌─────────────────────────────────────────────────┐
│ CLASP Router │
│ ┌─────────────────────────────────────────┐ │
│ │ Shared State │ │
│ │ sessions | subscriptions | state │ │
│ └──────┬──────────────┬──────────────┬────┘ │
│ │ │ │ │
│ ┌──────▼──────┐ ┌─────▼─────┐ ┌─────▼─────┐ │
│ │ Journal │ │ Rules │ │ Federation│ │
│ │ (optional) │ │ (optional)│ │ (optional)│ │
│ └─────────────┘ └───────────┘ └─────┬─────┘ │
│ │ │
│ ▲ ▲ ▲ │ │
│ │ │ │ ▼ │
│ ┌─────┴───┐ ┌─────┴───┐ ┌─────┴───┐ ┌──────┐ │
│ │WebSocket│ │ MQTT │ │ OSC │ │ Peer │ │
│ │ :7330 │ │ :1883 │ │ :8000 │ │Router│ │
│ └─────────┘ └─────────┘ └─────────┘ └──────┘ │
└─────────────────────────────────────────────────┘
All protocol adapters and federation peers share the same router state, enabling cross-protocol and cross-site communication.
Performance
| Metric | Value |
|---|---|
| E2E throughput | 173k msg/s |
| Fanout 100 subs | 175k deliveries/s |
| Events (no state) | 259k msg/s |
| Late-joiner replay | Yes (chunked snapshots) |
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Maintained by LumenCanvas
Dependencies
~10–26MB
~263K SLoC