perf: cache renote muting
This commit is contained in:
parent
3779b77c25
commit
090bb9a2c3
6 changed files with 55 additions and 18 deletions
|
@ -9,6 +9,7 @@ import {
|
||||||
ChannelFollowingsCache,
|
ChannelFollowingsCache,
|
||||||
InstanceMutingsCache,
|
InstanceMutingsCache,
|
||||||
LocalFollowingsCache,
|
LocalFollowingsCache,
|
||||||
|
RenoteMutingsCache,
|
||||||
UserBlockedCache,
|
UserBlockedCache,
|
||||||
UserMutingsCache,
|
UserMutingsCache,
|
||||||
userWordMuteCache,
|
userWordMuteCache,
|
||||||
|
@ -16,7 +17,7 @@ import {
|
||||||
import { getTimestamp } from "@/misc/gen-id.js";
|
import { getTimestamp } from "@/misc/gen-id.js";
|
||||||
import Logger from "@/services/logger.js";
|
import Logger from "@/services/logger.js";
|
||||||
import { UserProfiles } from "@/models/index.js";
|
import { UserProfiles } from "@/models/index.js";
|
||||||
import { getWordHardMute } from "@/misc/check-word-mute";
|
import { getWordHardMute } from "@/misc/check-word-mute.js";
|
||||||
|
|
||||||
function newClient(): Client | null {
|
function newClient(): Client | null {
|
||||||
if (!config.scylla) {
|
if (!config.scylla) {
|
||||||
|
@ -107,8 +108,8 @@ export const prepared = {
|
||||||
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||||
select: {
|
select: {
|
||||||
byDate: `SELECT * FROM note WHERE "createdAtDate" = ?`,
|
byDate: `SELECT * FROM note WHERE "createdAtDate" = ?`,
|
||||||
byUri: `SELECT * FROM note WHERE "uri" IN ?`,
|
byUri: `SELECT * FROM note WHERE "uri" = ?`,
|
||||||
byUrl: `SELECT * FROM note WHERE "url" IN ?`,
|
byUrl: `SELECT * FROM note WHERE "url" = ?`,
|
||||||
byId: `SELECT * FROM note_by_id WHERE "id" IN ?`,
|
byId: `SELECT * FROM note_by_id WHERE "id" IN ?`,
|
||||||
byUserId: `SELECT * FROM note_by_userid WHERE "userId" IN ?`,
|
byUserId: `SELECT * FROM note_by_userid WHERE "userId" IN ?`,
|
||||||
},
|
},
|
||||||
|
@ -482,3 +483,15 @@ export async function filterBlockedUser(
|
||||||
!(note.renoteUserId && blockerIds.includes(note.renoteUserId)),
|
!(note.renoteUserId && blockerIds.includes(note.renoteUserId)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function filterMutedRenotes(
|
||||||
|
notes: ScyllaNote[],
|
||||||
|
user: { id: User["id"] },
|
||||||
|
): Promise<ScyllaNote[]> {
|
||||||
|
const cache = await RenoteMutingsCache.init(user.id);
|
||||||
|
const muteeIds = await cache.getAll();
|
||||||
|
|
||||||
|
return notes.filter(
|
||||||
|
(note) => note.text || !note.renoteId || !muteeIds.includes(note.userId),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
Followings,
|
Followings,
|
||||||
MutedNotes,
|
MutedNotes,
|
||||||
Mutings,
|
Mutings,
|
||||||
|
RenoteMutings,
|
||||||
UserProfiles,
|
UserProfiles,
|
||||||
} from "@/models/index.js";
|
} from "@/models/index.js";
|
||||||
import { IsNull } from "typeorm";
|
import { IsNull } from "typeorm";
|
||||||
|
@ -73,7 +74,7 @@ export class Cache<T> {
|
||||||
|
|
||||||
public async delete(...keys: (string | null)[]): Promise<void> {
|
public async delete(...keys: (string | null)[]): Promise<void> {
|
||||||
if (keys.length > 0) {
|
if (keys.length > 0) {
|
||||||
const _keys = keys.map(this.prefixedKey);
|
const _keys = keys.map((key) => this.prefixedKey(key));
|
||||||
await redisClient.del(_keys);
|
await redisClient.del(_keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,7 +234,9 @@ class HashCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async delete(...fields: string[]) {
|
public async delete(...fields: string[]) {
|
||||||
await redisClient.hdel(this.key, ...fields);
|
if (fields.length > 0) {
|
||||||
|
await redisClient.hdel(this.key, ...fields);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async clear() {
|
public async clear() {
|
||||||
|
@ -401,3 +404,22 @@ export class UserBlockedCache extends SetCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const userWordMuteCache = new Cache<string[][]>("mutedWord", 60 * 30);
|
export const userWordMuteCache = new Cache<string[][]>("mutedWord", 60 * 30);
|
||||||
|
|
||||||
|
export class RenoteMutingsCache extends SetCache {
|
||||||
|
private constructor(userId: string) {
|
||||||
|
const fetcher = () =>
|
||||||
|
RenoteMutings.find({
|
||||||
|
select: ["muteeId"],
|
||||||
|
where: { muterId: userId },
|
||||||
|
}).then((mutes) => mutes.map(({ muteeId }) => muteeId));
|
||||||
|
|
||||||
|
super("renoteMute", userId, fetcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async init(userId: string): Promise<RenoteMutingsCache> {
|
||||||
|
const cache = new RenoteMutingsCache(userId);
|
||||||
|
await cache.fetch();
|
||||||
|
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import {
|
||||||
filterMutedUser,
|
filterMutedUser,
|
||||||
filterMutedNote,
|
filterMutedNote,
|
||||||
filterBlockedUser,
|
filterBlockedUser,
|
||||||
|
filterMutedRenotes,
|
||||||
} from "@/db/scylla.js";
|
} from "@/db/scylla.js";
|
||||||
import { ChannelFollowingsCache, LocalFollowingsCache } from "@/misc/cache.js";
|
import { ChannelFollowingsCache, LocalFollowingsCache } from "@/misc/cache.js";
|
||||||
|
|
||||||
|
@ -92,6 +93,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
filtered = await filterMutedUser(filtered, user);
|
filtered = await filterMutedUser(filtered, user);
|
||||||
filtered = await filterMutedNote(filtered, user);
|
filtered = await filterMutedNote(filtered, user);
|
||||||
filtered = await filterBlockedUser(filtered, user);
|
filtered = await filterBlockedUser(filtered, user);
|
||||||
|
filtered = await filterMutedRenotes(filtered, user);
|
||||||
return filtered;
|
return filtered;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { RenoteMuting } from "@/models/entities/renote-muting.js";
|
||||||
import define from "../../define.js";
|
import define from "../../define.js";
|
||||||
import { ApiError } from "../../error.js";
|
import { ApiError } from "../../error.js";
|
||||||
import { getUser } from "../../common/getters.js";
|
import { getUser } from "../../common/getters.js";
|
||||||
|
import { RenoteMutingsCache } from "@/misc/cache.js";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["account"],
|
tags: ["account"],
|
||||||
|
@ -47,12 +48,8 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check if already muting
|
// Check if already muting
|
||||||
const exist = await RenoteMutings.exist({
|
const cache = await RenoteMutingsCache.init(muter.id);
|
||||||
where: {
|
const exist = await cache.has(mutee.id);
|
||||||
muterId: muter.id,
|
|
||||||
muteeId: mutee.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (exist) {
|
if (exist) {
|
||||||
throw new ApiError(meta.errors.alreadyMuting);
|
throw new ApiError(meta.errors.alreadyMuting);
|
||||||
|
@ -66,5 +63,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
muteeId: mutee.id,
|
muteeId: mutee.id,
|
||||||
} as RenoteMuting);
|
} as RenoteMuting);
|
||||||
|
|
||||||
|
await cache.add(mutee.id);
|
||||||
|
|
||||||
// publishUserEvent(user.id, "mute", mutee);
|
// publishUserEvent(user.id, "mute", mutee);
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { RenoteMutings } from "@/models/index.js";
|
||||||
import define from "../../define.js";
|
import define from "../../define.js";
|
||||||
import { ApiError } from "../../error.js";
|
import { ApiError } from "../../error.js";
|
||||||
import { getUser } from "../../common/getters.js";
|
import { getUser } from "../../common/getters.js";
|
||||||
|
import { RenoteMutingsCache } from "@/misc/cache.js";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["account"],
|
tags: ["account"],
|
||||||
|
@ -45,19 +46,19 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check not muting
|
// Check not muting
|
||||||
const muting = await RenoteMutings.findOneBy({
|
const cache = await RenoteMutingsCache.init(muter.id);
|
||||||
muterId: muter.id,
|
const muting = await cache.has(mutee.id);
|
||||||
muteeId: mutee.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (muting == null) {
|
if (!muting) {
|
||||||
throw new ApiError(meta.errors.notMuting);
|
throw new ApiError(meta.errors.notMuting);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete mute
|
// Delete mute
|
||||||
await RenoteMutings.delete({
|
await RenoteMutings.delete({
|
||||||
id: muting.id,
|
muterId: muter.id,
|
||||||
|
muteeId: mutee.id,
|
||||||
});
|
});
|
||||||
|
await cache.delete(mutee.id);
|
||||||
|
|
||||||
// publishUserEvent(user.id, "unmute", mutee);
|
// publishUserEvent(user.id, "unmute", mutee);
|
||||||
});
|
});
|
||||||
|
|
|
@ -711,7 +711,7 @@ async function insertNote(
|
||||||
emojis: string[],
|
emojis: string[],
|
||||||
mentionedUsers: MinimumUser[],
|
mentionedUsers: MinimumUser[],
|
||||||
) {
|
) {
|
||||||
if (data.createdAt === null || data.createdAt === undefined) {
|
if (!data.createdAt || isNaN(data.createdAt.getTime())) {
|
||||||
data.createdAt = new Date();
|
data.createdAt = new Date();
|
||||||
}
|
}
|
||||||
const insert = new Note({
|
const insert = new Note({
|
||||||
|
|
Loading…
Reference in a new issue