convert all remaining backend code to TimeService
This commit is contained in:
parent
9c96dca5a6
commit
3a92471b68
11 changed files with 74 additions and 46 deletions
|
|
@ -145,6 +145,8 @@ export interface PromiseTimerHandle<T = void> extends PromiseLike<T> {
|
|||
@Injectable()
|
||||
export class NativeTimeService extends TimeService<NativeTimer> implements OnApplicationShutdown {
|
||||
public get now(): number {
|
||||
// This is the one place that actually *should* have it
|
||||
// eslint-disable-next-line no-restricted-properties
|
||||
return Date.now();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,16 +14,17 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js';
|
|||
import { type UserWebhookPayload, UserWebhookService } from '@/core/UserWebhookService.js';
|
||||
import { QueueService } from '@/core/QueueService.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { ModeratorInactivityRemainingTime } from '@/queue/processors/CheckModeratorsActivityProcessorService.js';
|
||||
|
||||
const oneDayMillis = 24 * 60 * 60 * 1000;
|
||||
|
||||
function generateDummyUser(override?: Partial<MiUser>): MiUser {
|
||||
function generateDummyUser(now: number, override?: Partial<MiUser>): MiUser {
|
||||
return {
|
||||
id: 'dummy-user-1',
|
||||
updatedAt: new Date(Date.now() - oneDayMillis * 7),
|
||||
lastFetchedAt: new Date(Date.now() - oneDayMillis * 5),
|
||||
lastActiveDate: new Date(Date.now() - oneDayMillis * 3),
|
||||
updatedAt: new Date(now - oneDayMillis * 7),
|
||||
lastFetchedAt: new Date(now - oneDayMillis * 5),
|
||||
lastActiveDate: new Date(now - oneDayMillis * 3),
|
||||
hideOnlineStatus: false,
|
||||
username: 'dummy1',
|
||||
usernameLower: 'dummy1',
|
||||
|
|
@ -132,31 +133,34 @@ function generateDummyNote(override?: Partial<MiNote>): MiNote {
|
|||
};
|
||||
}
|
||||
|
||||
const dummyUser1 = generateDummyUser();
|
||||
const dummyUser2 = generateDummyUser({
|
||||
id: 'dummy-user-2',
|
||||
updatedAt: new Date(Date.now() - oneDayMillis * 30),
|
||||
lastFetchedAt: new Date(Date.now() - oneDayMillis),
|
||||
lastActiveDate: new Date(Date.now() - oneDayMillis),
|
||||
username: 'dummy2',
|
||||
usernameLower: 'dummy2',
|
||||
name: 'DummyUser2',
|
||||
followersCount: 40,
|
||||
followingCount: 50,
|
||||
notesCount: 900,
|
||||
});
|
||||
const dummyUser3 = generateDummyUser({
|
||||
id: 'dummy-user-3',
|
||||
updatedAt: new Date(Date.now() - oneDayMillis * 15),
|
||||
lastFetchedAt: new Date(Date.now() - oneDayMillis * 2),
|
||||
lastActiveDate: new Date(Date.now() - oneDayMillis * 2),
|
||||
username: 'dummy3',
|
||||
usernameLower: 'dummy3',
|
||||
name: 'DummyUser3',
|
||||
followersCount: 60,
|
||||
followingCount: 70,
|
||||
notesCount: 15900,
|
||||
});
|
||||
function makeDummyUsers(now: number) {
|
||||
const dummyUser1 = generateDummyUser(now);
|
||||
const dummyUser2 = generateDummyUser(now, {
|
||||
id: 'dummy-user-2',
|
||||
updatedAt: new Date(now - oneDayMillis * 30),
|
||||
lastFetchedAt: new Date(now - oneDayMillis),
|
||||
lastActiveDate: new Date(now - oneDayMillis),
|
||||
username: 'dummy2',
|
||||
usernameLower: 'dummy2',
|
||||
name: 'DummyUser2',
|
||||
followersCount: 40,
|
||||
followingCount: 50,
|
||||
notesCount: 900,
|
||||
});
|
||||
const dummyUser3 = generateDummyUser(now, {
|
||||
id: 'dummy-user-3',
|
||||
updatedAt: new Date(now - oneDayMillis * 15),
|
||||
lastFetchedAt: new Date(now - oneDayMillis * 2),
|
||||
lastActiveDate: new Date(now - oneDayMillis * 2),
|
||||
username: 'dummy3',
|
||||
usernameLower: 'dummy3',
|
||||
name: 'DummyUser3',
|
||||
followersCount: 60,
|
||||
followingCount: 70,
|
||||
notesCount: 15900,
|
||||
});
|
||||
return { dummyUser1, dummyUser2, dummyUser3 };
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class WebhookTestService {
|
||||
|
|
@ -169,6 +173,7 @@ export class WebhookTestService {
|
|||
private systemWebhookService: SystemWebhookService,
|
||||
private queueService: QueueService,
|
||||
private readonly idService: IdService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -207,6 +212,8 @@ export class WebhookTestService {
|
|||
this.queueService.userWebhookDeliver(merged, type, contents, { attempts: 1 });
|
||||
};
|
||||
|
||||
const { dummyUser1, dummyUser2, dummyUser3 } = makeDummyUsers(this.timeService.now);
|
||||
|
||||
const dummyNote1 = generateDummyNote({
|
||||
userId: dummyUser1.id,
|
||||
user: dummyUser1,
|
||||
|
|
@ -311,6 +318,8 @@ export class WebhookTestService {
|
|||
this.queueService.systemWebhookDeliver(merged, type, contents, { attempts: 1 });
|
||||
};
|
||||
|
||||
const { dummyUser1, dummyUser2, dummyUser3 } = makeDummyUsers(this.timeService.now);
|
||||
|
||||
switch (params.type) {
|
||||
case 'abuseReport': {
|
||||
send('abuseReport', await this.generateAbuseReport({
|
||||
|
|
@ -396,13 +405,13 @@ export class WebhookTestService {
|
|||
return {
|
||||
id: note.id,
|
||||
threadId: note.threadId ?? note.id,
|
||||
createdAt: new Date().toISOString(),
|
||||
createdAt: this.timeService.date.toISOString(),
|
||||
deletedAt: null,
|
||||
text: note.text,
|
||||
cw: note.cw,
|
||||
userId: note.userId,
|
||||
userHost: note.userHost ?? null,
|
||||
user: await this.toPackedUserLite(note.user ?? generateDummyUser()),
|
||||
user: await this.toPackedUserLite(note.user ?? generateDummyUser(this.timeService.now)),
|
||||
replyId: note.replyId,
|
||||
renoteId: note.renoteId,
|
||||
isHidden: false,
|
||||
|
|
@ -486,7 +495,7 @@ export class WebhookTestService {
|
|||
uri: null,
|
||||
movedTo: null,
|
||||
alsoKnownAs: [],
|
||||
createdAt: new Date().toISOString(),
|
||||
createdAt: this.timeService.date.toISOString(),
|
||||
updatedAt: user.updatedAt?.toISOString() ?? null,
|
||||
lastFetchedAt: user.lastFetchedAt?.toISOString() ?? null,
|
||||
bannerUrl: user.bannerId == null ? null : user.bannerUrl,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { UserKeypairService } from '@/core/UserKeypairService.js';
|
|||
import { ApUtilityService } from '@/core/activitypub/ApUtilityService.js';
|
||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||
import { LoggerService } from '@/core/LoggerService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import type Logger from '@/logger.js';
|
||||
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
|
||||
|
|
@ -40,7 +41,7 @@ type PrivateKey = {
|
|||
};
|
||||
|
||||
export class ApRequestCreator {
|
||||
static createSignedPost(args: { key: PrivateKey, url: string, body: string, digest?: string, additionalHeaders: Record<string, string> }): Signed {
|
||||
static createSignedPost(args: { key: PrivateKey, url: string, body: string, digest?: string, additionalHeaders: Record<string, string>, now: Date | string | number }): Signed {
|
||||
const u = new URL(args.url);
|
||||
const digestHeader = args.digest ?? this.createDigest(args.body);
|
||||
|
||||
|
|
@ -48,7 +49,7 @@ export class ApRequestCreator {
|
|||
url: u.href,
|
||||
method: 'POST',
|
||||
headers: this.#objectAssignWithLcKey({
|
||||
'Date': new Date().toUTCString(),
|
||||
'Date': new Date(args.now).toUTCString(),
|
||||
'Host': u.host,
|
||||
'Content-Type': 'application/activity+json',
|
||||
'Digest': digestHeader,
|
||||
|
|
@ -69,7 +70,7 @@ export class ApRequestCreator {
|
|||
return `SHA-256=${crypto.createHash('sha256').update(body).digest('base64')}`;
|
||||
}
|
||||
|
||||
static createSignedGet(args: { key: PrivateKey, url: string, additionalHeaders: Record<string, string> }): Signed {
|
||||
static createSignedGet(args: { key: PrivateKey, url: string, additionalHeaders: Record<string, string>, now: Date | string | number }): Signed {
|
||||
const u = new URL(args.url);
|
||||
|
||||
const request: Request = {
|
||||
|
|
@ -77,7 +78,7 @@ export class ApRequestCreator {
|
|||
method: 'GET',
|
||||
headers: this.#objectAssignWithLcKey({
|
||||
'Accept': 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||
'Date': new Date().toUTCString(),
|
||||
'Date': new Date(args.now).toUTCString(),
|
||||
'Host': new URL(args.url).host,
|
||||
}, args.additionalHeaders),
|
||||
};
|
||||
|
|
@ -150,6 +151,7 @@ export class ApRequestService {
|
|||
private httpRequestService: HttpRequestService,
|
||||
private loggerService: LoggerService,
|
||||
private readonly apUtilityService: ApUtilityService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
this.logger = this.loggerService?.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる
|
||||
|
|
@ -171,6 +173,7 @@ export class ApRequestService {
|
|||
digest,
|
||||
additionalHeaders: {
|
||||
},
|
||||
now: this.timeService.now,
|
||||
});
|
||||
|
||||
await this.httpRequestService.send(url, {
|
||||
|
|
@ -200,6 +203,7 @@ export class ApRequestService {
|
|||
url,
|
||||
additionalHeaders: {
|
||||
},
|
||||
now: this.timeService.now,
|
||||
});
|
||||
|
||||
const res = await this.httpRequestService.send(url, {
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ import { secureRndstr } from './secure-rndstr.js';
|
|||
|
||||
const CHARS = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'; // [0-9A-Z] w/o [01IO] (32 patterns)
|
||||
|
||||
export function generateInviteCode(): string {
|
||||
export function generateInviteCode(now: number): string {
|
||||
const code = secureRndstr(8, {
|
||||
chars: CHARS,
|
||||
});
|
||||
|
||||
const uniqueId = [];
|
||||
let n = Math.floor(Date.now() / 1000 / 60);
|
||||
let n = Math.floor(now / 1000 / 60);
|
||||
while (true) {
|
||||
uniqueId.push(CHARS[n % CHARS.length]);
|
||||
const t = Math.floor(n / CHARS.length);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ export async function resetDb(db: DataSource) {
|
|||
if (i === 3) {
|
||||
throw e;
|
||||
} else {
|
||||
// Ignore rule - this is just testing code.
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { DI } from '@/di-symbols.js';
|
|||
import type Logger from '@/logger.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { CheckModeratorsActivityProcessorService } from '@/queue/processors/CheckModeratorsActivityProcessorService.js';
|
||||
import { TimeService } from '@/core/TimeService.js';
|
||||
import { renderFullError } from '@/misc/render-full-error.js';
|
||||
import { renderInlineError } from '@/misc/render-inline-error.js';
|
||||
import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
|
||||
|
|
@ -61,10 +62,10 @@ function httpRelatedBackoff(attemptsMade: number) {
|
|||
return backoff;
|
||||
}
|
||||
|
||||
function getJobInfo(job: Bull.Job | undefined, increment = false): string {
|
||||
function _getJobInfo(now: number, job: Bull.Job | undefined, increment = false): string {
|
||||
if (job == null) return '-';
|
||||
|
||||
const age = Date.now() - job.timestamp;
|
||||
const age = now - job.timestamp;
|
||||
|
||||
const formated = age > 60000 ? `${Math.floor(age / 1000 / 60)}m`
|
||||
: age > 10000 ? `${Math.floor(age / 1000)}s`
|
||||
|
|
@ -134,9 +135,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
private checkModeratorsActivityProcessorService: CheckModeratorsActivityProcessorService,
|
||||
private cleanProcessorService: CleanProcessorService,
|
||||
private scheduleNotePostProcessorService: ScheduleNotePostProcessorService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
this.logger = this.queueLoggerService.logger;
|
||||
|
||||
// This is just to avoid modifying all the existing code.
|
||||
const getJobInfo = (job: Bull.Job | undefined, increment = false) => {
|
||||
return _getJobInfo(this.timeService.now, job, increment);
|
||||
};
|
||||
|
||||
//#region system
|
||||
{
|
||||
const processer = (job: Bull.Job) => {
|
||||
|
|
@ -559,7 +566,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||
// Render job
|
||||
if (job) {
|
||||
parts.push('job [');
|
||||
parts.push(getJobInfo(job));
|
||||
parts.push(_getJobInfo(this.timeService.now, job));
|
||||
parts.push('] failed: ');
|
||||
} else {
|
||||
parts.push('job failed: ');
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ export class ExportCustomEmojisProcessorService {
|
|||
});
|
||||
};
|
||||
|
||||
await writeMeta(`{"metaVersion":2,"host":"${this.config.host}","exportedAt":"${new Date().toString()}","emojis":[`);
|
||||
await writeMeta(`{"metaVersion":2,"host":"${this.config.host}","exportedAt":"${this.timeService.date.toString()}","emojis":[`);
|
||||
|
||||
const customEmojis = await this.emojisRepository.find({
|
||||
where: {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { IdService } from '@/core/IdService.js';
|
|||
import { DI } from '@/di-symbols.js';
|
||||
import { generateInviteCode } from '@/misc/generate-invite-code.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
import type { TimeService } from '@/core/TimeService.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
|
|
@ -57,6 +58,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
private inviteCodeEntityService: InviteCodeEntityService,
|
||||
private idService: IdService,
|
||||
private moderationLogService: ModerationLogService,
|
||||
private readonly timeService: TimeService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
if (ps.expiresAt && isNaN(Date.parse(ps.expiresAt))) {
|
||||
|
|
@ -71,7 +73,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
createdBy: me,
|
||||
createdById: me.id,
|
||||
expiresAt: ps.expiresAt ? new Date(ps.expiresAt) : null,
|
||||
code: generateInviteCode(),
|
||||
code: generateInviteCode(this.timeService.now),
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
createdBy: me,
|
||||
createdById: me.id,
|
||||
expiresAt: policies.inviteExpirationTime ? new Date(this.timeService.now + (policies.inviteExpirationTime * 1000 * 60)) : null,
|
||||
code: generateInviteCode(),
|
||||
code: generateInviteCode(this.timeService.now),
|
||||
});
|
||||
|
||||
return await this.inviteCodeEntityService.pack(ticket, me);
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
logger.info('---- Database reset complete.');
|
||||
|
||||
// Ignore rule - this is just testing code.
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ describe('ap-request', () => {
|
|||
'User-Agent': 'UA',
|
||||
};
|
||||
|
||||
const req = ApRequestCreator.createSignedPost({ key, url, body, additionalHeaders: headers });
|
||||
const req = ApRequestCreator.createSignedPost({ key, url, body, additionalHeaders: headers, now: Date.now() });
|
||||
|
||||
const parsed = buildParsedSignature(req.signingString, req.signature, 'rsa-sha256');
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ describe('ap-request', () => {
|
|||
'User-Agent': 'UA',
|
||||
};
|
||||
|
||||
const req = ApRequestCreator.createSignedGet({ key, url, additionalHeaders: headers });
|
||||
const req = ApRequestCreator.createSignedGet({ key, url, additionalHeaders: headers, now: Date.now() });
|
||||
|
||||
const parsed = buildParsedSignature(req.signingString, req.signature, 'rsa-sha256');
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue