This commit is contained in:
parent
956b197316
commit
a2c130a484
|
@ -14,6 +14,7 @@ import { deepClone } from "./clone";
|
||||||
import { shouldCollapsed } from "./collapsed";
|
import { shouldCollapsed } from "./collapsed";
|
||||||
import { extractUrlFromMfm } from "./extract-url-from-mfm";
|
import { extractUrlFromMfm } from "./extract-url-from-mfm";
|
||||||
import * as mfm from 'mfm-js';
|
import * as mfm from 'mfm-js';
|
||||||
|
import { isDebuggerEnabled } from "@/debug";
|
||||||
|
|
||||||
export class EntitiyManager<T extends { id: string }> {
|
export class EntitiyManager<T extends { id: string }> {
|
||||||
private entities: Map<T['id'], Ref<T>>;
|
private entities: Map<T['id'], Ref<T>>;
|
||||||
|
@ -81,6 +82,7 @@ export class NoteManager {
|
||||||
private updatedAt: Map<Note['id'], number>;
|
private updatedAt: Map<Note['id'], number>;
|
||||||
private captureing: Map<Note['id'], number>;
|
private captureing: Map<Note['id'], number>;
|
||||||
private connection: Stream | null;
|
private connection: Stream | null;
|
||||||
|
private isDebuggerEnabled: boolean;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.notesSource = new Map();
|
this.notesSource = new Map();
|
||||||
|
@ -100,12 +102,15 @@ export class NoteManager {
|
||||||
this.connection?.send('s', { id });
|
this.connection?.send('s', { id });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.isDebuggerEnabled = isDebuggerEnabled(6865);
|
||||||
}
|
}
|
||||||
|
|
||||||
public set(_note: Note): void {
|
public set(_note: Note): void {
|
||||||
const note: Note = { ..._note };
|
const note: Note = { ..._note };
|
||||||
|
|
||||||
userLiteManager.set(note.user);
|
userLiteManager.set(note.user);
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: set user', note.userId, userLiteManager.get(note.userId));
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
delete note.user;
|
delete note.user;
|
||||||
|
@ -113,23 +118,32 @@ export class NoteManager {
|
||||||
if (note.fileIds.length > 0) {
|
if (note.fileIds.length > 0) {
|
||||||
for (const file of note.files) {
|
for (const file of note.files) {
|
||||||
driveFileManager.set(file);
|
driveFileManager.set(file);
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: set file', file.id, driveFileManager.get(file.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
delete note.files;
|
delete note.files;
|
||||||
|
|
||||||
if (note.renote) this.set(note.renote);
|
if (note.renote) {
|
||||||
|
this.set(note.renote);
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: set renote', note.renoteId);
|
||||||
|
}
|
||||||
delete note.renote;
|
delete note.renote;
|
||||||
|
|
||||||
if (note.reply) this.set(note.reply);
|
if (note.reply) {
|
||||||
|
this.set(note.reply);
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: set reply', note.replyId);
|
||||||
|
}
|
||||||
delete note.reply;
|
delete note.reply;
|
||||||
|
|
||||||
const cached = this.notesSource.get(note.id);
|
const cached = this.notesSource.get(note.id);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
cached.value = note;
|
cached.value = note;
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: set note (update)', note.id, cached, note);
|
||||||
} else {
|
} else {
|
||||||
this.notesSource.set(note.id, ref(note));
|
this.notesSource.set(note.id, ref(note));
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: set note (new)', note.id, this.notesSource.get(note.id), note);
|
||||||
}
|
}
|
||||||
this.updatedAt.set(note.id, Date.now());
|
this.updatedAt.set(note.id, Date.now());
|
||||||
}
|
}
|
||||||
|
@ -139,6 +153,8 @@ export class NoteManager {
|
||||||
const note = this.notesSource.get(id) ?? this.notesSource.set(id, ref(null)).get(id)!;
|
const note = this.notesSource.get(id) ?? this.notesSource.set(id, ref(null)).get(id)!;
|
||||||
|
|
||||||
this.notesComputed.set(id, computed<Note | null>(() => {
|
this.notesComputed.set(id, computed<Note | null>(() => {
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: compute note', id, note.value);
|
||||||
|
|
||||||
if (!note.value) return null;
|
if (!note.value) return null;
|
||||||
|
|
||||||
const user = userLiteManager.get(note.value.userId)!;
|
const user = userLiteManager.get(note.value.userId)!;
|
||||||
|
@ -152,14 +168,21 @@ export class NoteManager {
|
||||||
|
|
||||||
const files = note.value.fileIds.map(id => driveFileManager.get(id)?.value);
|
const files = note.value.fileIds.map(id => driveFileManager.get(id)?.value);
|
||||||
|
|
||||||
return {
|
const result = {
|
||||||
...note.value,
|
...note.value,
|
||||||
user: user.value,
|
user: user.value,
|
||||||
renote: renote?.value ?? undefined,
|
renote: renote?.value ?? undefined,
|
||||||
reply: reply?.value ?? undefined,
|
reply: reply?.value ?? undefined,
|
||||||
files: files.filter(file => file) as DriveFile[],
|
files: files.filter(file => file) as DriveFile[],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: compute note (not null)', id, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
}));
|
}));
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: get note (new)', id, this.notesComputed.get(id));
|
||||||
|
} else {
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: get note (cached)', id, this.notesComputed.get(id), this.notesSource.get(id)?.value);
|
||||||
}
|
}
|
||||||
return this.notesComputed.get(id)!;
|
return this.notesComputed.get(id)!;
|
||||||
}
|
}
|
||||||
|
@ -195,6 +218,10 @@ export class NoteManager {
|
||||||
}
|
}
|
||||||
const interruptorUnwatch = watch(note, executeInterruptor);
|
const interruptorUnwatch = watch(note, executeInterruptor);
|
||||||
|
|
||||||
|
if (this.isDebuggerEnabled) {
|
||||||
|
console.log('NoteManager: get interrupted note (new)', id, interruptedNote);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
interruptedNote,
|
interruptedNote,
|
||||||
interruptorUnwatch,
|
interruptorUnwatch,
|
||||||
|
@ -211,6 +238,10 @@ export class NoteManager {
|
||||||
const isMyRenote = computed(() => noteIsRenote.value && $i && ($i.id === note.value?.userId));
|
const isMyRenote = computed(() => noteIsRenote.value && $i && ($i.id === note.value?.userId));
|
||||||
const appearNote = computed(() => (noteIsRenote.value ? note.value?.renote : note.value) ?? null);
|
const appearNote = computed(() => (noteIsRenote.value ? note.value?.renote : note.value) ?? null);
|
||||||
|
|
||||||
|
if (this.isDebuggerEnabled) {
|
||||||
|
console.log('NoteManager: get note view base (new)', id, { note, noteIsRenote, isMyRenote, appearNote });
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
note, interruptorUnwatch, executeInterruptor,
|
note, interruptorUnwatch, executeInterruptor,
|
||||||
isRenote: noteIsRenote, isMyRenote, appearNote,
|
isRenote: noteIsRenote, isMyRenote, appearNote,
|
||||||
|
@ -222,10 +253,13 @@ export class NoteManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async fetch(id: string, force = false): Promise<CachedNote> {
|
public async fetch(id: string, force = false): Promise<CachedNote> {
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note', id, { force });
|
||||||
|
|
||||||
if (!force) {
|
if (!force) {
|
||||||
const cachedNote = this.get(id);
|
const cachedNote = this.get(id);
|
||||||
if (cachedNote.value === null) {
|
if (cachedNote.value === null) {
|
||||||
// 削除されている場合はnullを返す
|
// 削除されている場合はnullを返す
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note (deleted)', id, cachedNote.value);
|
||||||
return cachedNote;
|
return cachedNote;
|
||||||
}
|
}
|
||||||
// Renoteの場合はRenote元の更新日時も考慮する
|
// Renoteの場合はRenote元の更新日時も考慮する
|
||||||
|
@ -233,18 +267,20 @@ export class NoteManager {
|
||||||
this.updatedAt.get(id) :
|
this.updatedAt.get(id) :
|
||||||
Math.max(this.updatedAt.get(id) ?? 0, this.updatedAt.get(cachedNote.value!.renoteId!) ?? 0);
|
Math.max(this.updatedAt.get(id) ?? 0, this.updatedAt.get(cachedNote.value!.renoteId!) ?? 0);
|
||||||
// 2分以上経過していない場合はキャッシュを返す
|
// 2分以上経過していない場合はキャッシュを返す
|
||||||
if (updatedAt && Date.now() - updatedAt < 1000 * 120) {
|
if (cachedNote && updatedAt && Date.now() - updatedAt < 1000 * 120) {
|
||||||
if (cachedNote) {
|
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note (use cache)', id, { cachedNote, updatedAt });
|
||||||
return cachedNote;
|
return cachedNote;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note (fetch)', id);
|
||||||
return api('notes/show', { noteId: id })
|
return api('notes/show', { noteId: id })
|
||||||
.then(fetchedNote => {
|
.then(fetchedNote => {
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note (success)', id, fetchedNote);
|
||||||
this.set(fetchedNote);
|
this.set(fetchedNote);
|
||||||
return this.get(id)!;
|
return this.get(id)!;
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note (error)', id);
|
||||||
// エラーが発生した場合は何もしない
|
// エラーが発生した場合は何もしない
|
||||||
return this.get(id)!;
|
return this.get(id)!;
|
||||||
});
|
});
|
||||||
|
@ -255,12 +291,17 @@ export class NoteManager {
|
||||||
|
|
||||||
const note = this.notesSource.get(id);
|
const note = this.notesSource.get(id);
|
||||||
|
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: onStreamNoteUpdated', noteData);
|
||||||
|
|
||||||
if (!note || !note.value) {
|
if (!note || !note.value) {
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: onStreamNoteUpdated (not found)', note, note?.value);
|
||||||
this.connection?.send('un', { id });
|
this.connection?.send('un', { id });
|
||||||
this.captureing.delete(id);
|
this.captureing.delete(id);
|
||||||
this.notesComputed.delete(id);
|
this.notesComputed.delete(id);
|
||||||
this.updatedAt.delete(id);
|
this.updatedAt.delete(id);
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: onStreamNoteUpdated (found)', note.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -334,11 +375,13 @@ export class NoteManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private capture(id: string, markRead = true): void {
|
private capture(id: string, markRead = true): void {
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: capture', id, { has: this.notesSource.has(id), markRead, count: this.captureing.get(id) });
|
||||||
|
|
||||||
if (!this.notesSource.has(id)) return;
|
if (!this.notesSource.has(id)) return;
|
||||||
|
|
||||||
const captureingNumber = this.captureing.get(id);
|
const captureingCount = this.captureing.get(id);
|
||||||
if (typeof captureingNumber === 'number' && captureingNumber > 0) {
|
if (typeof captureingCount === 'number' && captureingCount > 0) {
|
||||||
this.captureing.set(id, captureingNumber + 1);
|
this.captureing.set(id, captureingCount + 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,11 +394,13 @@ export class NoteManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private decapture(id: string, noDeletion = false): void {
|
private decapture(id: string, noDeletion = false): void {
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: decapture', id, { has: this.notesSource.has(id), noDeletion, count: this.captureing.get(id) });
|
||||||
|
|
||||||
if (!this.notesSource.has(id)) return;
|
if (!this.notesSource.has(id)) return;
|
||||||
|
|
||||||
const captureingNumber = this.captureing.get(id);
|
const captureingCount = this.captureing.get(id);
|
||||||
if (typeof captureingNumber === 'number' && captureingNumber > 1) {
|
if (typeof captureingCount === 'number' && captureingCount > 1) {
|
||||||
this.captureing.set(id, captureingNumber - 1);
|
this.captureing.set(id, captureingCount - 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,6 +422,8 @@ export class NoteManager {
|
||||||
*/
|
*/
|
||||||
public useNote(id: string, shoudFetch: true): { note: Promise<CachedNote>, unuse: (noDeletion?: boolean) => void };
|
public useNote(id: string, shoudFetch: true): { note: Promise<CachedNote>, unuse: (noDeletion?: boolean) => void };
|
||||||
public useNote(id: string, shoudFetch = false) {
|
public useNote(id: string, shoudFetch = false) {
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: useNote', id, { has: this.notesSource.has(id), shoudFetch });
|
||||||
|
|
||||||
const note = (!this.notesSource.has(id) || shoudFetch) ? this.fetch(id) : this.get(id)!;
|
const note = (!this.notesSource.has(id) || shoudFetch) ? this.fetch(id) : this.get(id)!;
|
||||||
let using = false;
|
let using = false;
|
||||||
const CapturePromise = Promise.resolve(note)
|
const CapturePromise = Promise.resolve(note)
|
||||||
|
@ -384,12 +431,14 @@ export class NoteManager {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
console.log('NoteManager: useNote: CapturePromise.finally 1', id);
|
||||||
this.capture(id);
|
this.capture(id);
|
||||||
using = true;
|
using = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
const unuse = (noDeletion = false) => {
|
const unuse = (noDeletion = false) => {
|
||||||
CapturePromise.finally(() => {
|
CapturePromise.finally(() => {
|
||||||
|
console.log('NoteManager: useNote: unuse', id, { using, noDeletion });
|
||||||
if (!using) return;
|
if (!using) return;
|
||||||
this.decapture(id, noDeletion);
|
this.decapture(id, noDeletion);
|
||||||
using = false;
|
using = false;
|
||||||
|
@ -406,7 +455,7 @@ export class NoteManager {
|
||||||
export const noteManager = new NoteManager();
|
export const noteManager = new NoteManager();
|
||||||
|
|
||||||
if (_DEV_) {
|
if (_DEV_) {
|
||||||
console.log('entity manager initialized', {
|
console.log('NoteManager: entity manager initialized', {
|
||||||
noteManager,
|
noteManager,
|
||||||
userLiteManager,
|
userLiteManager,
|
||||||
driveFileManager,
|
driveFileManager,
|
||||||
|
|
Loading…
Reference in New Issue