This commit is contained in:
syuilo 2025-04-16 13:53:20 +09:00
parent 631715c86e
commit 417969604e
4 changed files with 49 additions and 14 deletions

View File

@ -595,7 +595,7 @@ export class NoteEntityService implements OnModuleInit {
}
@bindThis
public async ogogogo(noteIds: MiNote['id'][]) {
public async fetchDiffs(noteIds: MiNote['id'][]) {
if (noteIds.length === 0) return [];
const notes = await this.notesRepository.find({
@ -603,25 +603,32 @@ export class NoteEntityService implements OnModuleInit {
id: In(noteIds),
},
select: {
id: true,
userHost: true,
reactions: true,
reactionAndUserPairCache: true,
},
});
console.log(notes);
const bufferedReactionsMap = this.meta.enableReactionsBuffering ? await this.reactionsBufferingService.getMany(noteIds) : null;
const results = [];
for (const note of notes) {
const packings = notes.map(note => {
const bufferedReactions = bufferedReactionsMap?.get(note.id);
const reactionAndUserPairCache = note.reactionAndUserPairCache.concat(bufferedReactions.pairs.map(x => x.join('/')));
//const reactionAndUserPairCache = note.reactionAndUserPairCache.concat(bufferedReactions.pairs.map(x => x.join('/')));
results.push({
const reactions = this.reactionService.convertLegacyReactions(this.reactionsBufferingService.mergeReactions(note.reactions, bufferedReactions?.deltas ?? {}));
const reactionEmojiNames = Object.keys(reactions)
.filter(x => x.startsWith(':') && x.includes('@') && !x.includes('@.')) // リモートカスタム絵文字のみ
.map(x => this.reactionService.decodeReaction(x).reaction.replaceAll(':', ''));
return this.customEmojiService.populateEmojis(reactionEmojiNames, note.userHost).then(reactionEmojis => ({
id: note.id,
reactions: this.reactionService.convertLegacyReactions(this.reactionsBufferingService.mergeReactions(note.reactions, bufferedReactions.deltas ?? {})),
});
}
reactions,
reactionEmojis,
}));
});
return await Promise.all(packings);
}
}

View File

@ -317,6 +317,7 @@ export * as 'notes/replies' from './endpoints/notes/replies.js';
export * as 'notes/search' from './endpoints/notes/search.js';
export * as 'notes/search-by-tag' from './endpoints/notes/search-by-tag.js';
export * as 'notes/show' from './endpoints/notes/show.js';
export * as 'notes/show-partial-bulk' from './endpoints/notes/show-partial-bulk.js';
export * as 'notes/state' from './endpoints/notes/state.js';
export * as 'notes/thread-muting/create' from './endpoints/notes/thread-muting/create.js';
export * as 'notes/thread-muting/delete' from './endpoints/notes/thread-muting/delete.js';

View File

@ -38,9 +38,10 @@ export const paramDef = {
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
private noteEntityService: NoteEntityService,
) {
super(meta, paramDef, async (ps, me) => {
return await this.noteEntityService.fetchDiffs(ps.noteIds);
});
}
}

View File

@ -10,6 +10,7 @@ import type { Ref, ShallowRef } from 'vue';
import { useStream } from '@/stream.js';
import { $i } from '@/i.js';
import { store } from '@/store.js';
import { misskeyApi } from '@/utility/misskey-api.js';
const noteEvents = new EventEmitter<{
reacted: Misskey.entities.Note;
@ -18,16 +19,31 @@ const noteEvents = new EventEmitter<{
deleted: Misskey.entities.Note;
}>();
const fetchEvent = new EventEmitter<{
[id: string]: Pick<Misskey.entities.Note, 'reactions' | 'reactionEmojis'>;
}>();
const capturedNoteIdMapForPolling = new Map<string, number>();
const CAPTURE_MAX = 30;
const POLLING_INTERVAL = 1000 * 10;
window.setInterval(() => {
const ids = [...capturedNoteIdMapForPolling.keys()];
const ids = [...capturedNoteIdMapForPolling.keys()].sort((a, b) => (a > b ? -1 : 1)).slice(0, CAPTURE_MAX); // 新しいものを優先するためにIDで降順ソート
if (ids.length === 0) return;
if (window.document.hidden) return;
console.log('Polling notes', ids);
// まとめてリクエストするのではなく、個別にHTTPリクエスト投げてCDNにキャッシュさせた方がサーバーの負荷低減には良いかもしれない
misskeyApi('notes/show-partial-bulk', {
noteIds: ids,
}).then((items) => {
for (const item of items) {
fetchEvent.emit(item.id, {
reactions: item.reactions,
reactionEmojis: item.reactionEmojis,
});
}
});
}, POLLING_INTERVAL);
function pseudoNoteCapture(props: {
@ -43,17 +59,27 @@ function pseudoNoteCapture(props: {
}
function onFetched(data: Pick<Misskey.entities.Note, 'reactions' | 'reactionEmojis'>): void {
note.value.reactions = data.reactions;
note.value.reactionCount = Object.values(data.reactions).reduce((a, b) => a + b, 0);
note.value.reactionEmojis = data.reactionEmojis;
}
if (capturedNoteIdMapForPolling.has(note.value.id)) {
capturedNoteIdMapForPolling.set(note.value.id, capturedNoteIdMapForPolling.get(note.value.id)! + 1);
} else {
capturedNoteIdMapForPolling.set(note.value.id, 1);
}
fetchEvent.on(note.value.id, onFetched);
onUnmounted(() => {
capturedNoteIdMapForPolling.set(note.value.id, capturedNoteIdMapForPolling.get(note.value.id)! - 1);
if (capturedNoteIdMapForPolling.get(note.value.id) === 0) {
capturedNoteIdMapForPolling.delete(note.value.id);
}
fetchEvent.off(note.value.id, onFetched);
});
}