Distributed publish-subscribe data service and Mles protocol reference implementation on Rust, Warp and Serde
Rust
167
489 commits
updated Jun 27, 2026
Mles (Modern Lightweight channEl Service) is a client-server data distribution protocol targeted to serve as a lightweight and reliable distributed publish-subscribe data service.
Please check https://mles.io and https://mles.io/blog.html for a generic overview of Mles and /c/mles for the latest news.
Mles clients connect to a Mles server using Mles protocol header first frame (uid, channel, optional auth) value triplet on a TLS [1] WebSocket [2] session where the triplet is encapsulated in JavaScript Object Notation (JSON). A Mles client first subscribes to a channel by sending the correct Mles protocol header first frame value triplet (uid, channel, optional auth) where the channel specifies the channel to publish/subscribe. The auth MAY be included in case authentication is needed on top of WebSocket TLS. A Mles client MUST set Sec-WebSocket-Protocol subprotocol to "mles-websocket" [3] to be able to establish a connection with a Mles server successfully.
The Mles server verifies the Mles protocol header first frame and then joins the Mles client to the selected channel. Every channel uses its own context and is independent of other channels: therefore a TLS session per (uid, channel) pair is always used. After joining, the Mles server distributes the value triplet between all clients on the same channel. If a Mles client wants to depart from a channel, it just closes the WebSocket TLS session. If a Mles client does not want to receive any message, it just closes the WebSocket TLS session receive side.
A Mles server MAY save the history of received data, which can be then distributed to new clients when they connect to the Mles server. In case Mles server is restarted, Mles peer server, or even a Mles client, MAY provide history data for the Mles server as a resynchronization for those channels for which it has the history available. This allows distributed data protection for the channel information. A client SHOULD implement packet deduplication to avoid showing duplicate messages to user.
An Mles proxy-client MAY proxy a selected channel data between several Mles servers. Mles servers see proxy sessions as any other Mles client sessions. A proxy MUST implement packet deduplication to avoid forwarding loops for several proxies on the same channel. This allows Mles proxy-client to share and distribute value triplet data in an organized and powerful, yet simple manner between several Mles servers.
Mles clients and servers are independent of IP version and do not use IP broadcast or multicast. A Mles server MAY be configured to use IP anycast.
The protocol header first frame for Mles is as follows:
{
"uid":"<user identification>",
"channel":"<selected channel>",
"auth":"<optional authentication hash>"
}
Usage: mles [OPTIONS] --domains <DOMAINS> --wwwroot <WWWROOT>
Options:
-d, --domains <DOMAINS>
Domain(s) - can be specified multiple times for multiple domains
-e, --email <EMAIL>
Contact info for Let's Encrypt certificate registration
-c, --cache <CACHE>
Cache directory for Let's Encrypt certificates
-l, --limit <LIMIT>
History limit - maximum number of messages to store per channel
[default: 200]
-f, --filelimit <FILELIMIT>
Open files limit - maximum number of concurrent file handles
[default: 256]
-w, --wwwroot <WWWROOT>
Www-root directory for domain(s)
Structure: /path/static where domain example.io goes to static/example.io
-s, --staging
Use Let's Encrypt staging environment
(see https://letsencrypt.org/docs/staging-environment/)
-p, --port <PORT>
TLS port for WebSocket connections
[default: 443]
-r, --redirect
Enable HTTP to HTTPS redirect on port 80
-C, --compression-cache <COMPRESSION_CACHE>
Compression cache size in MB for static file serving
Set to 0 to disable caching
--rate-limit <RATE_LIMIT>
Per-IP TCP-accept rate limit (connections/minute)
Applies to the TLS port and (when --redirect is set) port 80.
Connections from an IP exceeding the quota are dropped before TLS
handshake. IPv4-mapped IPv6 addresses are normalized so a client
counts as one IP regardless of socket family. Omit to disable.
-h, --help
Print help
static/your.domainRUST_LOG=debug mles --domains your.domain --cache . --wwwroot static
You can serve multiple domains by specifying the --domains flag multiple times:
RUST_LOG=debug mles \
--domains your.domain \
--domains www.your.domain \
--cache . \
--wwwroot static
Enable HTTP to HTTPS redirect and use a 100MB compression cache for better performance:
RUST_LOG=debug mles \
--domains your.domain \
--cache . \
--wwwroot static \
--redirect \
--compression-cache 100
For production use, specify contact email for Let's Encrypt:
mles \
--domains your.domain \
--email admin@your.domain \
--cache /var/cache/mles \
--wwwroot /var/www \
--redirect \
--compression-cache 100 \
--limit 500 \
--filelimit 1024
Cap each client IP at 120 new TCP connections per minute across both ports.
Useful when fronting upstream services via --proxy, since abusive IPs are
rejected at TCP accept before reaching the TLS handshake or any upstream:
mles \
--domains your.domain \
--email admin@your.domain \
--cache /var/cache/mles \
--wwwroot /var/www \
--redirect \
--rate-limit 120
An example client session with websocat looks like this:
% websocat wss://mles.io --header "Sec-WebSocket-Protocol: mles-websocket"
{ "uid":"alice", "channel":"example" }
Hello Bob!
mles-client is another example. It also includes a proxy implementation which can be used to connect channels of several servers together in a distributed manner.
Rust
100.0%
Distributed publish-subscribe data service and Mles protocol reference implementation on Rust, Warp and Serde
Rust
167
489 commits
updated Jun 27, 2026
Mles (Modern Lightweight channEl Service) is a client-server data distribution protocol targeted to serve as a lightweight and reliable distributed publish-subscribe data service.
Please check https://mles.io and https://mles.io/blog.html for a generic overview of Mles and /c/mles for the latest news.
Mles clients connect to a Mles server using Mles protocol header first frame (uid, channel, optional auth) value triplet on a TLS [1] WebSocket [2] session where the triplet is encapsulated in JavaScript Object Notation (JSON). A Mles client first subscribes to a channel by sending the correct Mles protocol header first frame value triplet (uid, channel, optional auth) where the channel specifies the channel to publish/subscribe. The auth MAY be included in case authentication is needed on top of WebSocket TLS. A Mles client MUST set Sec-WebSocket-Protocol subprotocol to "mles-websocket" [3] to be able to establish a connection with a Mles server successfully.
The Mles server verifies the Mles protocol header first frame and then joins the Mles client to the selected channel. Every channel uses its own context and is independent of other channels: therefore a TLS session per (uid, channel) pair is always used. After joining, the Mles server distributes the value triplet between all clients on the same channel. If a Mles client wants to depart from a channel, it just closes the WebSocket TLS session. If a Mles client does not want to receive any message, it just closes the WebSocket TLS session receive side.
A Mles server MAY save the history of received data, which can be then distributed to new clients when they connect to the Mles server. In case Mles server is restarted, Mles peer server, or even a Mles client, MAY provide history data for the Mles server as a resynchronization for those channels for which it has the history available. This allows distributed data protection for the channel information. A client SHOULD implement packet deduplication to avoid showing duplicate messages to user.
An Mles proxy-client MAY proxy a selected channel data between several Mles servers. Mles servers see proxy sessions as any other Mles client sessions. A proxy MUST implement packet deduplication to avoid forwarding loops for several proxies on the same channel. This allows Mles proxy-client to share and distribute value triplet data in an organized and powerful, yet simple manner between several Mles servers.
Mles clients and servers are independent of IP version and do not use IP broadcast or multicast. A Mles server MAY be configured to use IP anycast.
The protocol header first frame for Mles is as follows:
{
"uid":"<user identification>",
"channel":"<selected channel>",
"auth":"<optional authentication hash>"
}
Usage: mles [OPTIONS] --domains <DOMAINS> --wwwroot <WWWROOT>
Options:
-d, --domains <DOMAINS>
Domain(s) - can be specified multiple times for multiple domains
-e, --email <EMAIL>
Contact info for Let's Encrypt certificate registration
-c, --cache <CACHE>
Cache directory for Let's Encrypt certificates
-l, --limit <LIMIT>
History limit - maximum number of messages to store per channel
[default: 200]
-f, --filelimit <FILELIMIT>
Open files limit - maximum number of concurrent file handles
[default: 256]
-w, --wwwroot <WWWROOT>
Www-root directory for domain(s)
Structure: /path/static where domain example.io goes to static/example.io
-s, --staging
Use Let's Encrypt staging environment
(see https://letsencrypt.org/docs/staging-environment/)
-p, --port <PORT>
TLS port for WebSocket connections
[default: 443]
-r, --redirect
Enable HTTP to HTTPS redirect on port 80
-C, --compression-cache <COMPRESSION_CACHE>
Compression cache size in MB for static file serving
Set to 0 to disable caching
--rate-limit <RATE_LIMIT>
Per-IP TCP-accept rate limit (connections/minute)
Applies to the TLS port and (when --redirect is set) port 80.
Connections from an IP exceeding the quota are dropped before TLS
handshake. IPv4-mapped IPv6 addresses are normalized so a client
counts as one IP regardless of socket family. Omit to disable.
-h, --help
Print help
static/your.domainRUST_LOG=debug mles --domains your.domain --cache . --wwwroot static
You can serve multiple domains by specifying the --domains flag multiple times:
RUST_LOG=debug mles \
--domains your.domain \
--domains www.your.domain \
--cache . \
--wwwroot static
Enable HTTP to HTTPS redirect and use a 100MB compression cache for better performance:
RUST_LOG=debug mles \
--domains your.domain \
--cache . \
--wwwroot static \
--redirect \
--compression-cache 100
For production use, specify contact email for Let's Encrypt:
mles \
--domains your.domain \
--email admin@your.domain \
--cache /var/cache/mles \
--wwwroot /var/www \
--redirect \
--compression-cache 100 \
--limit 500 \
--filelimit 1024
Cap each client IP at 120 new TCP connections per minute across both ports.
Useful when fronting upstream services via --proxy, since abusive IPs are
rejected at TCP accept before reaching the TLS handshake or any upstream:
mles \
--domains your.domain \
--email admin@your.domain \
--cache /var/cache/mles \
--wwwroot /var/www \
--redirect \
--rate-limit 120
An example client session with websocat looks like this:
% websocat wss://mles.io --header "Sec-WebSocket-Protocol: mles-websocket"
{ "uid":"alice", "channel":"example" }
Hello Bob!
mles-client is another example. It also includes a proxy implementation which can be used to connect channels of several servers together in a distributed manner.
Rust
100.0%