broadcast channel reactions - #8450
Merged
Merged
Conversation
r10s
force-pushed
the
r10s/channel-reactions
branch
30 times, most recently
from
July 25, 2026 20:28
c8015bc to
8831752
Compare
this reverts 4c75f2d, esp. in small channels, it is weird that there is an additional person reacting, always then minutes after you reacted with the same reaction. a ghost 👻
…ications for reactions is usually not wanted
Co-authored-by: l <link2xt@testrun.org>
…e one call to time()
Co-authored-by: l <link2xt@testrun.org>
r10s
force-pushed
the
r10s/channel-reactions
branch
from
August 4, 2026 15:57
9a00f18 to
7c7f074
Compare
Contributor
Author
rebased, so that can be squash-merged once CI is through |
r10s
added a commit
that referenced
this pull request
Aug 5, 2026
the UIs are currently advised to only allow the five default reactions in broadcast channels. this PR ensures that from sending site as well as receiving site. soon, we probably want to make the possible reactions configurable, this PR is mainly for some safety until then. once we have an API to change default reactions, we can also easily test "invalid" reactions on the receiving side; currently only sending is tested successor of #8450 --------- Co-authored-by: Jagoda Estera Ślązak <128227338+j-g00da@users.noreply.github.com>
hpk42
pushed a commit
that referenced
this pull request
Aug 10, 2026
this PR adds support for reactions in broadcast channels.
> the idea of broadcast reactions is that they are sent as usual from
subscribers to owner. after some time, the owner broadcasts them to all
subscribers, who only get to see reaction+count, not who-reacted-what
the PR is quite large, but a good share are tests and otherwise many
things are straight forward.
review should be done by-file, not by-commit. to make review easier,
here is a high-level overview:
first a change in the existing internal `Reactions` object was required.
before this PR, `Reactions` had a "contact to reaction map" only, and
the "frequencies map", that are actually mainly needed for UI, were
calculated as needed. with this PR, the "frequencies map" is the field
that always exist, the "contact map" is only available on top of that.
moreover, this PR shifts that part to the core, it was unfortunately in
the bindings before.
with that preparation things done as follows:
1. reactions from broadcast channel subscriber (`Chattype::InBroadcast`)
to broadcast channel owner (`Chattype::OutBroadcast`) are sent as usual,
only change for that step was to allow sending them at all
2. the owner receives reactions and saves them to the existing
`reactions` table as usual. additionally, the changed message is
remembered in `reactions_need_broadcast` table
3. in the IMAP loop, when ~10 minutes have passed, and
`reactions_need_broadcast` contains entries, a single, hidden message
with accumulated reactions is sent. this message may contain reactions
to different messages. for each message, all known reactions are sent as
reaction+count.
4. subscriber receive that message and save the accumulated reactions in
`reactions_broadcasted`
6. `get_message_reactions` is adapted so that `frequencies` are set
independently of who-reacted-what (the old and only field).
who-reacted-what is called `by_contact` now. it is always set for
compatibility reasons, however, it is not exhaustive for subscribers.
in general, UI should work with frequencies, the API itself, however,
has not changed.
other tweaks:
- outgoing channels are muted on creation, and UI shall allow to
unmute/mute them as all other chats. reason is that reactions are
notified, but in many cases not of large interest. this is also what
telegram is doing
- to have an intermediate feedback when reacting, the local state should
include ones own reaction, even if it is not yet broadcasted. for that,
we modify `reactions_broadcasted` using `modify_frequencies()` as needed
when sending an reaction. there are still some situations where the
update may not include ones own reaction, in this case it is added
lately by `refine_frequencies()`, so that `get_message_reactions()`
always contain SELF.
(in a first implementation, we always increased SELF reaction in
refine_frequencies(), however, that was worse and led to SELF counted
twice once the owner sent broadcast)
<details>
<summary>wire format</summary>
wire format is a JSON in the `Broadcast-Reactions:` header.
additionally, `Content-Disposition: reaction` is set to not show the
hidden message on existing devices.
using a header also allows us to broadcast reactions with resent channel
messages (on joining) later.
```
{
"messages": [
{
"id": "12345678",
"reactions": [
{ "emoji": "👍", "count": 4 },
{ "emoji": "🎉", "count": 2 }
]
},
{
"id": "23456789",
"reactions": []
}
]
}
```
for `id`, the wire format needs to use `rfc724_mid` as `msg_id` are
local only.
</details>
### known issues
- if the channel owner uses multiple devices, broadcasted reaction
updates are sent from each device. the updates are not that big, so that
is probably not a big deal. if it turns out that this is an issue, we
can think about fixes in another PR. might be done by restarting our
10-minute-wait once we see an update from another device
- we cannot set contact_id for DC_EVENT_REACTIONS_CHANGED - but i doubt
it was ever used
### for another pr
- ~~add `Broadcast-Reactions:` header also for resent channel messages,
so that new subscriber do not only get the latest messages, but also
their reactions. for that, the `Broadcast-Reactions:` header can go to
the corresponding message, no need to send extra messages. we would need
to change the sending part to send all reactions for a given message. on
receiving part, we need to make sure, `receive_broadcast_reactions()` is
called when the message actually exist.~~
EDIT: subsequent PR for resending broadcast reactions at
#8496
- add api to allow only a subset of reactions, fiter incoming reactions
before broadcasting
### misc.
ui pr: deltachat/deltachat-ios#3225 and
deltachat/deltachat-android#4560 , which both
were tested successfully with this core PR already. desktop is meant to
be done once this is merged
---------
Co-authored-by: l <link2xt@testrun.org>
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
this PR adds support for reactions in broadcast channels.
the PR is quite large, but a good share are tests and otherwise many things are straight forward.
review should be done by-file, not by-commit. to make review easier, here is a high-level overview:
first a change in the existing internal
Reactionsobject was required. before this PR,Reactionshad a "contact to reaction map" only, and the "frequencies map", that are actually mainly needed for UI, were calculated as needed. with this PR, the "frequencies map" is the field that always exist, the "contact map" is only available on top of that.moreover, this PR shifts that part to the core, it was unfortunately in the bindings before.
with that preparation, things are done as follows:
reactions from broadcast channel subscriber (
Chattype::InBroadcast) to broadcast channel owner (Chattype::OutBroadcast) are sent as usual, only change for that step was to allow sending them at allthe owner receives reactions and saves them to the existing
reactionstable as usual. additionally, the changed message is remembered inreactions_need_broadcasttablein the IMAP loop, when ~10 minutes have passed, and
reactions_need_broadcastcontains entries, a single, hidden message with accumulated reactions is sent. this message may contain reactions to different messages. for each message, all known reactions are sent as reaction+count.subscriber receive that message and save the accumulated reactions in
reactions_broadcastedget_message_reactionsis adapted so thatfrequenciesare set independently of who-reacted-what (the old and only field). who-reacted-what is calledby_contactnow. it is always set for compatibility reasons, however, it is not exhaustive for subscribers.in general, UI should work with frequencies, the API itself, however, has not changed.
other tweaks:
outgoing channels are muted on creation, and UI shall allow to unmute/mute them as all other chats. reason is that reactions are notified, but in many cases not of large interest. this is also what telegram is doing
to have an intermediate feedback when reacting, the local state should include ones own reaction, even if it is not yet broadcasted. for that, we modify
reactions_broadcastedusingmodify_frequencies()as needed when sending an reaction. there are still some situations where the update may not include ones own reaction, in this case it is added lately byrefine_frequencies(), so thatget_message_reactions()always contain SELF.(in a first implementation, we always increased SELF reaction in refine_frequencies(), however, that was worse and led to SELF counted twice once the owner sent broadcast)
wire format
wire format is a JSON in the
Broadcast-Reactions:header. additionally,Content-Disposition: reactionis set to not show the hidden message on existing devices.using a header also allows us to broadcast reactions with resent channel messages (on joining) later.
for
id, the wire format needs to userfc724_midasmsg_idare local only.known issues
if the channel owner uses multiple devices, broadcasted reaction updates are sent from each device. the updates are not that big, so that is probably not a big deal. if it turns out that this is an issue, we can think about fixes in another PR. might be done by restarting our 10-minute-wait once we see an update from another device
we cannot set contact_id for DC_EVENT_REACTIONS_CHANGED - but i doubt it was ever used
for another pr
addBroadcast-Reactions:header also for resent channel messages, so that new subscriber do not only get the latest messages, but also their reactions. for that, theBroadcast-Reactions:header can go to the corresponding message, no need to send extra messages. we would need to change the sending part to send all reactions for a given message. on receiving part, we need to make sure,receive_broadcast_reactions()is called when the message actually exist.EDIT: subsequent PR for resending broadcast reactions at resend broadcast reactions together with message #8496
add api to allow only a subset of reactions, fiter incoming reactions before broadcasting
misc.
ui pr: deltachat/deltachat-ios#3225 and deltachat/deltachat-android#4560 , which both were tested successfully with this core PR already. desktop is meant to be done once this is merged