Skip to content

feat: HTTP mailbox transport and mailbox-relay - #45

Open
osmaczko wants to merge 3 commits into
masterfrom
feat/mailbox-transport
Open

feat: HTTP mailbox transport and mailbox-relay#45
osmaczko wants to merge 3 commits into
masterfrom
feat/mailbox-transport

Conversation

@osmaczko

@osmaczko osmaczko commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

The point of the mailbox is a reliable transport to run chat on: it lets the
protocol be exercised under perfect delivery conditions first, where problems
are far easier to catch, and the wire swaps for the production logos-delivery
transport once the protocol is solid.

refactor: rename SdkDelivery to LogosDelivery

The transport is named for the logos-delivery network it carries chat over, not
for the logos-rust-sdk it dispatches through; SdkDelivery described the plumbing,
LogosDelivery describes what it is.

feat(relay): add mailbox-relay, a centralized HTTP transport for testing

A standalone axum + sqlite relay that stands in for the delivery_module wire
when testing across machines, where the real delivery network is unreliable.
Each delivery topic is an append-only log: publishers POST sealed envelopes and
subscribers long-poll past a per-topic cursor. Payloads stay opaque (MLS
ciphertext), so the relay only ever sees metadata.

Lives in its own crate under tools/ with no chat dependencies, plus a dedicated
bare-cargo CI job (fmt, clippy, test). Deploy recipes and a curl debugging
cookbook are in its README.

feat: route chat over an HTTP mailbox transport

init gains a 4th param, transport_url: an empty value keeps the delivery_module
wire (configured by delivery_preset/tcp_port); a URL routes through the mailbox
relay instead, over reqwest blocking + rustls (reusing HttpRegistry's exact
config, so the dependency graph stays single-reqwest). The client is generic
over one transport, so the two impls sit behind a ModuleTransport enum; MLS, the
key-package registry, and everything above the transport are untouched.

The transport's poller and sender threads are spawned only after the fallible
client build and registry publish succeed, so a failure there strands nothing.

init's lidl signature gains the param, so the scaffold regenerates from the lidl
at build time and the module doc-test passes the new empty 4th arg; the contract
version is left unbumped while the module is pre-release.

osmaczko added 3 commits July 7, 2026 21:04
The transport is named for the logos-delivery network it carries chat over, not
for the logos-rust-sdk it dispatches through; SdkDelivery described the plumbing,
LogosDelivery describes what it is.
A standalone axum + sqlite relay that stands in for the delivery_module wire
when testing across machines, where the real delivery network is unreliable.
Each delivery topic is an append-only log: publishers POST sealed envelopes and
subscribers long-poll past a per-topic cursor. Payloads stay opaque (MLS
ciphertext), so the relay only ever sees metadata.

Lives in its own crate under tools/ with no chat dependencies, plus a dedicated
bare-cargo CI job (fmt, clippy, test). Deploy recipes and a curl debugging
cookbook are in its README.
init gains a 4th param, transport_url: an empty value keeps the delivery_module
wire (configured by delivery_preset/tcp_port); a URL routes through the mailbox
relay instead, over reqwest blocking + rustls (reusing HttpRegistry's exact
config, so the dependency graph stays single-reqwest). The client is generic
over one transport, so the two impls sit behind a ModuleTransport enum; MLS, the
key-package registry, and everything above the transport are untouched.

The transport's poller and sender threads are spawned only after the fallible
client build and registry publish succeed, so a failure there strands nothing.

init's lidl signature gains the param, so the scaffold regenerates from the lidl
at build time and the module doc-test passes the new empty 4th arg; the contract
version is left unbumped while the module is pre-release.
@osmaczko
osmaczko force-pushed the feat/mailbox-transport branch from 532d575 to 221db94 Compare July 7, 2026 19:07
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

Doc-test report

Two headless chat_module instances built against this commit, driven through the full message round-trip, rendered alongside the commands actually run and their output (updated each run, commit 55422a2):

Pages can take a minute to update after the run finishes.

@osmaczko
osmaczko marked this pull request as ready for review July 7, 2026 19:09
@osmaczko
osmaczko requested review from igor-sirotin and jazzz July 7, 2026 19:09
Comment on lines +1 to +4
# Standalone crate: the module repo root has no workspace, but rust-lib declares
# its own, so declare an empty one here too and never get adopted by a parent.
# Zero chat dependencies, so this can be extracted to its own repo later.
[workspace]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Pebble] this is a strong sign that this service doesn't belong in this repo.

Current model is that services live in their own repos

Comment thread rust-lib/chat_module.lidl
Comment on lines +37 to +41
; transport_url selects the wire: empty uses delivery_module (configured by
; delivery_preset/tcp_port); a URL (e.g. https://user:token@relay.example.com)
; routes through a centralized HTTP mailbox relay instead, ignoring
; delivery_preset/tcp_port. See tools/mailbox-relay.
method init(instance_path: tstr, delivery_preset: tstr, tcp_port: int, transport_url: tstr) -> result

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Boulder] Adding this configuration parameter adds fragmentation, and developer ambiguity. Suggest removing.

Creating fragmentation points exponentially increases desynchronization bugs. Allowing developers to choose a different delivery mechanism easily will result in missed messages, conversations being corrupted (Once persistence lands), Account corruption, and an a whole host of UX issues.

The primary goal at this time, is iterop - Keeping all users across all application able to communicate. LogosChat needs to be opinionated in order to stop developers from fragmenting the participant graph.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would even push back that the module should not expose delivery_preset either.

While there is no cost, there should only be one network that developers can use. I don't care which one, but having applications that support different delivery networks will cause untold headaches.

If its truly truly needed, I'd want to find a API shape that allows most developers to choose "the default" option, without causing confusion at the highlevel api.

Comment thread rust-lib/src/mailbox.rs
Comment on lines +1 to +4
//! HTTP mailbox transport: an alternative to the delivery_module path that
//! reaches peers through a centralized relay (see `tools/mailbox-relay`).
//! Selected at init by a non-empty `transport_url`; the delivery_module path is
//! left untouched when it's empty.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At a High level I'm not sure I support this change/ Concept.

  1. Reliability bugs are the most important ones to find. The focus should be on amplifying them, not hiding them. Historically these have been the hardest to discover, delaying that discovery process means the project will take longer to be ready to use.

    "and the wire swaps for the production logos-delivery transport once the protocol is solid."

    The protocol needs to operate safely under un-reliable conditions. Even with "ReliableChannels", completely reliable delivery cannot be assumed. The protocol needs to be tolerant to faults. The only way to build that is to do the work and deal with them, rather than avoid and hide them.

    I may even go as far to say, it would be advantageous to purposely drop messages stochastically (a la ChaosMonkey™ ) to show where the protocol is weak.

  2. If this is beneficial for testing then lets move the client to components/delivery. Which allows Contributors to use it for testing. The LogosChat module is intended for developers who want to build apps.

  3. This complicates the public interface, and makes managing changes more difficult in the future.
    This conversation mirrors feat: default transport for logos chat client logos-messaging/libchat#159 (comment) which is facing the same decisions only for LogosChatClient instead of the module.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open to pushback here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants