diff options
| author | dakkar <dakkar@thenautilus.net> | 2025-01-18 16:44:56 +0000 |
|---|---|---|
| committer | dakkar <dakkar@thenautilus.net> | 2025-01-18 16:44:56 +0000 |
| commit | b5d2aea2ac68b2eb4bdd5f09bdc03fcd7c2fa746 (patch) | |
| tree | 77ea7d8c40f5c19a74bb2e3fe126512a070ce07f /packages/backend/src/server/api/stream/channel.ts | |
| parent | merge: attribute invite codes to admins/moderators (!858) (diff) | |
| parent | comment :3 (diff) | |
| download | sharkey-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.ts | 39 |
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; } } |