re-type userFollowingsCache to match the others
This commit is contained in:
parent
0c84d73294
commit
853b548a43
17 changed files with 47 additions and 56 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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[]>>;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue