Skip to content

Commit

Permalink
fix(backend): RBTの修正 (#14621)
Browse files Browse the repository at this point in the history
* fix(backend): 絵文字の変換処理が不十分なのを修正

* enhance: リアクションバッファリングが無効になったら即bakeするように

* attempt to fix test

* fix
  • Loading branch information
kakkokari-gtyih authored Sep 24, 2024
1 parent 1d8bfe4 commit 6a1a2be
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 40 deletions.
4 changes: 2 additions & 2 deletions packages/backend/src/GlobalModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ const $meta: Provider = {
const { type, body } = obj.message as GlobalEvents['internal']['payload'];
switch (type) {
case 'metaUpdated': {
for (const key in body) {
(meta as any)[key] = (body as any)[key];
for (const key in body.after) {
(meta as any)[key] = (body.after as any)[key];
}
meta.proxyAccount = null; // joinなカラムは通常取ってこないので
break;
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/core/GlobalEventService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ export interface InternalEventTypes {
avatarDecorationCreated: MiAvatarDecoration;
avatarDecorationDeleted: MiAvatarDecoration;
avatarDecorationUpdated: MiAvatarDecoration;
metaUpdated: MiMeta;
metaUpdated: { before?: MiMeta; after: MiMeta; };
followChannel: { userId: MiUser['id']; channelId: MiChannel['id']; };
unfollowChannel: { userId: MiUser['id']; channelId: MiChannel['id']; };
updateUserProfile: MiUserProfile;
Expand Down
4 changes: 2 additions & 2 deletions packages/backend/src/core/MetaService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class MetaService implements OnApplicationShutdown {
switch (type) {
case 'metaUpdated': {
this.cache = { // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい
...body,
...(body.after),
proxyAccount: null, // joinなカラムは通常取ってこないので
};
break;
Expand Down Expand Up @@ -141,7 +141,7 @@ export class MetaService implements OnApplicationShutdown {
});
}

this.globalEventService.publishInternalEvent('metaUpdated', updated);
this.globalEventService.publishInternalEvent('metaUpdated', { before, after: updated });

return updated;
}
Expand Down
28 changes: 15 additions & 13 deletions packages/backend/src/core/ReactionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,10 +337,22 @@ export class ReactionService {
//#endregion
}

/**
* - 文字列タイプのレガシーな形式のリアクションを現在の形式に変換する
* - ローカルのリアクションのホストを `@.` にする(`decodeReaction()`の効果)
*/
@bindThis
public convertLegacyReaction(reaction: string): string {
reaction = this.decodeReaction(reaction).reaction;
if (Object.keys(legacies).includes(reaction)) return legacies[reaction];
return reaction;
}

// TODO: 廃止
/**
* 文字列タイプのレガシーな形式のリアクションを現在の形式に変換しつつ、
* データベース上には存在する「0個のリアクションがついている」という情報を削除する。
* - 文字列タイプのレガシーな形式のリアクションを現在の形式に変換する
* - ローカルのリアクションのホストを `@.` にする(`decodeReaction()`の効果)
* - データベース上には存在する「0個のリアクションがついている」という情報を削除する
*/
@bindThis
public convertLegacyReactions(reactions: MiNote['reactions']): MiNote['reactions'] {
Expand All @@ -353,10 +365,7 @@ export class ReactionService {
return count > 0;
})
.map(([reaction, count]) => {
// unchecked indexed access
const convertedReaction = legacies[reaction] as string | undefined;

const key = this.decodeReaction(convertedReaction ?? reaction).reaction;
const key = this.convertLegacyReaction(reaction);

return [key, count] as const;
})
Expand Down Expand Up @@ -411,11 +420,4 @@ export class ReactionService {
host: undefined,
};
}

@bindThis
public convertLegacyReaction(reaction: string): string {
reaction = this.decodeReaction(reaction).reaction;
if (Object.keys(legacies).includes(reaction)) return legacies[reaction];
return reaction;
}
}
51 changes: 50 additions & 1 deletion packages/backend/src/core/ReactionsBufferingService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,48 @@ import { bindThis } from '@/decorators.js';
import type { MiUser, NotesRepository } from '@/models/_.js';
import type { Config } from '@/config.js';
import { PER_NOTE_REACTION_USER_PAIR_CACHE_MAX } from '@/const.js';
import type { GlobalEvents } from '@/core/GlobalEventService.js';
import type { OnApplicationShutdown } from '@nestjs/common';

const REDIS_DELTA_PREFIX = 'reactionsBufferDeltas';
const REDIS_PAIR_PREFIX = 'reactionsBufferPairs';

@Injectable()
export class ReactionsBufferingService {
export class ReactionsBufferingService implements OnApplicationShutdown {
constructor(
@Inject(DI.config)
private config: Config,

@Inject(DI.redisForSub)
private redisForSub: Redis.Redis,

@Inject(DI.redisForReactions)
private redisForReactions: Redis.Redis, // TODO: 専用のRedisインスタンスにする

@Inject(DI.notesRepository)
private notesRepository: NotesRepository,
) {
this.redisForSub.on('message', this.onMessage);
}

@bindThis
private async onMessage(_: string, data: string) {
const obj = JSON.parse(data);

if (obj.channel === 'internal') {
const { type, body } = obj.message as GlobalEvents['internal']['payload'];
switch (type) {
case 'metaUpdated': {
// リアクションバッファリングが有効→無効になったら即bake
if (body.before != null && body.before.enableReactionsBuffering && !body.after.enableReactionsBuffering) {
this.bake();
}
break;
}
default:
break;
}
}
}

@bindThis
Expand Down Expand Up @@ -159,4 +185,27 @@ export class ReactionsBufferingService {
.execute();
}
}

@bindThis
public mergeReactions(src: MiNote['reactions'], delta: Record<string, number>): MiNote['reactions'] {
const reactions = { ...src };
for (const [name, count] of Object.entries(delta)) {
if (reactions[name] != null) {
reactions[name] += count;
} else {
reactions[name] = count;
}
}
return reactions;
}

@bindThis
public dispose(): void {
this.redisForSub.off('message', this.onMessage);
}

@bindThis
public onApplicationShutdown(signal?: string | undefined): void {
this.dispose();
}
}
24 changes: 3 additions & 21 deletions packages/backend/src/core/entities/NoteEntityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,12 @@ import { bindThis } from '@/decorators.js';
import { DebounceLoader } from '@/misc/loader.js';
import { IdService } from '@/core/IdService.js';
import { ReactionsBufferingService } from '@/core/ReactionsBufferingService.js';
import { MetaService } from '@/core/MetaService.js';
import type { OnModuleInit } from '@nestjs/common';
import type { CustomEmojiService } from '../CustomEmojiService.js';
import type { ReactionService } from '../ReactionService.js';
import type { UserEntityService } from './UserEntityService.js';
import type { DriveFileEntityService } from './DriveFileEntityService.js';

function mergeReactions(src: Record<string, number>, delta: Record<string, number>) {
const reactions = { ...src };
for (const [name, count] of Object.entries(delta)) {
if (reactions[name] != null) {
reactions[name] += count;
} else {
reactions[name] = count;
}
}
return reactions;
}

@Injectable()
export class NoteEntityService implements OnModuleInit {
private userEntityService: UserEntityService;
Expand Down Expand Up @@ -329,12 +316,7 @@ export class NoteEntityService implements OnModuleInit {
: this.meta.enableReactionsBuffering
? await this.reactionsBufferingService.get(note.id)
: { deltas: {}, pairs: [] };
const reactions = mergeReactions(this.reactionService.convertLegacyReactions(note.reactions), bufferedReactions.deltas ?? {});
for (const [name, count] of Object.entries(reactions)) {
if (count <= 0) {
delete reactions[name];
}
}
const reactions = this.reactionService.convertLegacyReactions(this.reactionsBufferingService.mergeReactions(note.reactions, bufferedReactions.deltas ?? {}));

const reactionAndUserPairCache = note.reactionAndUserPairCache.concat(bufferedReactions.pairs.map(x => x.join('/')));

Expand Down Expand Up @@ -451,7 +433,7 @@ export class NoteEntityService implements OnModuleInit {

for (const note of notes) {
if (note.renote && (note.text == null && note.fileIds.length === 0)) { // pure renote
const reactionsCount = Object.values(mergeReactions(note.renote.reactions, bufferedReactions?.get(note.renote.id)?.deltas ?? {})).reduce((a, b) => a + b, 0);
const reactionsCount = Object.values(this.reactionsBufferingService.mergeReactions(note.renote.reactions, bufferedReactions?.get(note.renote.id)?.deltas ?? {})).reduce((a, b) => a + b, 0);
if (reactionsCount === 0) {
myReactionsMap.set(note.renote.id, null);
} else if (reactionsCount <= note.renote.reactionAndUserPairCache.length + (bufferedReactions?.get(note.renote.id)?.pairs.length ?? 0)) {
Expand All @@ -467,7 +449,7 @@ export class NoteEntityService implements OnModuleInit {
}
} else {
if (note.id < oldId) {
const reactionsCount = Object.values(mergeReactions(note.reactions, bufferedReactions?.get(note.id)?.deltas ?? {})).reduce((a, b) => a + b, 0);
const reactionsCount = Object.values(this.reactionsBufferingService.mergeReactions(note.reactions, bufferedReactions?.get(note.id)?.deltas ?? {})).reduce((a, b) => a + b, 0);
if (reactionsCount === 0) {
myReactionsMap.set(note.id, null);
} else if (reactionsCount <= note.reactionAndUserPairCache.length + (bufferedReactions?.get(note.id)?.pairs.length ?? 0)) {
Expand Down

0 comments on commit 6a1a2be

Please sign in to comment.