Skip to content

feat(dm): one moss node for every conversation - #37

Merged
ForeverInLaw merged 1 commit into
mainfrom
feat/one-node-for-every-dm
Jul 29, 2026
Merged

feat(dm): one moss node for every conversation#37
ForeverInLaw merged 1 commit into
mainfrom
feat/one-node-for-every-dm

Conversation

@ForeverInLaw

Copy link
Copy Markdown
Contributor

Why

Each session started its own moss node. Node identity is per process (the keystore is a process global), so N open conversations meant N nodes presenting the same peer id from N ports. A remote peer keeps one session per identity: it closed the rest on arrival, and declined to dial the others at all because it already held that id.

Measured over three days, mosh clients only:

node sessions dead <1s discarded handshakes/hour
A 15,494 14,799 205
B 9,772 9,419 131
C 8,527 8,112 113

95%+ of sessions dead inside a second, against 6–8 distinct peers each. One identity on 27 ports inside one hour. That is what users hit as "the chat only works once I close every other chat".

What changed

Sessions share one node, refcounted exactly like the existing relay node (ensure_relay_up / release_relay), and separate themselves by room using moss v0.8.19's per-room subscribe/publish. A joined room is byte-identical to the same room owned outright, so this stays wire-compatible with every already-released client.

Three things the shared node forced into the open:

  • unsubscribe was never bound. Moss_Unsubscribe has existed in the FFI all along; unsubscribe_voice_call was a stub returning Ok(()). With a node per session that was harmless — dropping the node ended its subscriptions. Now a closed conversation must say so or it keeps receiving forever. Bound, and close_session leaves the room.
  • publish_room needed publish's tolerance for "no peers yet", or every message sent before the mesh forms is marked Failed. (Caught by the existing suite.)
  • mesh_info reports the whole node, so one chat's diagnostics listed every other chat's channels. Filtered to the session's own; peer lists stay whole because has_live_peer matches the counterpart by id against them.

Verification

  • New sessions_share_one_node_and_close_releases_it: two conversations, one node, separate rooms; closing one keeps the node up, closing the last takes it down.
  • Live moss E2E on the shared node: attachment transfer and voice call both pass.
  • 187 unit tests, clippy --all-targets -D warnings, src-tauri checks.
  • A pre-v0.8.19 library fails cleanly (Moss symbol unavailable: Moss_JoinRoom), verified against the released v0.8.18 dll — not a crash.

Known, not caused here

private_dm_runtime_exchanges_e2ee_message_over_moss (#[ignore]d) fails. Verified it fails identically on unchanged main and against the v0.8.18 library, so it predates this work: both test runtimes drain one process-global inbound queue, and whichever polls first consumes the delivery ack. Left alone rather than folded into this change.

Each session started its own moss node. Node identity is per process — the
keystore is a process global — so N open conversations meant N nodes presenting
the SAME peer id from N ports. A remote peer keeps one session per identity: it
closed the rest on arrival and declined to dial the others at all, because it
already held that id.

Measured across three clients over three days: 33,715 sessions, 32,330 of them
dead inside one second (95%), sustained at 205 / 131 / 113 discarded Noise
handshakes an hour against only 6-8 distinct peers each. One identity was seen
on 27 different ports within a single hour. That is what users experienced as a
chat that only worked once every other chat was closed.

Sessions now share one node (refcounted exactly like the relay node) and
separate themselves by room, using moss v0.8.19's per-room subscribe/publish.
A joined room is byte-identical to the same room owned outright, so this stays
wire-compatible with every already-released client.

Three things the shared node forced into the open:

  - `unsubscribe` was never bound. The FFI has exposed Moss_Unsubscribe all
    along; mosh's `unsubscribe_voice_call` was a stub returning Ok(()). With a
    node per session it did not matter, because dropping the node ended its
    subscriptions. Now a closed conversation must say so, or it keeps
    receiving forever. Bound, and close_session leaves the room.

  - `publish_room` needed the same "no peers yet is not a failure" tolerance as
    `publish`, or every message sent before the mesh forms is marked Failed.

  - `mesh_info` reports the whole node, so one chat's diagnostics listed every
    other chat's channels. Filtered to the session's own. Peer lists stay whole
    on purpose — has_live_peer matches the counterpart by id against them.

Verified on live moss: attachment transfer and voice call E2E both pass on the
shared node, plus 187 unit tests and clippy -D warnings.
@ForeverInLaw
ForeverInLaw merged commit 91b866a into main Jul 29, 2026
3 checks passed
@ForeverInLaw
ForeverInLaw deleted the feat/one-node-for-every-dm branch July 29, 2026 01:16
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.

1 participant