Skip to content

Conversation

DonPrus
Copy link

@DonPrus DonPrus commented Sep 19, 2025

Implements MSC4357 live messaging protocol for real-time message composition in iamb. Messages appear gray while being typed and update in real-time for all room participants.

Features

  • /live <message> command to compose messages that update as you type
  • Live messages appear gray (RGB 100,100,100) to indicate they're still being composed
  • Real-time updates visible to all room participants
  • Messages finalize to normal color when Enter is pressed
  • Rate limiting to prevent excessive server load

Implementation Details

  • Live message detection: Uses org.matrix.msc4357.live marker in message JSON
  • Raw event handling: Preserves custom JSON fields that would be lost during deserialization
  • Session management: LiveMessageManager tracks active live sessions per room
  • Proper edit handling: Only the latest edit determines if a message is live (prevents old messages from appearing gray after restart)

Bug Fixes

  • Fixed issue where all historical edits were processed instead of just the latest one, which caused old messages to incorrectly appear as live after client restart

Changes

  • Added src/message/live.rs - Core live messaging functionality
  • Added src/message/live_detection.rs - Centralized marker detection
  • Modified worker to handle raw message events and track live status
  • Updated chat window to handle /live command and send updates
  • Messages with live marker render in gray color
v02.mov

@DonPrus DonPrus marked this pull request as draft September 19, 2025 01:57
@DonPrus
Copy link
Author

DonPrus commented Sep 19, 2025

I'll double check this at weekends

@VAWVAW
Copy link
Contributor

VAWVAW commented Sep 19, 2025

The notification handler should be modified to exclude live messages.

And can't most of the new logic in worker.rs in load_insert be replaced by looking at the bundled relations of the message?

@DonPrus DonPrus marked this pull request as ready for review September 19, 2025 12:36
@DonPrus
Copy link
Author

DonPrus commented Sep 19, 2025

The notification handler should be modified to exclude live messages.

Fixed! I've added a check to skip notifications for live messages in the notification handler. I didn't catch this during testing because I had notifications disabled in my iamb client. The handler now filters out any events with the org.matrix.msc4357.live marker before sending notifications

And can't most of the new logic in worker.rs in load_insert be replaced by looking at the bundled relations of the message?

I looked into using bundled relations but couldn't find them exposed through the current SDK interface. The events come through as AnyTimelineEvent which doesn't seem to provide access to bundled relations directly. Instead, I simplified the logic by relying on the centralized live detection in load_older_one that checks for the org.matrix.msc4357.live marker in the raw event. If there's a way to access bundled relations that I missed, I'd be happy to refactor further.

@DonPrus DonPrus force-pushed the msc4357-live-messaging branch from 7de4ff0 to 3516f12 Compare September 19, 2025 13:47
Live messages (MSC4357) are now filtered out in the notification handler to prevent notifications for incomplete messages that are still being typed. This fixes the issue where users would receive notifications for messages with just a few letters.

Also simplified the worker.rs load_insert logic by clarifying comments and relying on the centralized live detection.
@DonPrus DonPrus force-pushed the msc4357-live-messaging branch from 3516f12 to af6994f Compare September 19, 2025 13:48
@VAWVAW
Copy link
Contributor

VAWVAW commented Sep 19, 2025

I looked into using bundled relations but couldn't find them exposed through the current SDK interface. The events come through as AnyTimelineEvent which doesn't seem to provide access to bundled relations directly. Instead, I simplified the logic by relying on the centralized live detection in load_older_one that checks for the org.matrix.msc4357.live marker in the raw event. If there's a way to access bundled relations that I missed, I'd be happy to refactor further.

There is RoomMessageEvent::Original.unsigned.relations.replace. We could extract that from the raw message in load_older_one. But I'm not sure whether the server sends these bundled messages for encrypted rooms.

If we can use this, we could filter edits events from the message load to preserve bandwidth and increase load times. With live messages there would be more edit events in the history and only the newest one is important anyway.

@DonPrus
Copy link
Author

DonPrus commented Sep 20, 2025

There is RoomMessageEvent::Original.unsigned.relations.replace. We could extract that from the raw message in load_older_one. But I'm not sure whether the server sends these bundled messages for encrypted rooms.

If we can use this, we could filter edits events from the message load to preserve bandwidth and increase load times. With live messages there would be more edit events in the history and only the newest one is important anyway.

Thanks for pointing me in the right direction! I investigated this further and you're absolutely right - the server does send bundled relations in unsigned.m.relations.m.replace. I added some logging to check what's actually coming through.

The good news is that for unencrypted rooms, the bundled relations contain the full content of the latest edit, which we could definitely use to skip loading intermediate edits. This would be especially helpful for live messages since they may generate so many edits.

The bad news is that for encrypted rooms, the bundled relations only contain the encrypted ciphertext. Makes sense when you think about it - the server can't aggregate content it can't decrypt, so this optimization wouldn't work for E2E encrypted rooms.

There's also a minor SDK limitation - after deserializing to AnyTimelineEvent, we lose direct access to the unsigned.relations field. We'd have to parse the raw JSON like we're already doing for live marker detection.

If you think it's worth it, I could implement this optimization for unencrypted rooms. I'll check for bundled relations in the raw event, track which events already have the latest content bundled, and skip loading the intermediate edits that are superseded. For original messages with bundled edits, we'd apply that content directly instead of waiting for the separate edit events.

@VAWVAW
Copy link
Contributor

VAWVAW commented Sep 21, 2025

The bad news is that for encrypted rooms, the bundled relations only contain the encrypted ciphertext. Makes sense when you think about it - the server can't aggregate content it can't decrypt, so this optimization wouldn't work for E2E encrypted rooms.

Could we use Room::decrypt_event for that?

If you think it's worth it, I could implement this optimization for unencrypted rooms. I'll check for bundled relations in the raw event, track which events already have the latest content bundled, and skip loading the intermediate edits that are superseded. For original messages with bundled edits, we'd apply that content directly instead of waiting for the separate edit events.

It is your PR and I'm not a maintainer so that is your decision.
But I think that this MSC will generate a lot more edit events and we could probably improve the load time if we manage to filter edit events in Room::messages.

Since messages come in reverse chronological order, the first edit we encounter is the latest. This commit:
- Tracks which edits we've already seen the latest version of
- Skips loading older edits when we already have a newer one
- Skips edits for messages that have bundled replacements
- Significantly reduces the number of events to process, especially for live messages

This optimization works for both encrypted and unencrypted rooms, as we're just filtering duplicate edits regardless of content.
@DonPrus
Copy link
Author

DonPrus commented Sep 21, 2025

It is your PR and I'm not a maintainer so that is your decision. But I think that this MSC will generate a lot more edit events and we could probably improve the load time if we manage to filter edit events in Room::messages.

Since messages come in reverse chronological order, the first edit we encounter is the latest. This commit:

  • Tracks which edits we've already seen the latest version
  • Skips loading older edits when we already have a newer one
  • Skips edits for messages that have bundled replacements
  • Significantly reduces the number of events to process, especially for live messages

This optimization works for both encrypted and unencrypted rooms, as we're just filtering duplicate edits regardless of content.

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