use TimeService everywhere in the backend
This commit is contained in:
parent
ed750fd990
commit
6cceca90f9
123 changed files with 550 additions and 285 deletions
|
|
@ -23,6 +23,7 @@ import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js';
|
|||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
import { SystemWebhookService } from '@/core/SystemWebhookService.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { IdService } from './IdService.js';
|
||||
|
||||
@Injectable()
|
||||
|
|
@ -44,6 +45,7 @@ export class AbuseReportNotificationService implements OnApplicationShutdown {
|
|||
private moderationLogService: ModerationLogService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private userEntityService: UserEntityService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
this.redisForSub.on('message', this.onMessage);
|
||||
}
|
||||
|
|
@ -326,7 +328,7 @@ export class AbuseReportNotificationService implements OnApplicationShutdown {
|
|||
|
||||
await this.abuseReportNotificationRecipientRepository.update(params.id, {
|
||||
isActive: params.isActive,
|
||||
updatedAt: new Date(),
|
||||
updatedAt: this.timeService.date,
|
||||
name: params.name,
|
||||
method: params.method,
|
||||
userId: params.userId,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import { RoleService } from '@/core/RoleService.js';
|
|||
import { AntennaService } from '@/core/AntennaService.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { UserListService } from '@/core/UserListService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
@Injectable()
|
||||
export class AccountMoveService {
|
||||
|
|
@ -72,6 +73,7 @@ export class AccountMoveService {
|
|||
private antennaService: AntennaService,
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly userListService: UserListService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +91,7 @@ export class AccountMoveService {
|
|||
const update = {} as Partial<MiLocalUser>;
|
||||
update.alsoKnownAs = src.alsoKnownAs?.includes(dstUri) ? src.alsoKnownAs : src.alsoKnownAs?.concat([dstUri]) ?? [dstUri];
|
||||
update.movedToUri = dstUri;
|
||||
update.movedAt = new Date();
|
||||
update.movedAt = this.timeService.date;
|
||||
await this.usersRepository.update(src.id, update);
|
||||
Object.assign(src, update);
|
||||
|
||||
|
|
@ -181,7 +183,7 @@ export class AccountMoveService {
|
|||
// Insert new mutings with the same values except mutee
|
||||
const oldMutings = await this.mutingsRepository.findBy([
|
||||
{ muteeId: src.id, expiresAt: IsNull() },
|
||||
{ muteeId: src.id, expiresAt: MoreThan(new Date()) },
|
||||
{ muteeId: src.id, expiresAt: MoreThan(this.timeService.date) },
|
||||
]);
|
||||
if (oldMutings.length === 0) return;
|
||||
|
||||
|
|
@ -348,7 +350,7 @@ export class AccountMoveService {
|
|||
let resultUser: MiLocalUser | MiRemoteUser | null = null;
|
||||
|
||||
if (this.userEntityService.isRemoteUser(dst)) {
|
||||
if (Date.now() - (dst.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
|
||||
if (this.timeService.now - (dst.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
|
||||
await this.apPersonService.updatePerson(dst.uri);
|
||||
}
|
||||
dst = await this.apPersonService.fetchPerson(dst.uri) ?? dst;
|
||||
|
|
@ -364,7 +366,7 @@ export class AccountMoveService {
|
|||
if (!src) continue; // oldAccountを探してもこのサーバーに存在しない場合はフォロー関係もないということなのでスルー
|
||||
|
||||
if (this.userEntityService.isRemoteUser(dst)) {
|
||||
if (Date.now() - (src.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
|
||||
if (this.timeService.now - (src.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
|
||||
await this.apPersonService.updatePerson(srcUri);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import type { MiUser } from '@/models/User.js';
|
|||
import { DI } from '@/di-symbols.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { NotificationService } from '@/core/NotificationService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { ACHIEVEMENT_TYPES } from '@/models/UserProfile.js';
|
||||
|
||||
@Injectable()
|
||||
|
|
@ -18,6 +19,7 @@ export class AchievementService {
|
|||
private userProfilesRepository: UserProfilesRepository,
|
||||
|
||||
private notificationService: NotificationService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -28,7 +30,7 @@ export class AchievementService {
|
|||
): Promise<void> {
|
||||
if (!ACHIEVEMENT_TYPES.includes(type)) return;
|
||||
|
||||
const date = Date.now();
|
||||
const date = this.timeService.now;
|
||||
|
||||
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: userId });
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { ModerationLogService } from '@/core/ModerationLogService.js';
|
|||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
@Injectable()
|
||||
export class AnnouncementService {
|
||||
|
|
@ -38,6 +39,7 @@ export class AnnouncementService {
|
|||
private moderationLogService: ModerationLogService,
|
||||
private announcementEntityService: AnnouncementEntityService,
|
||||
private roleService: RoleService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +145,7 @@ export class AnnouncementService {
|
|||
}
|
||||
|
||||
await this.announcementsRepository.update(announcement.id, {
|
||||
updatedAt: new Date(),
|
||||
updatedAt: this.timeService.date,
|
||||
title: values.title,
|
||||
text: values.text,
|
||||
/* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- 空の文字列の場合、nullを渡すようにするため */
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import type { ApContextsRepository, ApFetchLogsRepository, ApInboxLogsRepository
|
|||
import type { Config } from '@/config.js';
|
||||
import { JsonValue } from '@/misc/json-value.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { IActivity, IObject } from './activitypub/type.js';
|
||||
|
||||
|
|
@ -32,6 +33,7 @@ export class ApLogService {
|
|||
|
||||
private readonly utilityService: UtilityService,
|
||||
private readonly idService: IdService,
|
||||
private readonly timeService: TimeService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
|
@ -46,7 +48,7 @@ export class ApLogService {
|
|||
|
||||
const log = new SkApInboxLog({
|
||||
id: this.idService.gen(),
|
||||
at: new Date(),
|
||||
at: this.timeService.date,
|
||||
verified: false,
|
||||
accepted: false,
|
||||
host,
|
||||
|
|
@ -85,7 +87,7 @@ export class ApLogService {
|
|||
}): Promise<SkApFetchLog> {
|
||||
const log = new SkApFetchLog({
|
||||
id: this.idService.gen(),
|
||||
at: new Date(),
|
||||
at: this.timeService.date,
|
||||
accepted: false,
|
||||
...data,
|
||||
});
|
||||
|
|
@ -163,7 +165,7 @@ export class ApLogService {
|
|||
*/
|
||||
public async deleteExpiredLogs(): Promise<number> {
|
||||
// This is the date in UTC of the oldest log to KEEP
|
||||
const oldestAllowed = new Date(Date.now() - this.config.activityLogging.maxAge);
|
||||
const oldestAllowed = new Date(this.timeService.now - this.config.activityLogging.maxAge);
|
||||
|
||||
// Delete all logs older than the threshold.
|
||||
const inboxDeleted = await this.deleteExpiredInboxLogs(oldestAllowed);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import type { GlobalEvents } from '@/core/GlobalEventService.js';
|
|||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
import { CacheManagementService, type ManagedMemorySingleCache } from '@/core/CacheManagementService.js';
|
||||
import { InternalEventService } from '@/core/InternalEventService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
@Injectable()
|
||||
export class AvatarDecorationService implements OnApplicationShutdown {
|
||||
|
|
@ -31,6 +32,8 @@ export class AvatarDecorationService implements OnApplicationShutdown {
|
|||
private moderationLogService: ModerationLogService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private readonly internalEventService: InternalEventService,
|
||||
private readonly timeService: TimeService,
|
||||
|
||||
cacheManagementService: CacheManagementService,
|
||||
) {
|
||||
this.cache = cacheManagementService.createMemorySingleCache<MiAvatarDecoration[]>(1000 * 60 * 30); // 30s
|
||||
|
|
@ -68,7 +71,7 @@ export class AvatarDecorationService implements OnApplicationShutdown {
|
|||
public async update(id: MiAvatarDecoration['id'], params: Partial<MiAvatarDecoration>, moderator?: MiUser): Promise<void> {
|
||||
const avatarDecoration = await this.avatarDecorationsRepository.findOneByOrFail({ id });
|
||||
|
||||
const date = new Date();
|
||||
const date = this.timeService.date;
|
||||
await this.avatarDecorationsRepository.update(avatarDecoration.id, {
|
||||
updatedAt: date,
|
||||
...params,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js';
|
|||
import { emojiRegex } from '@/misc/emoji-regex.js';
|
||||
import { NotificationService } from '@/core/NotificationService.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
const MAX_ROOM_MEMBERS = 30;
|
||||
const MAX_REACTIONS_PER_MESSAGE = 100;
|
||||
|
|
@ -91,6 +92,7 @@ export class ChatService {
|
|||
private userFollowingService: UserFollowingService,
|
||||
private customEmojiService: CustomEmojiService,
|
||||
private moderationLogService: ModerationLogService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -225,7 +227,7 @@ export class ChatService {
|
|||
|
||||
// 3秒経っても既読にならなかったらイベント発行
|
||||
if (this.userEntityService.isLocalUser(toUser)) {
|
||||
setTimeout(async () => {
|
||||
this.timeService.startTimer(async () => {
|
||||
const marker = await this.redisClient.get(`newUserChatMessageExists:${toUser.id}:${fromUser.id}`);
|
||||
|
||||
if (marker == null) return; // 既読
|
||||
|
|
@ -285,7 +287,7 @@ export class ChatService {
|
|||
redisPipeline.exec();
|
||||
|
||||
// 3秒経っても既読にならなかったらイベント発行
|
||||
setTimeout(async () => {
|
||||
this.timeService.startTimer(async () => {
|
||||
const redisPipeline = this.redisClient.pipeline();
|
||||
for (const membership of membershipsOtherThanMe) {
|
||||
redisPipeline.get(`newRoomChatMessageExists:${membership.userId}:${toRoom.id}`);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js
|
|||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import type { MiLocalUser } from '@/models/User.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
@Injectable()
|
||||
export class ClipService {
|
||||
|
|
@ -33,6 +34,7 @@ export class ClipService {
|
|||
|
||||
private roleService: RoleService,
|
||||
private idService: IdService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -125,7 +127,7 @@ export class ClipService {
|
|||
}
|
||||
|
||||
this.clipsRepository.update(clip.id, {
|
||||
lastClippedAt: new Date(),
|
||||
lastClippedAt: this.timeService.date,
|
||||
});
|
||||
|
||||
this.notesRepository.increment({ id: noteId }, 'clippedCount', 1);
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@ export class CustomEmojiService {
|
|||
await this.bulkUpdateEmojis(ids, async emojis => {
|
||||
for (const emoji of emojis) {
|
||||
await this.emojisRepository.update(emoji.id, {
|
||||
updatedAt: new Date(),
|
||||
updatedAt: this.timeService.date,
|
||||
aliases: [...new Set(emoji.aliases.concat(aliases))],
|
||||
});
|
||||
}
|
||||
|
|
@ -374,7 +374,7 @@ export class CustomEmojiService {
|
|||
await this.emojisRepository.update({
|
||||
id: In(ids),
|
||||
}, {
|
||||
updatedAt: new Date(),
|
||||
updatedAt: this.timeService.date,
|
||||
aliases: aliases,
|
||||
});
|
||||
|
||||
|
|
@ -386,7 +386,7 @@ export class CustomEmojiService {
|
|||
await this.bulkUpdateEmojis(ids, async emojis => {
|
||||
for (const emoji of emojis) {
|
||||
await this.emojisRepository.update(emoji.id, {
|
||||
updatedAt: new Date(),
|
||||
updatedAt: this.timeService.date,
|
||||
aliases: emoji.aliases.filter(x => !aliases.includes(x)),
|
||||
});
|
||||
}
|
||||
|
|
@ -398,7 +398,7 @@ export class CustomEmojiService {
|
|||
await this.emojisRepository.update({
|
||||
id: In(ids),
|
||||
}, {
|
||||
updatedAt: new Date(),
|
||||
updatedAt: this.timeService.date,
|
||||
category: category,
|
||||
});
|
||||
|
||||
|
|
@ -410,7 +410,7 @@ export class CustomEmojiService {
|
|||
await this.emojisRepository.update({
|
||||
id: In(ids),
|
||||
}, {
|
||||
updatedAt: new Date(),
|
||||
updatedAt: this.timeService.date,
|
||||
license: license,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import * as Redis from 'ioredis';
|
|||
import { DI } from '@/di-symbols.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
export type FanoutTimelineName = (
|
||||
// home timeline
|
||||
|
|
@ -46,6 +47,7 @@ export class FanoutTimelineService {
|
|||
private redisForTimelines: Redis.Redis,
|
||||
|
||||
private idService: IdService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +55,7 @@ export class FanoutTimelineService {
|
|||
public push(tl: FanoutTimelineName, id: string, maxlen: number, pipeline: Redis.ChainableCommander) {
|
||||
// リモートから遅れて届いた(もしくは後から追加された)投稿日時が古い投稿が追加されるとページネーション時に問題を引き起こすため、
|
||||
// 3分以内に投稿されたものでない場合、Redisにある最古のIDより新しい場合のみ追加する
|
||||
if (this.idService.parse(id).date.getTime() > Date.now() - 1000 * 60 * 3) {
|
||||
if (this.idService.parse(id).date.getTime() > this.timeService.now - 1000 * 60 * 3) {
|
||||
pipeline.lpush('list:' + tl, id);
|
||||
if (Math.random() < 0.1) { // 10%の確率でトリム
|
||||
pipeline.ltrim('list:' + tl, 0, maxlen - 1);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import type { MiGalleryPost, MiNote, MiUser } from '@/models/_.js';
|
|||
import { DI } from '@/di-symbols.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
const GLOBAL_NOTES_RANKING_WINDOW = 1000 * 60 * 60 * 24 * 3; // 3日ごと
|
||||
export const GALLERY_POSTS_RANKING_WINDOW = 1000 * 60 * 60 * 24 * 3; // 3日ごと
|
||||
|
|
@ -24,12 +25,13 @@ export class FeaturedService {
|
|||
private redisClient: Redis.Redis, // TODO: 専用のRedisサーバーを設定できるようにする
|
||||
|
||||
private readonly roleService: RoleService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
private getCurrentWindow(windowRange: number): number {
|
||||
const passed = new Date().getTime() - featuredEpoc;
|
||||
const passed = this.timeService.now - featuredEpoc;
|
||||
return Math.floor(passed / windowRange);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { CacheManagementService, type ManagedQuantumKVCache } from '@/core/Cache
|
|||
import { InternalEventService } from '@/core/InternalEventService.js';
|
||||
import { diffArraysSimple } from '@/misc/diff-arrays.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
|
||||
|
||||
@Injectable()
|
||||
|
|
@ -32,6 +33,7 @@ export class FederatedInstanceService implements OnApplicationShutdown {
|
|||
private utilityService: UtilityService,
|
||||
private idService: IdService,
|
||||
private readonly internalEventService: InternalEventService,
|
||||
private readonly timeService: TimeService,
|
||||
|
||||
cacheManagementService: CacheManagementService,
|
||||
) {
|
||||
|
|
@ -47,7 +49,7 @@ export class FederatedInstanceService implements OnApplicationShutdown {
|
|||
.values({
|
||||
id: this.idService.gen(),
|
||||
host,
|
||||
firstRetrievedAt: new Date(),
|
||||
firstRetrievedAt: this.timeService.date,
|
||||
isBlocked: this.utilityService.isBlockedHost(host),
|
||||
isSilenced: this.utilityService.isSilencedHost(host),
|
||||
isMediaSilenced: this.utilityService.isMediaSilencedHost(host),
|
||||
|
|
@ -87,7 +89,7 @@ export class FederatedInstanceService implements OnApplicationShutdown {
|
|||
.values({
|
||||
id: this.idService.gen(),
|
||||
host,
|
||||
firstRetrievedAt: new Date(),
|
||||
firstRetrievedAt: this.timeService.date,
|
||||
isBlocked: this.utilityService.isBlockedHost(host),
|
||||
isSilenced: this.utilityService.isSilencedHost(host),
|
||||
isMediaSilenced: this.utilityService.isMediaSilencedHost(host),
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import type { HashtagsRepository, MiMeta } from '@/models/_.js';
|
|||
import { bindThis } from '@/decorators.js';
|
||||
import { FeaturedService } from '@/core/FeaturedService.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
@Injectable()
|
||||
export class HashtagService {
|
||||
|
|
@ -31,6 +32,7 @@ export class HashtagService {
|
|||
private featuredService: FeaturedService,
|
||||
private idService: IdService,
|
||||
private utilityService: UtilityService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -165,7 +167,7 @@ export class HashtagService {
|
|||
if (this.utilityService.isKeyWordIncluded(hashtag, this.meta.sensitiveWords)) return;
|
||||
|
||||
// YYYYMMDDHHmm (10分間隔)
|
||||
const now = new Date();
|
||||
const now = this.timeService.date;
|
||||
now.setMinutes(Math.floor(now.getMinutes() / 10) * 10, 0, 0);
|
||||
const window = `${now.getUTCFullYear()}${(now.getUTCMonth() + 1).toString().padStart(2, '0')}${now.getUTCDate().toString().padStart(2, '0')}${now.getUTCHours().toString().padStart(2, '0')}${now.getUTCMinutes().toString().padStart(2, '0')}`;
|
||||
|
||||
|
|
@ -196,7 +198,7 @@ export class HashtagService {
|
|||
|
||||
@bindThis
|
||||
public async getChart(hashtag: string, range: number): Promise<number[]> {
|
||||
const now = new Date();
|
||||
const now = this.timeService.date;
|
||||
now.setMinutes(Math.floor(now.getMinutes() / 10) * 10, 0, 0);
|
||||
|
||||
const redisPipeline = this.redisClient.pipeline();
|
||||
|
|
@ -216,7 +218,7 @@ export class HashtagService {
|
|||
|
||||
@bindThis
|
||||
public async getCharts(hashtags: string[], range: number): Promise<Record<string, number[]>> {
|
||||
const now = new Date();
|
||||
const now = this.timeService.date;
|
||||
now.setMinutes(Math.floor(now.getMinutes() / 10) * 10, 0, 0);
|
||||
|
||||
const redisPipeline = this.redisClient.pipeline();
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/val
|
|||
import type { IObject, IObjectWithId } from '@/core/activitypub/type.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import { ApUtilityService } from '@/core/activitypub/ApUtilityService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import type { Response } from 'node-fetch';
|
||||
import type { Socket } from 'node:net';
|
||||
|
||||
|
|
@ -156,8 +157,10 @@ export class HttpRequestService {
|
|||
constructor(
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
private readonly apUtilityService: ApUtilityService,
|
||||
private readonly utilityService: UtilityService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
const cache = new CacheableLookup({
|
||||
maxTtl: 3600, // 1hours
|
||||
|
|
@ -343,7 +346,7 @@ export class HttpRequestService {
|
|||
this.utilityService.assertUrl(parsedUrl, allowHttp);
|
||||
|
||||
const controller = new AbortController();
|
||||
setTimeout(() => {
|
||||
this.timeService.startTimer(() => {
|
||||
controller.abort();
|
||||
}, timeout);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import Logger from '@/logger.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import type { KEYWORD } from 'color-convert/conversions.js';
|
||||
import { envOption } from '@/env.js';
|
||||
|
|
@ -16,12 +17,13 @@ export class LoggerService {
|
|||
constructor(
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public getLogger(domain: string, color?: KEYWORD | undefined) {
|
||||
const verbose = this.config.logging?.verbose || envOption.verbose;
|
||||
return new Logger(domain, color, verbose);
|
||||
return new Logger(domain, color, verbose, undefined, this.timeService);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { GlobalEventService } from '@/core/GlobalEventService.js';
|
|||
import { bindThis } from '@/decorators.js';
|
||||
import type { GlobalEvents } from '@/core/GlobalEventService.js';
|
||||
import { FeaturedService } from '@/core/FeaturedService.js';
|
||||
import { TimeService, type TimerHandle } from '@/core/TimeService.js';
|
||||
import { MiInstance } from '@/models/Instance.js';
|
||||
import { diffArrays } from '@/misc/diff-arrays.js';
|
||||
import type { MetasRepository } from '@/models/_.js';
|
||||
|
|
@ -20,7 +21,7 @@ import type { OnApplicationShutdown } from '@nestjs/common';
|
|||
@Injectable()
|
||||
export class MetaService implements OnApplicationShutdown {
|
||||
private cache: MiMeta | undefined;
|
||||
private intervalId: NodeJS.Timeout;
|
||||
private intervalId: TimerHandle;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.redisForSub)
|
||||
|
|
@ -34,16 +35,17 @@ export class MetaService implements OnApplicationShutdown {
|
|||
|
||||
private featuredService: FeaturedService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
//this.onMessage = this.onMessage.bind(this);
|
||||
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
this.intervalId = setInterval(() => {
|
||||
this.intervalId = this.timeService.startTimer(() => {
|
||||
this.fetch(true).then(meta => {
|
||||
// fetch内でもセットしてるけど仕様変更の可能性もあるため一応
|
||||
this.cache = meta;
|
||||
});
|
||||
}, 1000 * 60 * 5);
|
||||
}, 1000 * 60 * 5, { repeated: true });
|
||||
}
|
||||
|
||||
this.redisForSub.on('message', this.onMessage);
|
||||
|
|
@ -161,7 +163,7 @@ export class MetaService implements OnApplicationShutdown {
|
|||
|
||||
@bindThis
|
||||
public dispose(): void {
|
||||
clearInterval(this.intervalId);
|
||||
this.timeService.stopTimer(this.intervalId);
|
||||
this.redisForSub.off('message', this.onMessage);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ import { IdentifiableError } from '@/misc/identifiable-error.js';
|
|||
import { LatestNoteService } from '@/core/LatestNoteService.js';
|
||||
import { CollapsedQueue } from '@/misc/collapsed-queue.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { NoteVisibilityService } from '@/core/NoteVisibilityService.js';
|
||||
import { isPureRenote } from '@/misc/is-renote.js';
|
||||
|
||||
|
|
@ -224,9 +225,10 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
private userBlockingService: UserBlockingService,
|
||||
private cacheService: CacheService,
|
||||
private latestNoteService: LatestNoteService,
|
||||
private readonly timeService: TimeService,
|
||||
private readonly noteVisibilityService: NoteVisibilityService,
|
||||
) {
|
||||
this.updateNotesCountQueue = new CollapsedQueue(process.env.NODE_ENV !== 'test' ? 60 * 1000 * 5 : 0, this.collapseNotesCount, this.performUpdateNotesCount);
|
||||
this.updateNotesCountQueue = new CollapsedQueue(this.timeService, process.env.NODE_ENV !== 'test' ? 60 * 1000 * 5 : 0, this.collapseNotesCount, this.performUpdateNotesCount);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
|
@ -253,7 +255,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
data.channel = await this.channelsRepository.findOneBy({ id: data.reply.channelId });
|
||||
}
|
||||
|
||||
if (data.createdAt == null) data.createdAt = new Date();
|
||||
if (data.createdAt == null) data.createdAt = this.timeService.date;
|
||||
if (data.visibility == null) data.visibility = 'public';
|
||||
if (data.localOnly == null) data.localOnly = false;
|
||||
if (data.channel != null) data.visibility = 'public';
|
||||
|
|
@ -613,7 +615,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
// Increment notes count (user)
|
||||
this.incNotesCountOfUser(user);
|
||||
} else {
|
||||
this.usersRepository.update({ id: user.id }, { updatedAt: new Date() });
|
||||
this.usersRepository.update({ id: user.id }, { updatedAt: this.timeService.date });
|
||||
}
|
||||
|
||||
this.pushToTl(note, user);
|
||||
|
|
@ -657,7 +659,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
}
|
||||
|
||||
if (data.poll && data.poll.expiresAt) {
|
||||
const delay = data.poll.expiresAt.getTime() - Date.now();
|
||||
const delay = data.poll.expiresAt.getTime() - this.timeService.now;
|
||||
this.queueService.endedPollNotificationQueue.add(note.id, {
|
||||
noteId: note.id,
|
||||
}, {
|
||||
|
|
@ -791,7 +793,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
if (data.channel) {
|
||||
this.channelsRepository.increment({ id: data.channel.id }, 'notesCount', 1);
|
||||
this.channelsRepository.update(data.channel.id, {
|
||||
lastNotedAt: new Date(),
|
||||
lastNotedAt: this.timeService.date,
|
||||
});
|
||||
|
||||
this.notesRepository.countBy({
|
||||
|
|
@ -838,7 +840,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
.execute();
|
||||
|
||||
// 30%の確率、3日以内に投稿されたノートの場合ハイライト用ランキング更新
|
||||
if (user.isExplorable && Math.random() < 0.3 && (Date.now() - this.idService.parse(renote.id).date.getTime()) < 1000 * 60 * 60 * 24 * 3) {
|
||||
if (user.isExplorable && Math.random() < 0.3 && (this.timeService.now - this.idService.parse(renote.id).date.getTime()) < 1000 * 60 * 60 * 24 * 3) {
|
||||
const policies = await this.roleService.getUserPolicies(user);
|
||||
if (policies.canTrend) {
|
||||
if (renote.channelId != null) {
|
||||
|
|
@ -905,7 +907,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
private incNotesCountOfUser(user: { id: MiUser['id']; }) {
|
||||
this.usersRepository.createQueryBuilder().update()
|
||||
.set({
|
||||
updatedAt: new Date(),
|
||||
updatedAt: this.timeService.date,
|
||||
notesCount: () => '"notesCount" + 1',
|
||||
})
|
||||
.where('id = :id', { id: user.id })
|
||||
|
|
@ -1064,7 +1066,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
const hibernatedUsers = await this.usersRepository.find({
|
||||
where: {
|
||||
id: In(samples.map(x => x.followerId)),
|
||||
lastActiveDate: LessThan(new Date(Date.now() - (1000 * 60 * 60 * 24 * 50))),
|
||||
lastActiveDate: LessThan(new Date(this.timeService.now - (1000 * 60 * 60 * 24 * 50))),
|
||||
},
|
||||
select: ['id'],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ import { isQuote, isRenote } from '@/misc/is-renote.js';
|
|||
import { LatestNoteService } from '@/core/LatestNoteService.js';
|
||||
import { ApLogService } from '@/core/ApLogService.js';
|
||||
import type Logger from '@/logger.js';
|
||||
import { LoggerService } from './LoggerService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { LoggerService } from '@/core/LoggerService.js';
|
||||
|
||||
@Injectable()
|
||||
export class NoteDeleteService {
|
||||
|
|
@ -60,6 +61,8 @@ export class NoteDeleteService {
|
|||
private instanceChart: InstanceChart,
|
||||
private latestNoteService: LatestNoteService,
|
||||
private readonly apLogService: ApLogService,
|
||||
private readonly timeService: TimeService,
|
||||
|
||||
loggerService: LoggerService,
|
||||
) {
|
||||
this.logger = loggerService.getLogger('note-delete-service');
|
||||
|
|
@ -71,7 +74,7 @@ export class NoteDeleteService {
|
|||
* @param note 投稿
|
||||
*/
|
||||
async delete(user: { id: MiUser['id']; uri: MiUser['uri']; host: MiUser['host']; isBot: MiUser['isBot']; }, note: MiNote, quiet = false, deleter?: MiUser) {
|
||||
const deletedAt = new Date();
|
||||
const deletedAt = this.timeService.date;
|
||||
const cascadingNotes = await this.findCascadingNotes(note);
|
||||
|
||||
if (note.replyId) {
|
||||
|
|
@ -127,7 +130,7 @@ export class NoteDeleteService {
|
|||
// Decrement notes count (user)
|
||||
this.decNotesCountOfUser(user);
|
||||
} else {
|
||||
this.usersRepository.update({ id: user.id }, { updatedAt: new Date() });
|
||||
this.usersRepository.update({ id: user.id }, { updatedAt: this.timeService.date });
|
||||
}
|
||||
|
||||
if (this.meta.enableStatsForFederatedInstances) {
|
||||
|
|
@ -179,7 +182,7 @@ export class NoteDeleteService {
|
|||
private decNotesCountOfUser(user: { id: MiUser['id']; }) {
|
||||
this.usersRepository.createQueryBuilder().update()
|
||||
.set({
|
||||
updatedAt: new Date(),
|
||||
updatedAt: this.timeService.date,
|
||||
notesCount: () => '"notesCount" - 1',
|
||||
})
|
||||
.where('id = :id', { id: user.id })
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ import { IdentifiableError } from '@/misc/identifiable-error.js';
|
|||
import { LatestNoteService } from '@/core/LatestNoteService.js';
|
||||
import { CollapsedQueue } from '@/misc/collapsed-queue.js';
|
||||
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { NoteVisibilityService } from '@/core/NoteVisibilityService.js';
|
||||
import { isPureRenote } from '@/misc/is-renote.js';
|
||||
|
||||
|
|
@ -221,9 +222,10 @@ export class NoteEditService implements OnApplicationShutdown {
|
|||
private cacheService: CacheService,
|
||||
private latestNoteService: LatestNoteService,
|
||||
private noteCreateService: NoteCreateService,
|
||||
private readonly timeService: TimeService,
|
||||
private readonly noteVisibilityService: NoteVisibilityService,
|
||||
) {
|
||||
this.updateNotesCountQueue = new CollapsedQueue(process.env.NODE_ENV !== 'test' ? 60 * 1000 * 5 : 0, this.collapseNotesCount, this.performUpdateNotesCount);
|
||||
this.updateNotesCountQueue = new CollapsedQueue(this.timeService, process.env.NODE_ENV !== 'test' ? 60 * 1000 * 5 : 0, this.collapseNotesCount, this.performUpdateNotesCount);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
|
@ -272,7 +274,7 @@ export class NoteEditService implements OnApplicationShutdown {
|
|||
data.channel = await this.channelsRepository.findOneBy({ id: data.reply.channelId });
|
||||
}
|
||||
|
||||
if (data.updatedAt == null) data.updatedAt = new Date();
|
||||
if (data.updatedAt == null) data.updatedAt = this.timeService.date;
|
||||
if (data.visibility == null) data.visibility = 'public';
|
||||
if (data.localOnly == null) data.localOnly = false;
|
||||
if (data.channel != null) data.visibility = 'public';
|
||||
|
|
@ -493,12 +495,12 @@ export class NoteEditService implements OnApplicationShutdown {
|
|||
cw: update.cw || undefined,
|
||||
fileIds: undefined,
|
||||
oldDate: exists ? oldnote.updatedAt as Date : this.idService.parse(oldnote.id).date,
|
||||
updatedAt: new Date(),
|
||||
updatedAt: this.timeService.date,
|
||||
});
|
||||
|
||||
const note = new MiNote({
|
||||
id: oldnote.id,
|
||||
updatedAt: data.updatedAt ? data.updatedAt : new Date(),
|
||||
updatedAt: data.updatedAt ? data.updatedAt : this.timeService.date,
|
||||
fileIds: data.files ? data.files.map(file => file.id) : [],
|
||||
replyId: oldnote.replyId,
|
||||
renoteId: data.renote ? data.renote.id : null,
|
||||
|
|
@ -619,13 +621,13 @@ export class NoteEditService implements OnApplicationShutdown {
|
|||
}
|
||||
}
|
||||
|
||||
this.usersRepository.update({ id: user.id }, { updatedAt: new Date() });
|
||||
this.usersRepository.update({ id: user.id }, { updatedAt: this.timeService.date });
|
||||
|
||||
// ハッシュタグ更新
|
||||
this.pushToTl(note, user);
|
||||
|
||||
if (data.poll && data.poll.expiresAt) {
|
||||
const delay = data.poll.expiresAt.getTime() - Date.now();
|
||||
const delay = data.poll.expiresAt.getTime() - this.timeService.now;
|
||||
this.queueService.endedPollNotificationQueue.remove(`pollEnd:${note.id}`);
|
||||
this.queueService.endedPollNotificationQueue.add(note.id, {
|
||||
noteId: note.id,
|
||||
|
|
@ -737,7 +739,7 @@ export class NoteEditService implements OnApplicationShutdown {
|
|||
if (data.channel) {
|
||||
this.channelsRepository.increment({ id: data.channel.id }, 'notesCount', 1);
|
||||
this.channelsRepository.update(data.channel.id, {
|
||||
lastNotedAt: new Date(),
|
||||
lastNotedAt: this.timeService.date,
|
||||
});
|
||||
|
||||
this.notesRepository.countBy({
|
||||
|
|
@ -935,7 +937,7 @@ export class NoteEditService implements OnApplicationShutdown {
|
|||
const hibernatedUsers = await this.usersRepository.find({
|
||||
where: {
|
||||
id: In(samples.map(x => x.followerId)),
|
||||
lastActiveDate: LessThan(new Date(Date.now() - (1000 * 60 * 60 * 24 * 50))),
|
||||
lastActiveDate: LessThan(new Date(this.timeService.now - (1000 * 60 * 60 * 24 * 50))),
|
||||
},
|
||||
select: ['id'],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import type { Packed } from '@/misc/json-schema.js';
|
|||
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { awaitAll } from '@/misc/prelude/await-all.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
|
|
@ -70,6 +71,7 @@ export class NoteVisibilityService {
|
|||
private readonly cacheService: CacheService,
|
||||
private readonly idService: IdService,
|
||||
private readonly federatedInstanceService: FederatedInstanceService,
|
||||
private readonly timeService: TimeService,
|
||||
) {}
|
||||
|
||||
@bindThis
|
||||
|
|
@ -293,7 +295,7 @@ export class NoteVisibilityService {
|
|||
const createdAt = new Date(note.createdAt).valueOf();
|
||||
|
||||
// I don't understand this logic, but I tried to break it out for readability
|
||||
const followersOnlyOpt1 = followersOnlyBefore <= 0 && (Date.now() - createdAt > 0 - followersOnlyBefore);
|
||||
const followersOnlyOpt1 = followersOnlyBefore <= 0 && (this.timeService.now - createdAt > 0 - followersOnlyBefore);
|
||||
const followersOnlyOpt2 = followersOnlyBefore > 0 && (createdAt < followersOnlyBefore);
|
||||
if (followersOnlyOpt1 || followersOnlyOpt2) {
|
||||
note.visibility = 'followers';
|
||||
|
|
@ -323,7 +325,7 @@ export class NoteVisibilityService {
|
|||
const createdAt = note.createdAt.valueOf();
|
||||
|
||||
// I don't understand this logic, but I tried to break it out for readability
|
||||
const hiddenOpt1 = hiddenBefore <= 0 && (Date.now() - createdAt > 0 - hiddenBefore);
|
||||
const hiddenOpt1 = hiddenBefore <= 0 && (this.timeService.now - createdAt > 0 - hiddenBefore);
|
||||
const hiddenOpt2 = hiddenBefore > 0 && (createdAt < hiddenBefore);
|
||||
if (hiddenOpt1 || hiddenOpt2) return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import type { Config } from '@/config.js';
|
|||
import { UserListService } from '@/core/UserListService.js';
|
||||
import { FilterUnionByProperty, groupedNotificationTypes, obsoleteNotificationTypes } from '@/types.js';
|
||||
import { trackPromise } from '@/misc/promise-tracker.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
@Injectable()
|
||||
export class NotificationService implements OnApplicationShutdown {
|
||||
|
|
@ -43,6 +44,7 @@ export class NotificationService implements OnApplicationShutdown {
|
|||
private pushNotificationService: PushNotificationService,
|
||||
private cacheService: CacheService,
|
||||
private userListService: UserListService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -146,7 +148,7 @@ export class NotificationService implements OnApplicationShutdown {
|
|||
}
|
||||
}
|
||||
|
||||
const createdAt = new Date();
|
||||
const createdAt = this.timeService.date;
|
||||
let notification: FilterUnionByProperty<MiNotification, 'type', T>;
|
||||
let redisId: string;
|
||||
|
||||
|
|
@ -187,7 +189,7 @@ export class NotificationService implements OnApplicationShutdown {
|
|||
// 2秒経っても(今回作成した)通知が既読にならなかったら「未読の通知がありますよ」イベントを発行する
|
||||
// テスト通知の場合は即時発行
|
||||
const interval = notification.type === 'test' ? 0 : 2000;
|
||||
setTimeout(interval, 'unread notification', { signal: this.#shutdownController.signal }).then(async () => {
|
||||
this.timeService.startPromiseTimer(interval, 'unread notification', { signal: this.#shutdownController.signal }).then(async () => {
|
||||
const latestReadNotificationId = await this.redisClient.get(`latestReadNotification:${notifieeId}`);
|
||||
if (latestReadNotificationId && (latestReadNotificationId >= redisId)) return;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { getNoteSummary } from '@/misc/get-note-summary.js';
|
|||
import type { MiMeta, MiSwSubscription, SwSubscriptionsRepository } from '@/models/_.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { CacheManagementService, type ManagedQuantumKVCache } from '@/core/CacheManagementService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
// Defined also packages/sw/types.ts#L13
|
||||
type PushNotificationsTypes = {
|
||||
|
|
@ -62,6 +63,9 @@ export class PushNotificationService {
|
|||
|
||||
@Inject(DI.swSubscriptionsRepository)
|
||||
private swSubscriptionsRepository: SwSubscriptionsRepository,
|
||||
|
||||
private readonly timeService: TimeService,
|
||||
|
||||
cacheManagementService: CacheManagementService,
|
||||
) {
|
||||
this.subscriptionsCache = cacheManagementService.createQuantumKVCache<MiSwSubscription[]>('userSwSubscriptions', {
|
||||
|
|
@ -98,7 +102,7 @@ export class PushNotificationService {
|
|||
type,
|
||||
body: (type === 'notification' || type === 'unreadAntennaNote') ? truncateBody(type, body) : body,
|
||||
userId,
|
||||
dateTime: Date.now(),
|
||||
dateTime: this.timeService.now,
|
||||
}), {
|
||||
proxy: this.config.proxy,
|
||||
}).catch((err: any) => {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { DI } from '@/di-symbols.js';
|
|||
import { bindThis } from '@/decorators.js';
|
||||
import type { Antenna } from '@/server/api/endpoints/i/import-antennas.js';
|
||||
import { ApRequestCreator } from '@/core/activitypub/ApRequestService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import type { SystemWebhookPayload } from '@/core/SystemWebhookService.js';
|
||||
import type { MiNote } from '@/models/Note.js';
|
||||
import { type UserWebhookPayload } from './UserWebhookService.js';
|
||||
|
|
@ -71,6 +72,8 @@ export class QueueService implements OnModuleInit {
|
|||
@Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue,
|
||||
@Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue,
|
||||
@Inject('queue:scheduleNotePost') public ScheduleNotePostQueue: ScheduleNotePostQueue,
|
||||
|
||||
private readonly timeService: TimeService,
|
||||
) {}
|
||||
|
||||
@bindThis
|
||||
|
|
@ -791,7 +794,7 @@ export class QueueService implements OnModuleInit {
|
|||
userId: webhook.userId,
|
||||
to: webhook.url,
|
||||
secret: webhook.secret,
|
||||
createdAt: Date.now(),
|
||||
createdAt: this.timeService.now,
|
||||
eventId: randomUUID(),
|
||||
};
|
||||
|
||||
|
|
@ -828,7 +831,7 @@ export class QueueService implements OnModuleInit {
|
|||
webhookId: webhook.id,
|
||||
to: webhook.url,
|
||||
secret: webhook.secret,
|
||||
createdAt: Date.now(),
|
||||
createdAt: this.timeService.now,
|
||||
eventId: randomUUID(),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import { ReactionsBufferingService } from '@/core/ReactionsBufferingService.js';
|
|||
import { PER_NOTE_REACTION_USER_PAIR_CACHE_MAX } from '@/const.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { NoteVisibilityService } from '@/core/NoteVisibilityService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import type { DataSource } from 'typeorm';
|
||||
|
||||
const FALLBACK = '\u2764';
|
||||
|
|
@ -108,6 +109,7 @@ export class ReactionService implements OnModuleInit {
|
|||
private perUserReactionsChart: PerUserReactionsChart,
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly noteVisibilityService: NoteVisibilityService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -222,13 +224,13 @@ export class ReactionService implements OnModuleInit {
|
|||
.execute();
|
||||
}
|
||||
|
||||
this.usersRepository.update({ id: user.id }, { updatedAt: new Date() });
|
||||
this.usersRepository.update({ id: user.id }, { updatedAt: this.timeService.date });
|
||||
|
||||
// 30%の確率、セルフではない、3日以内に投稿されたノートの場合ハイライト用ランキング更新
|
||||
if (
|
||||
Math.random() < 0.3 &&
|
||||
note.userId !== user.id &&
|
||||
(Date.now() - this.idService.parse(note.id).date.getTime()) < 1000 * 60 * 60 * 24 * 3
|
||||
(this.timeService.now - this.idService.parse(note.id).date.getTime()) < 1000 * 60 * 60 * 24 * 3
|
||||
) {
|
||||
const author = await this.cacheService.findUserById(note.userId);
|
||||
if (author.isExplorable) {
|
||||
|
|
@ -338,7 +340,7 @@ export class ReactionService implements OnModuleInit {
|
|||
.execute();
|
||||
}
|
||||
|
||||
this.usersRepository.update({ id: user.id }, { updatedAt: new Date() });
|
||||
this.usersRepository.update({ id: user.id }, { updatedAt: this.timeService.date });
|
||||
|
||||
this.globalEventService.publishNoteStream(note.id, 'unreacted', {
|
||||
reaction: this.decodeReaction(exist.reaction).reaction,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import * as Redis from 'ioredis';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import type { MiNote } from '@/models/Note.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import type { MiUser, NotesRepository } from '@/models/_.js';
|
||||
|
|
@ -31,6 +32,8 @@ export class ReactionsBufferingService implements OnApplicationShutdown {
|
|||
|
||||
@Inject(DI.notesRepository)
|
||||
private notesRepository: NotesRepository,
|
||||
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
this.redisForSub.on('message', this.onMessage);
|
||||
}
|
||||
|
|
@ -62,7 +65,7 @@ export class ReactionsBufferingService implements OnApplicationShutdown {
|
|||
for (let i = 0; i < currentPairs.length; i++) {
|
||||
pipeline.zadd(`${REDIS_PAIR_PREFIX}:${noteId}`, i, currentPairs[i]);
|
||||
}
|
||||
pipeline.zadd(`${REDIS_PAIR_PREFIX}:${noteId}`, Date.now(), `${userId}/${reaction}`);
|
||||
pipeline.zadd(`${REDIS_PAIR_PREFIX}:${noteId}`, this.timeService.now, `${userId}/${reaction}`);
|
||||
pipeline.zremrangebyrank(`${REDIS_PAIR_PREFIX}:${noteId}`, 0, -(PER_NOTE_REACTION_USER_PAIR_CACHE_MAX + 1));
|
||||
await pipeline.exec();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import type { MiUser } from '@/models/User.js';
|
|||
import { IdService } from '@/core/IdService.js';
|
||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
@Injectable()
|
||||
export class RegistryApiService {
|
||||
|
|
@ -20,6 +21,7 @@ export class RegistryApiService {
|
|||
|
||||
private idService: IdService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -31,7 +33,7 @@ export class RegistryApiService {
|
|||
.insert()
|
||||
.values({
|
||||
id: this.idService.gen(),
|
||||
updatedAt: new Date(),
|
||||
updatedAt: this.timeService.date,
|
||||
userId: userId,
|
||||
domain: domain,
|
||||
scope: scope,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { ILink, WebfingerService } from '@/core/WebfingerService.js';
|
|||
import { RemoteLoggerService } from '@/core/RemoteLoggerService.js';
|
||||
import { ApDbResolverService } from '@/core/activitypub/ApDbResolverService.js';
|
||||
import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { renderInlineError } from '@/misc/render-inline-error.js';
|
||||
|
||||
|
|
@ -35,6 +36,7 @@ export class RemoteUserResolveService {
|
|||
private remoteLoggerService: RemoteLoggerService,
|
||||
private apDbResolverService: ApDbResolverService,
|
||||
private apPersonService: ApPersonService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
this.logger = this.remoteLoggerService.logger.createSubLogger('resolve-user');
|
||||
}
|
||||
|
|
@ -81,10 +83,10 @@ export class RemoteUserResolveService {
|
|||
}
|
||||
|
||||
// ユーザー情報が古い場合は、WebFingerからやりなおして返す
|
||||
if (user.lastFetchedAt == null || Date.now() - user.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
|
||||
if (user.lastFetchedAt == null || this.timeService.now - user.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
|
||||
// 繋がらないインスタンスに何回も試行するのを防ぐ, 後続の同様処理の連続試行を防ぐ ため 試行前にも更新する
|
||||
await this.usersRepository.update(user.id, {
|
||||
lastFetchedAt: new Date(),
|
||||
lastFetchedAt: this.timeService.date,
|
||||
});
|
||||
|
||||
const self = await this.resolveSelf(acctLower);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { bindThis } from '@/decorators.js';
|
|||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import type { NotificationService } from '@/core/NotificationService.js';
|
||||
import { Serialized } from '@/types.js';
|
||||
import { ReversiGameEntityService } from './entities/ReversiGameEntityService.js';
|
||||
|
|
@ -43,6 +44,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
|||
private globalEventService: GlobalEventService,
|
||||
private reversiGameEntityService: ReversiGameEntityService,
|
||||
private idService: IdService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -99,8 +101,8 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
|||
// 既にマッチしている対局が無いか探す(3分以内)
|
||||
const games = await this.reversiGamesRepository.find({
|
||||
where: [
|
||||
{ id: MoreThan(this.idService.gen(Date.now() - 1000 * 60 * 3)), user1Id: me.id, user2Id: targetUser.id, isStarted: false },
|
||||
{ id: MoreThan(this.idService.gen(Date.now() - 1000 * 60 * 3)), user1Id: targetUser.id, user2Id: me.id, isStarted: false },
|
||||
{ id: MoreThan(this.idService.gen(this.timeService.now - 1000 * 60 * 3)), user1Id: me.id, user2Id: targetUser.id, isStarted: false },
|
||||
{ id: MoreThan(this.idService.gen(this.timeService.now - 1000 * 60 * 3)), user1Id: targetUser.id, user2Id: me.id, isStarted: false },
|
||||
],
|
||||
relations: ['user1', 'user2'],
|
||||
order: { id: 'DESC' },
|
||||
|
|
@ -113,7 +115,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
|||
//#region 相手から既に招待されてないか確認
|
||||
const invitations = await this.redisClient.zrange(
|
||||
`reversi:matchSpecific:${me.id}`,
|
||||
Date.now() - INVITATION_TIMEOUT_MS,
|
||||
this.timeService.now - INVITATION_TIMEOUT_MS,
|
||||
'+inf',
|
||||
'BYSCORE');
|
||||
|
||||
|
|
@ -129,7 +131,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
|||
//#endregion
|
||||
|
||||
const redisPipeline = this.redisClient.pipeline();
|
||||
redisPipeline.zadd(`reversi:matchSpecific:${targetUser.id}`, Date.now(), me.id);
|
||||
redisPipeline.zadd(`reversi:matchSpecific:${targetUser.id}`, this.timeService.now, me.id);
|
||||
redisPipeline.expire(`reversi:matchSpecific:${targetUser.id}`, 120, 'NX');
|
||||
await redisPipeline.exec();
|
||||
|
||||
|
|
@ -146,8 +148,8 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
|||
// 既にマッチしている対局が無いか探す(3分以内)
|
||||
const games = await this.reversiGamesRepository.find({
|
||||
where: [
|
||||
{ id: MoreThan(this.idService.gen(Date.now() - 1000 * 60 * 3)), user1Id: me.id, isStarted: false },
|
||||
{ id: MoreThan(this.idService.gen(Date.now() - 1000 * 60 * 3)), user2Id: me.id, isStarted: false },
|
||||
{ id: MoreThan(this.idService.gen(this.timeService.now - 1000 * 60 * 3)), user1Id: me.id, isStarted: false },
|
||||
{ id: MoreThan(this.idService.gen(this.timeService.now - 1000 * 60 * 3)), user2Id: me.id, isStarted: false },
|
||||
],
|
||||
relations: ['user1', 'user2'],
|
||||
order: { id: 'DESC' },
|
||||
|
|
@ -160,7 +162,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
|||
//#region まず自分宛ての招待を探す
|
||||
const invitations = await this.redisClient.zrange(
|
||||
`reversi:matchSpecific:${me.id}`,
|
||||
Date.now() - INVITATION_TIMEOUT_MS,
|
||||
this.timeService.now - INVITATION_TIMEOUT_MS,
|
||||
'+inf',
|
||||
'BYSCORE');
|
||||
|
||||
|
|
@ -201,9 +203,9 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
|||
} else {
|
||||
const redisPipeline = this.redisClient.pipeline();
|
||||
if (options.noIrregularRules) {
|
||||
redisPipeline.zadd('reversi:matchAny', Date.now(), me.id + ':noIrregularRules');
|
||||
redisPipeline.zadd('reversi:matchAny', this.timeService.now, me.id + ':noIrregularRules');
|
||||
} else {
|
||||
redisPipeline.zadd('reversi:matchAny', Date.now(), me.id);
|
||||
redisPipeline.zadd('reversi:matchAny', this.timeService.now, me.id);
|
||||
}
|
||||
redisPipeline.expire('reversi:matchAny', 15, 'NX');
|
||||
await redisPipeline.exec();
|
||||
|
|
@ -224,7 +226,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
|||
@bindThis
|
||||
public async cleanOutdatedGames() {
|
||||
await this.reversiGamesRepository.delete({
|
||||
id: LessThan(this.idService.gen(Date.now() - 1000 * 60 * 10)),
|
||||
id: LessThan(this.idService.gen(this.timeService.now - 1000 * 60 * 10)),
|
||||
isStarted: false,
|
||||
});
|
||||
}
|
||||
|
|
@ -269,7 +271,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
|||
|
||||
if (isBothReady) {
|
||||
// 3秒後、両者readyならゲーム開始
|
||||
setTimeout(async () => {
|
||||
this.timeService.startTimer(async () => {
|
||||
const freshGame = await this.get(game.id);
|
||||
if (freshGame == null || freshGame.isStarted || freshGame.isEnded) return;
|
||||
if (!freshGame.user1Ready || !freshGame.user2Ready) return;
|
||||
|
|
@ -323,7 +325,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
|||
const updatedGame = await this.reversiGamesRepository.createQueryBuilder().update()
|
||||
.set({
|
||||
...this.getBakeProps(game),
|
||||
startedAt: new Date(),
|
||||
startedAt: this.timeService.date,
|
||||
isStarted: true,
|
||||
black: bw,
|
||||
map: game.map,
|
||||
|
|
@ -368,7 +370,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
|||
.set({
|
||||
...this.getBakeProps(game),
|
||||
isEnded: true,
|
||||
endedAt: new Date(),
|
||||
endedAt: this.timeService.date,
|
||||
winnerId: winnerId,
|
||||
surrenderedUserId: reason === 'surrender' ? (winnerId === game.user1Id ? game.user2Id : game.user1Id) : null,
|
||||
timeoutUserId: reason === 'timeout' ? (winnerId === game.user1Id ? game.user2Id : game.user1Id) : null,
|
||||
|
|
@ -392,7 +394,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
|||
public async getInvitations(user: MiUser): Promise<MiUser['id'][]> {
|
||||
const invitations = await this.redisClient.zrange(
|
||||
`reversi:matchSpecific:${user.id}`,
|
||||
Date.now() - INVITATION_TIMEOUT_MS,
|
||||
this.timeService.now - INVITATION_TIMEOUT_MS,
|
||||
'+inf',
|
||||
'BYSCORE');
|
||||
return invitations;
|
||||
|
|
@ -475,7 +477,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
|||
const logs = Reversi.Serializer.deserializeLogs(game.logs);
|
||||
|
||||
const log = {
|
||||
time: Date.now(),
|
||||
time: this.timeService.now,
|
||||
player: myColor,
|
||||
operation: 'put',
|
||||
pos,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import { UtilityService } from '@/core/UtilityService.js';
|
|||
import { UserService } from '@/core/UserService.js';
|
||||
import { SystemAccountService } from '@/core/SystemAccountService.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
@Injectable()
|
||||
export class SignupService {
|
||||
|
|
@ -46,6 +47,7 @@ export class SignupService {
|
|||
private systemAccountService: SystemAccountService,
|
||||
private metaService: MetaService,
|
||||
private usersChart: UsersChart,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -150,7 +152,7 @@ export class SignupService {
|
|||
}));
|
||||
|
||||
await transactionalEntityManager.save(new MiUsedUsername({
|
||||
createdAt: new Date(),
|
||||
createdAt: this.timeService.date,
|
||||
username: username.toLowerCase(),
|
||||
}));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { genRsaKeyPair } from '@/misc/gen-key-pair.js';
|
|||
import { CacheManagementService, type ManagedMemoryKVCache } from '@/core/CacheManagementService.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { InternalEventService } from '@/core/InternalEventService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
export const SYSTEM_ACCOUNT_TYPES = ['actor', 'relay', 'proxy'] as const;
|
||||
|
||||
|
|
@ -51,6 +52,8 @@ export class SystemAccountService implements OnApplicationShutdown {
|
|||
private idService: IdService,
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly internalEventService: InternalEventService,
|
||||
private readonly timeService: TimeService,
|
||||
|
||||
cacheManagementService: CacheManagementService,
|
||||
) {
|
||||
this.cache = cacheManagementService.createMemoryKVCache<string>(1000 * 60 * 10); // 10m
|
||||
|
|
@ -173,7 +176,7 @@ export class SystemAccountService implements OnApplicationShutdown {
|
|||
});
|
||||
|
||||
await transactionalEntityManager.insert(MiUsedUsername, {
|
||||
createdAt: new Date(),
|
||||
createdAt: this.timeService.date,
|
||||
username: extra.username.toLowerCase(),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import { AbuseReportResolveType } from '@/models/AbuseUserReport.js';
|
|||
import { ModeratorInactivityRemainingTime } from '@/queue/processors/CheckModeratorsActivityProcessorService.js';
|
||||
import { CacheManagementService, type ManagedMemorySingleCache } from '@/core/CacheManagementService.js';
|
||||
import { InternalEventService } from '@/core/InternalEventService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||
|
||||
export type AbuseReportPayload = {
|
||||
|
|
@ -64,6 +65,7 @@ export class SystemWebhookService implements OnApplicationShutdown {
|
|||
private moderationLogService: ModerationLogService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private readonly internalEventService: InternalEventService,
|
||||
private readonly timeService: TimeService,
|
||||
|
||||
cacheManagementService: CacheManagementService,
|
||||
) {
|
||||
|
|
@ -156,7 +158,7 @@ export class SystemWebhookService implements OnApplicationShutdown {
|
|||
): Promise<MiSystemWebhook> {
|
||||
const beforeEntity = await this.systemWebhooksRepository.findOneByOrFail({ id: params.id });
|
||||
await this.systemWebhooksRepository.update(beforeEntity.id, {
|
||||
updatedAt: new Date(),
|
||||
updatedAt: this.timeService.date,
|
||||
isActive: params.isActive,
|
||||
name: params.name,
|
||||
on: params.on,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { CollapsedQueue } from '@/misc/collapsed-queue.js';
|
|||
import { bindThis } from '@/decorators.js';
|
||||
import { MiNote } from '@/models/Note.js';
|
||||
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
type UpdateInstanceJob = {
|
||||
latestRequestReceivedAt: Date,
|
||||
|
|
@ -19,8 +20,9 @@ type UpdateInstanceJob = {
|
|||
export class UpdateInstanceQueue extends CollapsedQueue<MiNote['id'], UpdateInstanceJob> implements OnApplicationShutdown {
|
||||
constructor(
|
||||
private readonly federatedInstanceService: FederatedInstanceService,
|
||||
timeService: TimeService,
|
||||
) {
|
||||
super(process.env.NODE_ENV !== 'test' ? 60 * 1000 * 5 : 0, (id, job) => this.collapseUpdateInstanceJobs(id, job), (id, job) => this.performUpdateInstance(id, job));
|
||||
super(timeService, process.env.NODE_ENV !== 'test' ? 60 * 1000 * 5 : 0, (id, job) => this.collapseUpdateInstanceJobs(id, job), (id, job) => this.performUpdateInstance(id, job));
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
|
@ -38,7 +40,7 @@ export class UpdateInstanceQueue extends CollapsedQueue<MiNote['id'], UpdateInst
|
|||
@bindThis
|
||||
private async performUpdateInstance(id: string, job: UpdateInstanceJob) {
|
||||
await this.federatedInstanceService.update(id, {
|
||||
latestRequestReceivedAt: new Date(),
|
||||
latestRequestReceivedAt: this.timeService.date,
|
||||
isNotResponding: false,
|
||||
// もしサーバーが死んでるために配信が止まっていた場合には自動的に復活させてあげる
|
||||
suspensionState: job.shouldUnsuspend ? 'none' : undefined,
|
||||
|
|
|
|||
|
|
@ -11,12 +11,9 @@ import { bindThis } from '@/decorators.js';
|
|||
import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { Packed } from '@/misc/json-schema.js';
|
||||
|
||||
function defaultActiveThreshold() {
|
||||
return new Date(Date.now() - 1000 * 60 * 60 * 24 * 30);
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class UserSearchService {
|
||||
constructor(
|
||||
|
|
@ -36,9 +33,14 @@ export class UserSearchService {
|
|||
private mutingsRepository: MutingsRepository,
|
||||
|
||||
private userEntityService: UserEntityService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
private defaultActiveThreshold() {
|
||||
return new Date(this.timeService.now - 1000 * 60 * 60 * 24 * 30);
|
||||
}
|
||||
|
||||
/**
|
||||
* ユーザ名とホスト名によるユーザ検索を行う.
|
||||
*
|
||||
|
|
@ -120,7 +122,7 @@ export class UserSearchService {
|
|||
},
|
||||
) {
|
||||
// デフォルト30日以内に更新されたユーザーをアクティブユーザーとする
|
||||
const activeThreshold = params.activeThreshold ?? defaultActiveThreshold();
|
||||
const activeThreshold = params.activeThreshold ?? this.defaultActiveThreshold();
|
||||
|
||||
const followingUserQuery = this.followingsRepository.createQueryBuilder('following')
|
||||
.select('following.followeeId')
|
||||
|
|
@ -166,7 +168,7 @@ export class UserSearchService {
|
|||
activeThreshold?: Date,
|
||||
}) {
|
||||
// デフォルト30日以内に更新されたユーザーをアクティブユーザーとする
|
||||
const activeThreshold = params.activeThreshold ?? defaultActiveThreshold();
|
||||
const activeThreshold = params.activeThreshold ?? this.defaultActiveThreshold();
|
||||
|
||||
const activeUserQuery = this.generateUserQueryBuilder(params)
|
||||
.andWhere(new Brackets(qb => {
|
||||
|
|
@ -218,7 +220,7 @@ export class UserSearchService {
|
|||
offset: number;
|
||||
origin: 'local' | 'remote' | 'combined';
|
||||
}> = {}) {
|
||||
const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日
|
||||
const activeThreshold = new Date(this.timeService.now - (1000 * 60 * 60 * 24 * 30)); // 30日
|
||||
|
||||
const isUsername = query.startsWith('@') && !query.includes(' ') && query.indexOf('@', 1) === -1;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { bindThis } from '@/decorators.js';
|
|||
import { SystemWebhookService } from '@/core/SystemWebhookService.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
|
|
@ -22,6 +23,7 @@ export class UserService {
|
|||
private systemWebhookService: SystemWebhookService,
|
||||
private userEntityService: UserEntityService,
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -30,7 +32,7 @@ export class UserService {
|
|||
if (user.isHibernated) {
|
||||
const result = await this.usersRepository.createQueryBuilder().update()
|
||||
.set({
|
||||
lastActiveDate: new Date(),
|
||||
lastActiveDate: this.timeService.date,
|
||||
})
|
||||
.where('id = :id', { id: user.id })
|
||||
.returning('*')
|
||||
|
|
@ -54,7 +56,7 @@ export class UserService {
|
|||
}
|
||||
} else {
|
||||
this.usersRepository.update(user.id, {
|
||||
lastActiveDate: new Date(),
|
||||
lastActiveDate: this.timeService.date,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import { bindThis } from '@/decorators.js';
|
|||
import { MiUser } from '@/models/_.js';
|
||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||
import { LoggerService } from '@/core/LoggerService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import Logger from '@/logger.js';
|
||||
import type {
|
||||
AuthenticationResponseJSON,
|
||||
|
|
@ -44,6 +45,9 @@ export class WebAuthnService {
|
|||
|
||||
@Inject(DI.userSecurityKeysRepository)
|
||||
private userSecurityKeysRepository: UserSecurityKeysRepository,
|
||||
|
||||
private readonly timeService: TimeService,
|
||||
|
||||
loggerService: LoggerService,
|
||||
) {
|
||||
this.logger = loggerService.getLogger('web-authn');
|
||||
|
|
@ -239,7 +243,7 @@ export class WebAuthnService {
|
|||
await this.userSecurityKeysRepository.update({
|
||||
id: response.id,
|
||||
}, {
|
||||
lastUsed: new Date(),
|
||||
lastUsed: this.timeService.date,
|
||||
counter: authenticationInfo.newCounter,
|
||||
credentialDeviceType: authenticationInfo.credentialDeviceType,
|
||||
credentialBackedUp: authenticationInfo.credentialBackedUp,
|
||||
|
|
@ -321,7 +325,7 @@ export class WebAuthnService {
|
|||
id: response.id,
|
||||
userId: userId,
|
||||
}, {
|
||||
lastUsed: new Date(),
|
||||
lastUsed: this.timeService.date,
|
||||
counter: authenticationInfo.newCounter,
|
||||
credentialDeviceType: authenticationInfo.credentialDeviceType,
|
||||
credentialBackedUp: authenticationInfo.credentialBackedUp,
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import { FetchInstanceMetadataService } from '@/core/FetchInstanceMetadataServic
|
|||
import { UpdateInstanceQueue } from '@/core/UpdateInstanceQueue.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { NoteVisibilityService } from '@/core/NoteVisibilityService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { getApHrefNullable, getApId, getApIds, getApType, getNullableApId, isAccept, isActor, isAdd, isAnnounce, isApObject, isBlock, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isDislike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost, isActivity, IObjectWithId } from './type.js';
|
||||
import { ApNoteService } from './models/ApNoteService.js';
|
||||
import { ApLoggerService } from './ApLoggerService.js';
|
||||
|
|
@ -102,6 +103,7 @@ export class ApInboxService {
|
|||
private readonly updateInstanceQueue: UpdateInstanceQueue,
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly noteVisibilityService: NoteVisibilityService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
this.logger = this.apLoggerService.logger;
|
||||
}
|
||||
|
|
@ -150,7 +152,7 @@ export class ApInboxService {
|
|||
|
||||
// ついでにリモートユーザーの情報が古かったら更新しておく
|
||||
if (actor.uri) {
|
||||
if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
|
||||
if (actor.lastFetchedAt == null || this.timeService.now - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
|
||||
setImmediate(() => {
|
||||
// 同一ユーザーの情報を再度処理するので、使用済みのresolverを再利用してはいけない
|
||||
this.apPersonService.updatePerson(actor.uri)
|
||||
|
|
@ -431,7 +433,7 @@ export class ApInboxService {
|
|||
if (i == null) return;
|
||||
|
||||
this.updateInstanceQueue.enqueue(i.id, {
|
||||
latestRequestReceivedAt: new Date(),
|
||||
latestRequestReceivedAt: this.timeService.date,
|
||||
shouldUnsuspend: i.suspensionState === 'autoSuspendedForNotResponding',
|
||||
});
|
||||
|
||||
|
|
@ -446,7 +448,7 @@ export class ApInboxService {
|
|||
return await this.performOneActivity(actor, activity, resolver)
|
||||
.finally(() => {
|
||||
// Update user (adapted from performActivity)
|
||||
if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
|
||||
if (actor.lastFetchedAt == null || this.timeService.now - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
|
||||
setImmediate(() => {
|
||||
// Don't re-use the resolver, or it may throw recursion errors.
|
||||
// Instead, create a new resolver with an appropriately-reduced recursion limit.
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import { UtilityService } from '@/core/UtilityService.js';
|
|||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { isPureRenote, isQuote, isRenote } from '@/misc/is-renote.js';
|
||||
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { JsonLdService } from './JsonLdService.js';
|
||||
import { ApMfmService } from './ApMfmService.js';
|
||||
import { CONTEXT } from './misc/contexts.js';
|
||||
|
|
@ -80,6 +81,7 @@ export class ApRendererService {
|
|||
private readonly queryService: QueryService,
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly federatedInstanceService: FederatedInstanceService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +176,7 @@ export class ApRendererService {
|
|||
type: 'Delete',
|
||||
actor: this.userEntityService.genLocalUserUri(user.id),
|
||||
object,
|
||||
published: new Date().toISOString(),
|
||||
published: this.timeService.date.toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -196,7 +198,7 @@ export class ApRendererService {
|
|||
id: `${this.config.url}/emojis/${emoji.name}`,
|
||||
type: 'Emoji',
|
||||
name: `:${emoji.name}:`,
|
||||
updated: emoji.updatedAt != null ? emoji.updatedAt.toISOString() : new Date().toISOString(),
|
||||
updated: emoji.updatedAt != null ? emoji.updatedAt.toISOString() : this.timeService.date.toISOString(),
|
||||
icon: {
|
||||
type: 'Image',
|
||||
mediaType: emoji.type ?? 'image/png',
|
||||
|
|
@ -534,7 +536,7 @@ export class ApRendererService {
|
|||
|
||||
const asPoll = poll ? {
|
||||
type: 'Question',
|
||||
[poll.expiresAt && poll.expiresAt < new Date() ? 'closed' : 'endTime']: poll.expiresAt,
|
||||
[poll.expiresAt && poll.expiresAt < this.timeService.date ? 'closed' : 'endTime']: poll.expiresAt,
|
||||
[poll.multiple ? 'anyOf' : 'oneOf']: poll.choices.map((text, i) => ({
|
||||
type: 'Note',
|
||||
name: text,
|
||||
|
|
@ -755,21 +757,21 @@ export class ApRendererService {
|
|||
...(id ? { id } : {}),
|
||||
actor: this.userEntityService.genLocalUserUri(user.id),
|
||||
object,
|
||||
published: new Date().toISOString(),
|
||||
published: this.timeService.date.toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public renderUpdate(object: IObject, user: { id: MiUser['id'] }): IUpdate {
|
||||
// Deterministic activity IDs to allow de-duplication by remote instances
|
||||
const updatedAt = object.updated ? new Date(object.updated).getTime() : Date.now();
|
||||
const updatedAt = object.updated ? new Date(object.updated).getTime() : this.timeService.now;
|
||||
return {
|
||||
id: `${this.config.url}/users/${user.id}#updates/${updatedAt}`,
|
||||
actor: this.userEntityService.genLocalUserUri(user.id),
|
||||
type: 'Update',
|
||||
to: ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
object,
|
||||
published: new Date().toISOString(),
|
||||
published: this.timeService.date.toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -780,7 +782,7 @@ export class ApRendererService {
|
|||
actor: this.userEntityService.genLocalUserUri(user.id),
|
||||
type: 'Create',
|
||||
to: [pollOwner.uri],
|
||||
published: new Date().toISOString(),
|
||||
published: this.timeService.date.toISOString(),
|
||||
object: {
|
||||
id: `${this.config.url}/users/${user.id}#votes/${vote.id}`,
|
||||
type: 'Note',
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { bindThis } from '@/decorators.js';
|
|||
import Logger from '@/logger.js';
|
||||
import { LoggerService } from '@/core/LoggerService.js';
|
||||
import { StatusError } from '@/misc/status-error.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { CONTEXT, PRELOADED_CONTEXTS } from './misc/contexts.js';
|
||||
import { validateContentTypeSetAsJsonLD } from './misc/validator.js';
|
||||
import type { ContextDefinition, JsonLdDocument } from 'jsonld';
|
||||
|
|
@ -56,6 +57,8 @@ export class JsonLdService {
|
|||
|
||||
constructor(
|
||||
private httpRequestService: HttpRequestService,
|
||||
private readonly timeService: TimeService,
|
||||
|
||||
loggerService: LoggerService,
|
||||
) {
|
||||
this.logger = loggerService.getLogger('json-ld');
|
||||
|
|
@ -73,7 +76,7 @@ export class JsonLdService {
|
|||
type: 'RsaSignature2017',
|
||||
creator,
|
||||
nonce: crypto.randomBytes(16).toString('hex'),
|
||||
created: (created ?? new Date()).toISOString(),
|
||||
created: (created ?? this.timeService.date).toISOString(),
|
||||
};
|
||||
|
||||
if (domain) {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import { extractMediaFromHtml } from '@/core/activitypub/misc/extract-media-from
|
|||
import { extractMediaFromMfm } from '@/core/activitypub/misc/extract-media-from-mfm.js';
|
||||
import { getContentByType } from '@/core/activitypub/misc/get-content-by-type.js';
|
||||
import { CustomEmojiService, encodeEmojiKey, isValidEmojiName } from '@/core/CustomEmojiService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { getOneApId, getApId, validPost, isEmoji, getApType, isApObject, isDocument, IApDocument, isLink } from '../type.js';
|
||||
import { ApLoggerService } from '../ApLoggerService.js';
|
||||
import { ApMfmService } from '../ApMfmService.js';
|
||||
|
|
@ -91,6 +92,7 @@ export class ApNoteService implements OnModuleInit {
|
|||
private apLoggerService: ApLoggerService,
|
||||
private readonly apUtilityService: ApUtilityService,
|
||||
private readonly customEmojiService: CustomEmojiService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
this.logger = this.apLoggerService.logger;
|
||||
}
|
||||
|
|
@ -291,7 +293,7 @@ export class ApNoteService implements OnModuleInit {
|
|||
const poll = await this.pollsRepository.findOneByOrFail({ noteId: reply.id });
|
||||
|
||||
const tryCreateVote = async (name: string, index: number): Promise<null> => {
|
||||
if (poll.expiresAt && Date.now() > new Date(poll.expiresAt).getTime()) {
|
||||
if (poll.expiresAt && this.timeService.now > new Date(poll.expiresAt).getTime()) {
|
||||
this.logger.warn(`vote to expired poll from AP: actor=${actor.username}@${actor.host}, note=${note.id}, choice=${name}`);
|
||||
} else if (index >= 0) {
|
||||
this.logger.info(`vote from AP: actor=${actor.username}@${actor.host}, note=${note.id}, choice=${name}`);
|
||||
|
|
@ -470,7 +472,7 @@ export class ApNoteService implements OnModuleInit {
|
|||
const poll = await this.pollsRepository.findOneByOrFail({ noteId: reply.id });
|
||||
|
||||
const tryCreateVote = async (name: string, index: number): Promise<null> => {
|
||||
if (poll.expiresAt && Date.now() > new Date(poll.expiresAt).getTime()) {
|
||||
if (poll.expiresAt && this.timeService.now > new Date(poll.expiresAt).getTime()) {
|
||||
this.logger.warn(`vote to expired poll from AP: actor=${actor.username}@${actor.host}, note=${note.id}, choice=${name}`);
|
||||
} else if (index >= 0) {
|
||||
this.logger.info(`vote from AP: actor=${actor.username}@${actor.host}, note=${note.id}, choice=${name}`);
|
||||
|
|
@ -601,7 +603,7 @@ export class ApNoteService implements OnModuleInit {
|
|||
uri: tag.id,
|
||||
originalUrl: tag.icon.url,
|
||||
publicUrl: tag.icon.url,
|
||||
updatedAt: new Date(),
|
||||
updatedAt: this.timeService.date,
|
||||
// _misskey_license が存在しなければ `null`
|
||||
license: (tag._misskey_license?.freeText ?? null),
|
||||
});
|
||||
|
|
@ -617,7 +619,7 @@ export class ApNoteService implements OnModuleInit {
|
|||
uri: tag.id,
|
||||
originalUrl: tag.icon.url,
|
||||
publicUrl: tag.icon.url,
|
||||
updatedAt: new Date(),
|
||||
updatedAt: this.timeService.date,
|
||||
aliases: [],
|
||||
localOnly: false,
|
||||
isSensitive: tag.sensitive === true,
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import type { AccountMoveService } from '@/core/AccountMoveService.js';
|
|||
import { ApUtilityService } from '@/core/activitypub/ApUtilityService.js';
|
||||
import { AppLockService } from '@/core/AppLockService.js';
|
||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { verifyFieldLinks } from '@/misc/verify-field-link.js';
|
||||
import { isRetryableError } from '@/misc/is-retryable-error.js';
|
||||
import { renderInlineError } from '@/misc/render-inline-error.js';
|
||||
|
|
@ -116,6 +117,7 @@ export class ApPersonService implements OnModuleInit {
|
|||
private readonly utilityService: UtilityService,
|
||||
private readonly apUtilityService: ApUtilityService,
|
||||
private readonly idService: IdService,
|
||||
private readonly timeService: TimeService,
|
||||
|
||||
apLoggerService: ApLoggerService,
|
||||
) {
|
||||
|
|
@ -419,13 +421,13 @@ export class ApPersonService implements OnModuleInit {
|
|||
avatarId: null,
|
||||
bannerId: null,
|
||||
backgroundId: null,
|
||||
lastFetchedAt: new Date(),
|
||||
lastFetchedAt: this.timeService.date,
|
||||
name: truncate(person.name, nameLength),
|
||||
noindex: (person as any).noindex ?? false,
|
||||
enableRss: person.enableRss === true,
|
||||
isLocked: person.manuallyApprovesFollowers,
|
||||
movedToUri: person.movedTo,
|
||||
movedAt: person.movedTo ? new Date() : null,
|
||||
movedAt: person.movedTo ? this.timeService.date : null,
|
||||
alsoKnownAs: person.alsoKnownAs,
|
||||
// We use "!== false" to handle incorrect types, missing / null values, and "default to true" logic.
|
||||
hideOnlineStatus: person.hideOnlineStatus !== false,
|
||||
|
|
@ -634,7 +636,7 @@ export class ApPersonService implements OnModuleInit {
|
|||
const verifiedLinks = await verifyFieldLinks(fields, profileUrls, this.httpRequestService);
|
||||
|
||||
const updates = {
|
||||
lastFetchedAt: new Date(),
|
||||
lastFetchedAt: this.timeService.date,
|
||||
inbox: person.inbox,
|
||||
sharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox ?? null,
|
||||
followersUri: person.followers ? getApId(person.followers) : undefined,
|
||||
|
|
@ -688,7 +690,7 @@ export class ApPersonService implements OnModuleInit {
|
|||
return false;
|
||||
})();
|
||||
|
||||
if (moving) updates.movedAt = new Date();
|
||||
if (moving) updates.movedAt = this.timeService.date;
|
||||
|
||||
// Update user
|
||||
if (!(await this.usersRepository.update({ id: exist.id, isDeleted: false }, updates)).affected) {
|
||||
|
|
@ -894,7 +896,7 @@ export class ApPersonService implements OnModuleInit {
|
|||
for (const note of featuredNotes.filter(x => x != null)) {
|
||||
td -= 1000;
|
||||
transactionalEntityManager.insert(MiUserNotePining, {
|
||||
id: this.idService.gen(Date.now() + td),
|
||||
id: this.idService.gen(this.timeService.now + td),
|
||||
userId: user.id,
|
||||
noteId: note.id,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { Injectable } from '@nestjs/common';
|
|||
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { ChartLoggerService } from '@/core/chart/ChartLoggerService.js';
|
||||
import { TimeService, type TimerHandle } from '@/core/TimeService.js';
|
||||
import Logger from '@/logger.js';
|
||||
import { renderInlineError } from '@/misc/render-inline-error.js';
|
||||
import FederationChart from './charts/federation.js';
|
||||
|
|
@ -26,7 +27,7 @@ import type { OnApplicationShutdown } from '@nestjs/common';
|
|||
@Injectable()
|
||||
export class ChartManagementService implements OnApplicationShutdown {
|
||||
private charts;
|
||||
private saveIntervalId: NodeJS.Timeout;
|
||||
private saveIntervalId: TimerHandle;
|
||||
private readonly logger: Logger;
|
||||
|
||||
constructor(
|
||||
|
|
@ -42,6 +43,8 @@ export class ChartManagementService implements OnApplicationShutdown {
|
|||
private perUserFollowingChart: PerUserFollowingChart,
|
||||
private perUserDriveChart: PerUserDriveChart,
|
||||
private apRequestChart: ApRequestChart,
|
||||
private readonly timeService: TimeService,
|
||||
|
||||
chartLoggerService: ChartLoggerService,
|
||||
) {
|
||||
this.charts = [
|
||||
|
|
@ -64,17 +67,17 @@ export class ChartManagementService implements OnApplicationShutdown {
|
|||
@bindThis
|
||||
public async start() {
|
||||
// 20分おきにメモリ情報をDBに書き込み
|
||||
this.saveIntervalId = setInterval(async () => {
|
||||
this.saveIntervalId = this.timeService.startTimer(async () => {
|
||||
for (const chart of this.charts) {
|
||||
await chart.save();
|
||||
}
|
||||
this.logger.info('All charts saved');
|
||||
}, 1000 * 60 * 20);
|
||||
}, 1000 * 60 * 20, { repeated: true });
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async dispose(): Promise<void> {
|
||||
clearInterval(this.saveIntervalId);
|
||||
this.timeService.stopTimer(this.saveIntervalId);
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
this.logger.info('Saving charts for shutdown...');
|
||||
for (const chart of this.charts) {
|
||||
|
|
|
|||
|
|
@ -54,12 +54,12 @@ export default class ActiveUsersChart extends Chart<typeof schema> { // eslint-d
|
|||
const createdAt = this.idService.parse(user.id).date;
|
||||
await this.commit({
|
||||
'read': [user.id],
|
||||
'registeredWithinWeek': (Date.now() - createdAt.getTime() < week) ? [user.id] : [],
|
||||
'registeredWithinMonth': (Date.now() - createdAt.getTime() < month) ? [user.id] : [],
|
||||
'registeredWithinYear': (Date.now() - createdAt.getTime() < year) ? [user.id] : [],
|
||||
'registeredOutsideWeek': (Date.now() - createdAt.getTime() > week) ? [user.id] : [],
|
||||
'registeredOutsideMonth': (Date.now() - createdAt.getTime() > month) ? [user.id] : [],
|
||||
'registeredOutsideYear': (Date.now() - createdAt.getTime() > year) ? [user.id] : [],
|
||||
'registeredWithinWeek': (this.timeService.now - createdAt.getTime() < week) ? [user.id] : [],
|
||||
'registeredWithinMonth': (this.timeService.now - createdAt.getTime() < month) ? [user.id] : [],
|
||||
'registeredWithinYear': (this.timeService.now - createdAt.getTime() < year) ? [user.id] : [],
|
||||
'registeredOutsideWeek': (this.timeService.now - createdAt.getTime() > week) ? [user.id] : [],
|
||||
'registeredOutsideMonth': (this.timeService.now - createdAt.getTime() > month) ? [user.id] : [],
|
||||
'registeredOutsideYear': (this.timeService.now - createdAt.getTime() > year) ? [user.id] : [],
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { SystemAccountService } from '@/core/SystemAccountService.js';
|
|||
import type { Config } from '@/config.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
@Injectable()
|
||||
export class MetaEntityService {
|
||||
|
|
@ -28,6 +29,7 @@ export class MetaEntityService {
|
|||
private adsRepository: AdsRepository,
|
||||
|
||||
private systemAccountService: SystemAccountService,
|
||||
private readonly timeService: TimeService,
|
||||
) { }
|
||||
|
||||
@bindThis
|
||||
|
|
@ -39,11 +41,11 @@ export class MetaEntityService {
|
|||
}
|
||||
|
||||
const ads = await this.adsRepository.createQueryBuilder('ads')
|
||||
.where('ads.expiresAt > :now', { now: new Date() })
|
||||
.andWhere('ads.startsAt <= :now', { now: new Date() })
|
||||
.where('ads.expiresAt > :now', { now: this.timeService.date })
|
||||
.andWhere('ads.startsAt <= :now', { now: this.timeService.date })
|
||||
.andWhere(new Brackets(qb => {
|
||||
// 曜日のビットフラグを確認する
|
||||
qb.where('ads.dayOfWeek & :dayOfWeek > 0', { dayOfWeek: 1 << new Date().getDay() })
|
||||
qb.where('ads.dayOfWeek & :dayOfWeek > 0', { dayOfWeek: 1 << this.timeService.date.getDay() })
|
||||
.orWhere('ads.dayOfWeek = 0');
|
||||
}))
|
||||
.getMany();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { DebounceLoader } from '@/misc/loader.js';
|
|||
import type { IdService } from '@/core/IdService.js';
|
||||
import type { ReactionsBufferingService } from '@/core/ReactionsBufferingService.js';
|
||||
import { QueryService } from '@/core/QueryService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import { NoteVisibilityService } from '@/core/NoteVisibilityService.js';
|
||||
import type { NoteVisibilityData } from '@/core/NoteVisibilityService.js';
|
||||
|
|
@ -106,6 +107,7 @@ export class NoteEntityService implements OnModuleInit {
|
|||
public readonly noteVisibilityService: NoteVisibilityService,
|
||||
|
||||
private readonly queryService: QueryService,
|
||||
private readonly timeService: TimeService,
|
||||
//private userEntityService: UserEntityService,
|
||||
//private driveFileEntityService: DriveFileEntityService,
|
||||
//private customEmojiService: CustomEmojiService,
|
||||
|
|
@ -134,7 +136,7 @@ export class NoteEntityService implements OnModuleInit {
|
|||
const followersOnlyBefore = packedNote.user.makeNotesFollowersOnlyBefore;
|
||||
if ((followersOnlyBefore != null)
|
||||
&& (
|
||||
(followersOnlyBefore <= 0 && (Date.now() - new Date(packedNote.createdAt).getTime() > 0 - (followersOnlyBefore * 1000)))
|
||||
(followersOnlyBefore <= 0 && (this.timeService.now - new Date(packedNote.createdAt).getTime() > 0 - (followersOnlyBefore * 1000)))
|
||||
|| (followersOnlyBefore > 0 && (new Date(packedNote.createdAt).getTime() < followersOnlyBefore * 1000))
|
||||
)
|
||||
) {
|
||||
|
|
@ -388,7 +390,7 @@ export class NoteEntityService implements OnModuleInit {
|
|||
}
|
||||
|
||||
// パフォーマンスのためノートが作成されてから2秒以上経っていない場合はリアクションを取得しない
|
||||
if (this.idService.parse(note.id).date.getTime() + 2000 > Date.now()) {
|
||||
if (this.idService.parse(note.id).date.getTime() + 2000 > this.timeService.now) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { bindThis } from '@/decorators.js';
|
|||
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { Packed } from '@/misc/json-schema.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
|
||||
@Injectable()
|
||||
export class RoleEntityService {
|
||||
|
|
@ -25,6 +26,7 @@ export class RoleEntityService {
|
|||
private roleAssignmentsRepository: RoleAssignmentsRepository,
|
||||
|
||||
private idService: IdService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -40,7 +42,7 @@ export class RoleEntityService {
|
|||
.andWhere(new Brackets(qb => {
|
||||
qb
|
||||
.where('assign.expiresAt IS NULL')
|
||||
.orWhere('assign.expiresAt > :now', { now: new Date() });
|
||||
.orWhere('assign.expiresAt > :now', { now: this.timeService.date });
|
||||
}))
|
||||
.getCount();
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ import type { RolePolicies, RoleService } from '@/core/RoleService.js';
|
|||
import type { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
|
||||
import type { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||
import type { IdService } from '@/core/IdService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import type { AnnouncementService } from '@/core/AnnouncementService.js';
|
||||
import type { CustomEmojiService } from '@/core/CustomEmojiService.js';
|
||||
import type { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
||||
|
|
@ -153,6 +154,8 @@ export class UserEntityService implements OnModuleInit {
|
|||
|
||||
@Inject(DI.userMemosRepository)
|
||||
private userMemosRepository: UserMemoRepository,
|
||||
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -398,7 +401,7 @@ export class UserEntityService implements OnModuleInit {
|
|||
public getOnlineStatus(user: MiUser): 'unknown' | 'online' | 'active' | 'offline' {
|
||||
if (user.hideOnlineStatus) return 'unknown';
|
||||
if (user.lastActiveDate == null) return 'unknown';
|
||||
const elapsed = Date.now() - user.lastActiveDate.getTime();
|
||||
const elapsed = this.timeService.now - user.lastActiveDate.getTime();
|
||||
return (
|
||||
elapsed < USER_ONLINE_THRESHOLD ? 'online' :
|
||||
elapsed < USER_ACTIVE_THRESHOLD ? 'active' :
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue