From e288d56181160db4e363bc46a4a55ef06c3a2c03 Mon Sep 17 00:00:00 2001 From: tamaina Date: Wed, 26 Jul 2023 16:40:42 +0000 Subject: [PATCH] perf(frontend): Notes Manager --- .../frontend/src/scripts/entity-manager.ts | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 packages/frontend/src/scripts/entity-manager.ts diff --git a/packages/frontend/src/scripts/entity-manager.ts b/packages/frontend/src/scripts/entity-manager.ts new file mode 100644 index 0000000000..269c143b0e --- /dev/null +++ b/packages/frontend/src/scripts/entity-manager.ts @@ -0,0 +1,94 @@ +import { Note, UserLite } from "misskey-js/built/entities"; +import { Ref, ref, ComputedRef, computed } from "vue"; +import { api } from "./api"; + +export class EntitiyManager { + private entities: Map>; + + constructor() { + this.entities = new Map(); + } + + public set(item: T): Ref { + const cached = this.entities.get(item.id); + if (cached) { + cached.value = item; + } else { + this.entities.set(item.id, ref(item) as Ref); + } + return this.get(item.id)!; + } + + public get(id: string): Ref | undefined { + return this.entities.get(id); + } +} + +export const userLiteManager = new EntitiyManager(); + +type OmittedNote = Omit; +type InternalCachedNote = Ref; + +export class NoteManager { + private notes: Map; + private updatedAt: Map; + private captureing: Map; + + constructor() { + this.notes = new Map(); + this.updatedAt = new Map(); + this.captureing = new Map(); + } + + public set(_note: Note): ComputedRef { + const note: Note = { ..._note }; + userLiteManager.set(note.user); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + //@ts-ignore + delete note.user; + if (note.renote) this.set(note.renote); + delete note.renote; + if (note.reply) this.set(note.reply); + delete note.reply; + const cached = this.notes.get(note.id); + if (cached) { + cached.value = note; + } else { + this.notes.set(note.id, ref(note)); + } + this.updatedAt.set(note.id, Date.now()); + return this.get(note.id)!; + } + + public get(id: string): ComputedRef | undefined { + const note: InternalCachedNote | undefined = this.notes.get(id); + if (!note) return undefined; + + return computed(() => { + const user = userLiteManager.get(note.value.userId)!; + const renote = note.value.renoteId ? this.get(note.value.renoteId) : undefined; + const reply = note.value.replyId ? this.get(note.value.replyId) : undefined; + + return { + ...note.value, + user: user.value, + renote: renote?.value, + reply: reply?.value, + }; + }); + } + + public async fetch(id: string, force = false): Promise> { + if (!force) { + const updatedAt = this.updatedAt.get(id); + if (updatedAt && Date.now() - updatedAt < 1000 * 30) { + const cachedNote = this.get(id); + if (cachedNote) { + return cachedNote as ComputedRef; + } + } + } + const fetchedNote = await api('notes/show', { noteId: id }); + return this.set(fetchedNote); + } +}