summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/api/stream/channel.ts
diff options
context:
space:
mode:
authordakkar <dakkar@thenautilus.net>2025-01-18 16:44:56 +0000
committerdakkar <dakkar@thenautilus.net>2025-01-18 16:44:56 +0000
commitb5d2aea2ac68b2eb4bdd5f09bdc03fcd7c2fa746 (patch)
tree77ea7d8c40f5c19a74bb2e3fe126512a070ce07f /packages/backend/src/server/api/stream/channel.ts
parentmerge: attribute invite codes to admins/moderators (!858) (diff)
parentcomment :3 (diff)
downloadsharkey-b5d2aea2ac68b2eb4bdd5f09bdc03fcd7c2fa746.tar.gz
sharkey-b5d2aea2ac68b2eb4bdd5f09bdc03fcd7c2fa746.tar.bz2
sharkey-b5d2aea2ac68b2eb4bdd5f09bdc03fcd7c2fa746.zip
merge: Clone note when adding myReaction to streamed notes. (!854)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/854 Approved-by: dakkar <dakkar@thenautilus.net> Approved-by: Marie <github@yuugi.dev>
Diffstat (limited to 'packages/backend/src/server/api/stream/channel.ts')
-rw-r--r--packages/backend/src/server/api/stream/channel.ts39
1 files changed, 35 insertions, 4 deletions
diff --git a/packages/backend/src/server/api/stream/channel.ts b/packages/backend/src/server/api/stream/channel.ts
index 93d5046902..047dedd5ce 100644
--- a/packages/backend/src/server/api/stream/channel.ts
+++ b/packages/backend/src/server/api/stream/channel.ts
@@ -103,11 +103,42 @@ export default abstract class Channel {
public onMessage?(type: string, body: JsonValue): void;
- public async assignMyReaction(note: Packed<'Note'>, noteEntityService: NoteEntityService) {
- if (this.user && Object.keys(note.reactions).length > 0) {
- const myReaction = await noteEntityService.populateMyReaction(note, this.user.id);
- note.myReaction = myReaction;
+ public async assignMyReaction(note: Packed<'Note'>, noteEntityService: NoteEntityService): Promise<Packed<'Note'>> {
+ let changed = false;
+ // StreamingApiServerService creates a single EventEmitter per server process,
+ // so a new note arriving from redis gets de-serialised once per server process,
+ // and then that single object is passed to all active channels on each connection.
+ // If we didn't clone the notes here, different connections would asynchronously write
+ // different values to the same object, resulting in a random value being sent to each frontend. -- Dakkar
+ const clonedNote = { ...note };
+ if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
+ if (note.renote && Object.keys(note.renote.reactions).length > 0) {
+ const myReaction = await noteEntityService.populateMyReaction(note.renote, this.user.id);
+ if (myReaction) {
+ changed = true;
+ clonedNote.renote = { ...note.renote };
+ clonedNote.renote.myReaction = myReaction;
+ }
+ }
+ if (note.renote?.reply && Object.keys(note.renote.reply.reactions).length > 0) {
+ const myReaction = await noteEntityService.populateMyReaction(note.renote.reply, this.user.id);
+ if (myReaction) {
+ changed = true;
+ clonedNote.renote = { ...note.renote };
+ clonedNote.renote.reply = { ...note.renote.reply };
+ clonedNote.renote.reply.myReaction = myReaction;
+ }
+ }
}
+ if (this.user && note.reply && Object.keys(note.reply.reactions).length > 0) {
+ const myReaction = await noteEntityService.populateMyReaction(note.reply, this.user.id);
+ if (myReaction) {
+ changed = true;
+ clonedNote.reply = { ...note.reply };
+ clonedNote.reply.myReaction = myReaction;
+ }
+ }
+ return changed ? clonedNote : note;
}
}