summaryrefslogtreecommitdiff
path: root/packages/backend/src/core/UserBlockingService.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/backend/src/core/UserBlockingService.ts')
-rw-r--r--packages/backend/src/core/UserBlockingService.ts71
1 files changed, 68 insertions, 3 deletions
diff --git a/packages/backend/src/core/UserBlockingService.ts b/packages/backend/src/core/UserBlockingService.ts
index a65a0bf313..d734328669 100644
--- a/packages/backend/src/core/UserBlockingService.ts
+++ b/packages/backend/src/core/UserBlockingService.ts
@@ -1,5 +1,6 @@
-import { Inject, Injectable } from '@nestjs/common';
+import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
+import Redis from 'ioredis';
import { IdService } from '@/core/IdService.js';
import type { CacheableUser, User } from '@/models/entities/User.js';
import type { Blocking } from '@/models/entities/Blocking.js';
@@ -7,7 +8,6 @@ import { QueueService } from '@/core/QueueService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js';
import { DI } from '@/di-symbols.js';
-import logger from '@/logger.js';
import type { UsersRepository, FollowingsRepository, FollowRequestsRepository, BlockingsRepository, UserListsRepository, UserListJoiningsRepository } from '@/models/index.js';
import Logger from '@/logger.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
@@ -15,12 +15,20 @@ import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { LoggerService } from '@/core/LoggerService.js';
import { WebhookService } from '@/core/WebhookService.js';
import { bindThis } from '@/decorators.js';
+import { Cache } from '@/misc/cache.js';
+import { StreamMessages } from '@/server/api/stream/types.js';
@Injectable()
-export class UserBlockingService {
+export class UserBlockingService implements OnApplicationShutdown {
private logger: Logger;
+ // キーがユーザーIDで、値がそのユーザーがブロックしているユーザーのIDのリストなキャッシュ
+ private blockingsByUserIdCache: Cache<User['id'][]>;
+
constructor(
+ @Inject(DI.redisSubscriber)
+ private redisSubscriber: Redis.Redis,
+
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@@ -49,6 +57,37 @@ export class UserBlockingService {
private loggerService: LoggerService,
) {
this.logger = this.loggerService.getLogger('user-block');
+
+ this.blockingsByUserIdCache = new Cache<User['id'][]>(Infinity);
+
+ this.redisSubscriber.on('message', this.onMessage);
+ }
+
+ @bindThis
+ private async onMessage(_: string, data: string): Promise<void> {
+ const obj = JSON.parse(data);
+
+ if (obj.channel === 'internal') {
+ const { type, body } = obj.message as StreamMessages['internal']['payload'];
+ switch (type) {
+ case 'blockingCreated': {
+ const cached = this.blockingsByUserIdCache.get(body.blockerId);
+ if (cached) {
+ this.blockingsByUserIdCache.set(body.blockerId, [...cached, ...[body.blockeeId]]);
+ }
+ break;
+ }
+ case 'blockingDeleted': {
+ const cached = this.blockingsByUserIdCache.get(body.blockerId);
+ if (cached) {
+ this.blockingsByUserIdCache.set(body.blockerId, cached.filter(x => x !== body.blockeeId));
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
}
@bindThis
@@ -72,6 +111,11 @@ export class UserBlockingService {
await this.blockingsRepository.insert(blocking);
+ this.globalEventService.publishInternalEvent('blockingCreated', {
+ blockerId: blocker.id,
+ blockeeId: blockee.id,
+ });
+
if (this.userEntityService.isLocalUser(blocker) && this.userEntityService.isRemoteUser(blockee)) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderBlock(blocking));
this.queueService.deliver(blocker, content, blockee.inbox);
@@ -210,10 +254,31 @@ export class UserBlockingService {
await this.blockingsRepository.delete(blocking.id);
+ this.globalEventService.publishInternalEvent('blockingDeleted', {
+ blockerId: blocker.id,
+ blockeeId: blockee.id,
+ });
+
// deliver if remote bloking
if (this.userEntityService.isLocalUser(blocker) && this.userEntityService.isRemoteUser(blockee)) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderBlock(blocking), blocker));
this.queueService.deliver(blocker, content, blockee.inbox);
}
}
+
+ @bindThis
+ public async checkBlocked(blockerId: User['id'], blockeeId: User['id']): Promise<boolean> {
+ const blockedUserIds = await this.blockingsByUserIdCache.fetch(blockerId, () => this.blockingsRepository.find({
+ where: {
+ blockerId,
+ },
+ select: ['blockeeId'],
+ }).then(records => records.map(record => record.blockeeId)));
+ return blockedUserIds.includes(blockeeId);
+ }
+
+ @bindThis
+ public onApplicationShutdown(signal?: string | undefined) {
+ this.redisSubscriber.off('message', this.onMessage);
+ }
}