diff options
| author | Hazelnoot <acomputerdog@gmail.com> | 2025-06-07 21:27:25 -0400 |
|---|---|---|
| committer | Hazelnoot <acomputerdog@gmail.com> | 2025-06-09 11:02:36 -0400 |
| commit | 853b548a4369051b8fdaabbda80d7d6ed52adb77 (patch) | |
| tree | 7aec31303f244cbdec4aee82fdbc0b0e90c33a83 /packages/backend/src/core | |
| parent | move QuantumKVCache to a separate file (diff) | |
| download | sharkey-853b548a4369051b8fdaabbda80d7d6ed52adb77.tar.gz sharkey-853b548a4369051b8fdaabbda80d7d6ed52adb77.tar.bz2 sharkey-853b548a4369051b8fdaabbda80d7d6ed52adb77.zip | |
re-type userFollowingsCache to match the others
Diffstat (limited to 'packages/backend/src/core')
| -rw-r--r-- | packages/backend/src/core/AntennaService.ts | 3 | ||||
| -rw-r--r-- | packages/backend/src/core/CacheService.ts | 38 | ||||
| -rw-r--r-- | packages/backend/src/core/NotificationService.ts | 12 | ||||
| -rw-r--r-- | packages/backend/src/core/entities/NoteEntityService.ts | 14 |
4 files changed, 29 insertions, 38 deletions
diff --git a/packages/backend/src/core/AntennaService.ts b/packages/backend/src/core/AntennaService.ts index cf696e3599..667df57943 100644 --- a/packages/backend/src/core/AntennaService.ts +++ b/packages/backend/src/core/AntennaService.ts @@ -130,7 +130,8 @@ export class AntennaService implements OnApplicationShutdown { } if (note.visibility === 'followers') { - const isFollowing = Object.hasOwn(await this.cacheService.userFollowingsCache.fetch(antenna.userId), note.userId); + const followings = await this.cacheService.userFollowingsCache.fetch(antenna.userId); + const isFollowing = followings.has(note.userId); if (!isFollowing && antenna.userId !== note.userId) return false; } diff --git a/packages/backend/src/core/CacheService.ts b/packages/backend/src/core/CacheService.ts index e59857b4ce..38a93e57f4 100644 --- a/packages/backend/src/core/CacheService.ts +++ b/packages/backend/src/core/CacheService.ts @@ -6,14 +6,14 @@ import { Inject, Injectable } from '@nestjs/common'; import * as Redis from 'ioredis'; import { In, IsNull } from 'typeorm'; -import type { BlockingsRepository, FollowingsRepository, MutingsRepository, RenoteMutingsRepository, MiUserProfile, UserProfilesRepository, UsersRepository, MiFollowing, MiNote } from '@/models/_.js'; +import type { BlockingsRepository, FollowingsRepository, MutingsRepository, RenoteMutingsRepository, MiUserProfile, UserProfilesRepository, UsersRepository, MiNote } from '@/models/_.js'; import { MemoryKVCache, RedisKVCache } from '@/misc/cache.js'; import { QuantumKVCache } from '@/misc/QuantumKVCache.js'; import type { MiLocalUser, MiUser } from '@/models/User.js'; import { DI } from '@/di-symbols.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; -import type { GlobalEvents, InternalEventTypes } from '@/core/GlobalEventService.js'; +import type { InternalEventTypes } from '@/core/GlobalEventService.js'; import { InternalEventService } from '@/core/InternalEventService.js'; import type { OnApplicationShutdown } from '@nestjs/common'; @@ -46,7 +46,7 @@ export class CacheService implements OnApplicationShutdown { public userBlockingCache: QuantumKVCache<Set<string>>; public userBlockedCache: QuantumKVCache<Set<string>>; // NOTE: 「被」Blockキャッシュ public renoteMutingsCache: QuantumKVCache<Set<string>>; - public userFollowingsCache: QuantumKVCache<Record<string, Pick<MiFollowing, 'withReplies'> | undefined>>; + public userFollowingsCache: QuantumKVCache<Map<string, { withReplies: boolean }>>; protected userFollowStatsCache = new MemoryKVCache<FollowStats>(1000 * 60 * 10); // 10 minutes protected translationsCache: RedisKVCache<CachedTranslationEntity>; @@ -110,15 +110,9 @@ export class CacheService implements OnApplicationShutdown { fetcher: (key) => this.renoteMutingsRepository.find({ where: { muterId: key }, select: ['muteeId'] }).then(xs => new Set(xs.map(x => x.muteeId))), }); - this.userFollowingsCache = new QuantumKVCache<Record<string, Pick<MiFollowing, 'withReplies'> | undefined>>(this.internalEventService, 'userFollowings', { + this.userFollowingsCache = new QuantumKVCache<Map<string, { withReplies: boolean }>>(this.internalEventService, 'userFollowings', { lifetime: 1000 * 60 * 30, // 30m - fetcher: (key) => this.followingsRepository.find({ where: { followerId: key }, select: ['followeeId', 'withReplies'] }).then(xs => { - const obj: Record<string, Pick<MiFollowing, 'withReplies'> | undefined> = {}; - for (const x of xs) { - obj[x.followeeId] = { withReplies: x.withReplies }; - } - return obj; - }), + fetcher: (key) => this.followingsRepository.find({ where: { followerId: key }, select: ['followeeId', 'withReplies'] }).then(xs => new Map(xs.map(f => [f.followeeId, { withReplies: f.withReplies }]))), }); this.translationsCache = new RedisKVCache<CachedTranslationEntity>(this.redisClient, 'translations', { @@ -305,14 +299,14 @@ export class CacheService implements OnApplicationShutdown { } @bindThis - public async getUserFollowings(userIds: Iterable<string>): Promise<Map<string, Set<string>>> { - const followings = new Map<string, Set<string>>(); + public async getUserFollowings(userIds: Iterable<string>): Promise<Map<string, Map<string, { withReplies: boolean }>>> { + const followings = new Map<string, Map<string, { withReplies: boolean }>>(); const toFetch: string[] = []; for (const userId of userIds) { const fromCache = this.userFollowingsCache.get(userId); if (fromCache) { - followings.set(userId, new Set(Object.keys(fromCache))); + followings.set(userId, fromCache); } else { toFetch.push(userId); } @@ -331,25 +325,25 @@ export class CacheService implements OnApplicationShutdown { }) .getMany(); - const toCache = new Map<string, Record<string, Pick<MiFollowing, 'withReplies'> | undefined>>(); + const toCache = new Map<string, Map<string, { withReplies: boolean }>>(); // Pivot to a map for (const { followerId, followeeId, withReplies } of fetchedFollowings) { // Queue for cache - let cacheSet = toCache.get(followerId); - if (!cacheSet) { - cacheSet = {}; - toCache.set(followerId, cacheSet); + let cacheMap = toCache.get(followerId); + if (!cacheMap) { + cacheMap = new Map(); + toCache.set(followerId, cacheMap); } - cacheSet[followeeId] = { withReplies }; + cacheMap.set(followeeId, { withReplies }); // Queue for return let returnSet = followings.get(followerId); if (!returnSet) { - returnSet = new Set(); + returnSet = new Map(); followings.set(followerId, returnSet); } - returnSet.add(followeeId); + returnSet.set(followeeId, { withReplies }); } // Update cache to speed up future calls diff --git a/packages/backend/src/core/NotificationService.ts b/packages/backend/src/core/NotificationService.ts index 0f05f5425d..2ce7bdb5a9 100644 --- a/packages/backend/src/core/NotificationService.ts +++ b/packages/backend/src/core/NotificationService.ts @@ -113,27 +113,27 @@ export class NotificationService implements OnApplicationShutdown { } if (recieveConfig?.type === 'following') { - const isFollowing = await this.cacheService.userFollowingsCache.fetch(notifieeId).then(followings => Object.hasOwn(followings, notifierId)); + const isFollowing = await this.cacheService.userFollowingsCache.fetch(notifieeId).then(followings => followings.has(notifierId)); if (!isFollowing) { return null; } } else if (recieveConfig?.type === 'follower') { - const isFollower = await this.cacheService.userFollowingsCache.fetch(notifierId).then(followings => Object.hasOwn(followings, notifieeId)); + const isFollower = await this.cacheService.userFollowingsCache.fetch(notifierId).then(followings => followings.has(notifieeId)); if (!isFollower) { return null; } } else if (recieveConfig?.type === 'mutualFollow') { const [isFollowing, isFollower] = await Promise.all([ - this.cacheService.userFollowingsCache.fetch(notifieeId).then(followings => Object.hasOwn(followings, notifierId)), - this.cacheService.userFollowingsCache.fetch(notifierId).then(followings => Object.hasOwn(followings, notifieeId)), + this.cacheService.userFollowingsCache.fetch(notifieeId).then(followings => followings.has(notifierId)), + this.cacheService.userFollowingsCache.fetch(notifierId).then(followings => followings.has(notifieeId)), ]); if (!(isFollowing && isFollower)) { return null; } } else if (recieveConfig?.type === 'followingOrFollower') { const [isFollowing, isFollower] = await Promise.all([ - this.cacheService.userFollowingsCache.fetch(notifieeId).then(followings => Object.hasOwn(followings, notifierId)), - this.cacheService.userFollowingsCache.fetch(notifierId).then(followings => Object.hasOwn(followings, notifieeId)), + this.cacheService.userFollowingsCache.fetch(notifieeId).then(followings => followings.has(notifierId)), + this.cacheService.userFollowingsCache.fetch(notifierId).then(followings => followings.has(notifieeId)), ]); if (!isFollowing && !isFollower) { return null; diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index 1b3920e13f..3af66b220d 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -133,7 +133,7 @@ export class NoteEntityService implements OnModuleInit { @bindThis public async hideNote(packedNote: Packed<'Note'>, meId: MiUser['id'] | null, hint?: { - myFollowing?: ReadonlySet<string>, + myFollowing?: ReadonlyMap<string, { withReplies: boolean }>, myBlockers?: ReadonlySet<string>, }): Promise<void> { if (meId === packedNote.userId) return; @@ -193,7 +193,7 @@ export class NoteEntityService implements OnModuleInit { } else { const isFollowing = hint?.myFollowing ? hint.myFollowing.has(packedNote.userId) - : (await this.cacheService.userFollowingsCache.fetch(meId))[packedNote.userId] != null; + : (await this.cacheService.userFollowingsCache.fetch(meId)).has(packedNote.userId); hide = !isFollowing; } @@ -358,14 +358,10 @@ export class NoteEntityService implements OnModuleInit { : this.cacheService.userBlockingCache.fetch(meId).then((ids) => ids.has(note.userId)), hint?.myFollowing ? hint.myFollowing.has(note.userId) - : this.followingsRepository.existsBy({ - followeeId: note.userId, - followerId: meId, - }), + : this.cacheService.userFollowingsCache.fetch(meId).then(ids => ids.has(note.userId)), hint?.me !== undefined ? (hint.me?.host ?? null) - : this.cacheService.userByIdCache.fetch(meId, () => this.usersRepository.findOneByOrFail({ id: meId })) - .then(me => me.host), + : this.cacheService.findUserById(meId).then(me => me.host), ]); if (blocked) return false; @@ -420,7 +416,7 @@ export class NoteEntityService implements OnModuleInit { packedFiles: Map<MiNote['fileIds'][number], Packed<'DriveFile'> | null>; packedUsers: Map<MiUser['id'], Packed<'UserLite'>>; mentionHandles: Record<string, string | undefined>; - userFollowings: Map<string, Set<string>>; + userFollowings: Map<string, Map<string, { withReplies: boolean }>>; userBlockers: Map<string, Set<string>>; polls: Map<string, MiPoll>; pollVotes: Map<string, Map<string, MiPollVote[]>>; |