mirror of
https://iceshrimp.dev/crimekillz/trashposs
synced 2024-11-22 00:43:49 +01:00
[backend] Only pack each user once per request
This commit is contained in:
parent
4e6e22633e
commit
735fd37707
@ -28,6 +28,7 @@ import {
|
|||||||
} from "@/misc/populate-emojis.js";
|
} from "@/misc/populate-emojis.js";
|
||||||
import { db } from "@/db/postgre.js";
|
import { db } from "@/db/postgre.js";
|
||||||
import { IdentifiableError } from "@/misc/identifiable-error.js";
|
import { IdentifiableError } from "@/misc/identifiable-error.js";
|
||||||
|
import { PackedUserCache } from "@/models/repositories/user.js";
|
||||||
|
|
||||||
export async function populatePoll(note: Note, meId: User["id"] | null) {
|
export async function populatePoll(note: Note, meId: User["id"] | null) {
|
||||||
const poll = await Polls.findOneByOrFail({ noteId: note.id });
|
const poll = await Polls.findOneByOrFail({ noteId: note.id });
|
||||||
@ -173,6 +174,7 @@ export const NoteRepository = db.getRepository(Note).extend({
|
|||||||
myRenotes: Map<Note["id"], boolean>;
|
myRenotes: Map<Note["id"], boolean>;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
userCache: PackedUserCache = Users.getFreshPackedUserCache(),
|
||||||
): Promise<Packed<"Note">> {
|
): Promise<Packed<"Note">> {
|
||||||
const opts = Object.assign(
|
const opts = Object.assign(
|
||||||
{
|
{
|
||||||
@ -221,7 +223,7 @@ export const NoteRepository = db.getRepository(Note).extend({
|
|||||||
id: note.id,
|
id: note.id,
|
||||||
createdAt: note.createdAt.toISOString(),
|
createdAt: note.createdAt.toISOString(),
|
||||||
userId: note.userId,
|
userId: note.userId,
|
||||||
user: Users.pack(note.user ?? note.userId, me, {
|
user: Users.packCached(note.user ?? note.userId, userCache, me, {
|
||||||
detail: false,
|
detail: false,
|
||||||
}),
|
}),
|
||||||
text: text,
|
text: text,
|
||||||
@ -265,14 +267,14 @@ export const NoteRepository = db.getRepository(Note).extend({
|
|||||||
? this.tryPack(note.reply || note.replyId, me, {
|
? this.tryPack(note.reply || note.replyId, me, {
|
||||||
detail: false,
|
detail: false,
|
||||||
_hint_: options?._hint_,
|
_hint_: options?._hint_,
|
||||||
})
|
}, userCache)
|
||||||
: undefined,
|
: undefined,
|
||||||
|
|
||||||
renote: note.renoteId
|
renote: note.renoteId
|
||||||
? this.pack(note.renote || note.renoteId, me, {
|
? this.pack(note.renote || note.renoteId, me, {
|
||||||
detail: true,
|
detail: true,
|
||||||
_hint_: options?._hint_,
|
_hint_: options?._hint_,
|
||||||
})
|
}, userCache)
|
||||||
: undefined,
|
: undefined,
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
@ -309,9 +311,10 @@ export const NoteRepository = db.getRepository(Note).extend({
|
|||||||
myRenotes: Map<Note["id"], boolean>;
|
myRenotes: Map<Note["id"], boolean>;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
userCache: PackedUserCache = Users.getFreshPackedUserCache(),
|
||||||
): Promise<Packed<"Note"> | undefined> {
|
): Promise<Packed<"Note"> | undefined> {
|
||||||
try {
|
try {
|
||||||
return await this.pack(src, me, options);
|
return await this.pack(src, me, options, userCache);
|
||||||
} catch {
|
} catch {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import type { Packed } from "@/misc/schema.js";
|
|||||||
import type { Promiseable } from "@/prelude/await-all.js";
|
import type { Promiseable } from "@/prelude/await-all.js";
|
||||||
import { awaitAll } from "@/prelude/await-all.js";
|
import { awaitAll } from "@/prelude/await-all.js";
|
||||||
import { populateEmojis } from "@/misc/populate-emojis.js";
|
import { populateEmojis } from "@/misc/populate-emojis.js";
|
||||||
import { getAntennas } from "@/misc/antenna-cache.js";
|
|
||||||
import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from "@/const.js";
|
import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from "@/const.js";
|
||||||
import { Cache } from "@/misc/cache.js";
|
import { Cache } from "@/misc/cache.js";
|
||||||
import { db } from "@/db/postgre.js";
|
import { db } from "@/db/postgre.js";
|
||||||
@ -37,6 +36,7 @@ import {
|
|||||||
UserSecurityKeys,
|
UserSecurityKeys,
|
||||||
} from "../index.js";
|
} from "../index.js";
|
||||||
import type { Instance } from "../entities/instance.js";
|
import type { Instance } from "../entities/instance.js";
|
||||||
|
import AsyncLock from "async-lock";
|
||||||
|
|
||||||
const userInstanceCache = new Cache<Instance | null>(
|
const userInstanceCache = new Cache<Instance | null>(
|
||||||
"userInstance",
|
"userInstance",
|
||||||
@ -59,6 +59,11 @@ type IsMeAndIsUserDetailed<
|
|||||||
|
|
||||||
const ajv = new Ajv();
|
const ajv = new Ajv();
|
||||||
|
|
||||||
|
export type PackedUserCache = {
|
||||||
|
locks: AsyncLock;
|
||||||
|
results: IsMeAndIsUserDetailed<any, any>[];
|
||||||
|
}
|
||||||
|
|
||||||
const localUsernameSchema = {
|
const localUsernameSchema = {
|
||||||
type: "string",
|
type: "string",
|
||||||
pattern: /^\w{1,20}$/.toString().slice(1, -1),
|
pattern: /^\w{1,20}$/.toString().slice(1, -1),
|
||||||
@ -366,6 +371,37 @@ export const UserRepository = db.getRepository(User).extend({
|
|||||||
return `${config.url}/identicon/${userId}`;
|
return `${config.url}/identicon/${userId}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getFreshPackedUserCache(): PackedUserCache {
|
||||||
|
return {
|
||||||
|
locks: new AsyncLock(),
|
||||||
|
results: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
async packCached<
|
||||||
|
ExpectsMe extends boolean | null = null,
|
||||||
|
D extends boolean = false,
|
||||||
|
>(
|
||||||
|
src: User["id"] | User,
|
||||||
|
cache: PackedUserCache,
|
||||||
|
me?: { id: User["id"] } | null | undefined,
|
||||||
|
options?: {
|
||||||
|
detail?: D;
|
||||||
|
includeSecrets?: boolean;
|
||||||
|
isPrivateMode?: boolean;
|
||||||
|
},
|
||||||
|
): Promise<IsMeAndIsUserDetailed<ExpectsMe, D>> {
|
||||||
|
const id = typeof src === "object" ? src.id : src;
|
||||||
|
return cache.locks.acquire(id, async () => {
|
||||||
|
const result = cache.results.find(p => p.id === id);
|
||||||
|
if (result) return result as IsMeAndIsUserDetailed<ExpectsMe, D>
|
||||||
|
return this.pack<ExpectsMe, D>(src, me, options).then(result => {
|
||||||
|
cache.results.push(result);
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
async pack<
|
async pack<
|
||||||
ExpectsMe extends boolean | null = null,
|
ExpectsMe extends boolean | null = null,
|
||||||
D extends boolean = false,
|
D extends boolean = false,
|
||||||
@ -638,8 +674,9 @@ export const UserRepository = db.getRepository(User).extend({
|
|||||||
detail?: D;
|
detail?: D;
|
||||||
includeSecrets?: boolean;
|
includeSecrets?: boolean;
|
||||||
},
|
},
|
||||||
|
cache?: PackedUserCache,
|
||||||
): Promise<IsUserDetailed<D>[]> {
|
): Promise<IsUserDetailed<D>[]> {
|
||||||
return Promise.all(users.map((u) => this.pack(u, me, options)));
|
return Promise.all(users.map((u) => this.packCached(u, cache ?? this.getFreshPackedUserCache(), me, options)));
|
||||||
},
|
},
|
||||||
|
|
||||||
isLocalUser,
|
isLocalUser,
|
||||||
|
Loading…
Reference in New Issue
Block a user