server: use time constants

This commit is contained in:
Johann150 2022-11-20 23:15:22 +01:00
parent 66a7c62342
commit 9e2553909e
Signed by untrusted user: Johann150
GPG key ID: 9EE6577A2A06F8F1
24 changed files with 78 additions and 58 deletions

View file

@ -1,9 +1,10 @@
import Xev from 'xev'; import Xev from 'xev';
import { deliverQueue, inboxQueue } from '@/queue/queues.js'; import { deliverQueue, inboxQueue } from '@/queue/queues.js';
import { SECOND } from '@/const.js';
const ev = new Xev(); const ev = new Xev();
const interval = 10000; const interval = 10 * SECOND;
/** /**
* Report queue stats regularly * Report queue stats regularly

View file

@ -1,5 +1,7 @@
// https://github.com/typeorm/typeorm/issues/2400 // https://github.com/typeorm/typeorm/issues/2400
import pg from 'pg'; import pg from 'pg';
import { SECOND } from '@/const.js';
pg.types.setTypeParser(20, Number); pg.types.setTypeParser(20, Number);
import { Logger, DataSource } from 'typeorm'; import { Logger, DataSource } from 'typeorm';
@ -182,7 +184,7 @@ export const db = new DataSource({
password: config.db.pass, password: config.db.pass,
database: config.db.db, database: config.db.db,
extra: { extra: {
statement_timeout: 1000 * 10, statement_timeout: 10 * SECOND,
...config.db.extra, ...config.db.extra,
}, },
synchronize: process.env.NODE_ENV === 'test', synchronize: process.env.NODE_ENV === 'test',
@ -234,7 +236,7 @@ export async function resetDb() {
if (i === 3) { if (i === 3) {
throw e; throw e;
} else { } else {
await new Promise(resolve => setTimeout(resolve, 1000)); await new Promise(resolve => setTimeout(resolve, SECOND));
continue; continue;
} }
} }

View file

@ -1,6 +1,7 @@
import { promisify } from 'node:util'; import { promisify } from 'node:util';
import redisLock from 'redis-lock'; import redisLock from 'redis-lock';
import { redisClient } from '@/db/redis.js'; import { redisClient } from '@/db/redis.js';
import { SECOND } from '@/const.js';
/** /**
* Retry delay (ms) for lock acquisition * Retry delay (ms) for lock acquisition
@ -18,14 +19,14 @@ const lock: (key: string, timeout?: number) => Promise<() => void>
* @param timeout Lock timeout (ms), The timeout releases previous lock. * @param timeout Lock timeout (ms), The timeout releases previous lock.
* @returns Unlock function * @returns Unlock function
*/ */
export function getApLock(uri: string, timeout = 30 * 1000) { export function getApLock(uri: string, timeout = 30 * SECOND) {
return lock(`ap-object:${uri}`, timeout); return lock(`ap-object:${uri}`, timeout);
} }
export function getFetchInstanceMetadataLock(host: string, timeout = 30 * 1000) { export function getFetchInstanceMetadataLock(host: string, timeout = 30 * SECOND) {
return lock(`instance:${host}`, timeout); return lock(`instance:${host}`, timeout);
} }
export function getChartInsertLock(lockKey: string, timeout = 30 * 1000) { export function getChartInsertLock(lockKey: string, timeout = 30 * SECOND) {
return lock(`chart-insert:${lockKey}`, timeout); return lock(`chart-insert:${lockKey}`, timeout);
} }

View file

@ -5,6 +5,7 @@ import chalk from 'chalk';
import got, * as Got from 'got'; import got, * as Got from 'got';
import IPCIDR from 'ip-cidr'; import IPCIDR from 'ip-cidr';
import PrivateIp from 'private-ip'; import PrivateIp from 'private-ip';
import { SECOND, MINUTE } from '@/const.js';
import config from '@/config/index.js'; import config from '@/config/index.js';
import Logger from '@/services/logger.js'; import Logger from '@/services/logger.js';
import { httpAgent, httpsAgent, StatusError } from './fetch.js'; import { httpAgent, httpsAgent, StatusError } from './fetch.js';
@ -16,8 +17,8 @@ export async function downloadUrl(url: string, path: string): Promise<void> {
logger.info(`Downloading ${chalk.cyan(url)} ...`); logger.info(`Downloading ${chalk.cyan(url)} ...`);
const timeout = 30 * 1000; const timeout = 30 * SECOND;
const operationTimeout = 60 * 1000; const operationTimeout = MINUTE;
const maxSize = config.maxFileSize || 262144000; const maxSize = config.maxFileSize || 262144000;
const req = got.stream(url, { const req = got.stream(url, {

View file

@ -4,9 +4,10 @@ import { URL } from 'node:url';
import CacheableLookup from 'cacheable-lookup'; import CacheableLookup from 'cacheable-lookup';
import fetch from 'node-fetch'; import fetch from 'node-fetch';
import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent'; import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent';
import { SECOND } from '@/const.js';
import config from '@/config/index.js'; import config from '@/config/index.js';
export async function getJson(url: string, accept = 'application/json, */*', timeout = 10000, headers?: Record<string, string>) { export async function getJson(url: string, accept = 'application/json, */*', timeout = 10 * SECOND, headers?: Record<string, string>) {
const res = await getResponse({ const res = await getResponse({
url, url,
method: 'GET', method: 'GET',
@ -20,7 +21,7 @@ export async function getJson(url: string, accept = 'application/json, */*', tim
return await res.json(); return await res.json();
} }
export async function getHtml(url: string, accept = 'text/html, */*', timeout = 10000, headers?: Record<string, string>) { export async function getHtml(url: string, accept = 'text/html, */*', timeout = 10 * SECOND, headers?: Record<string, string>) {
const res = await getResponse({ const res = await getResponse({
url, url,
method: 'GET', method: 'GET',
@ -35,7 +36,7 @@ export async function getHtml(url: string, accept = 'text/html, */*', timeout =
} }
export async function getResponse(args: { url: string, method: string, body?: string, headers: Record<string, string>, timeout?: number, size?: number }) { export async function getResponse(args: { url: string, method: string, body?: string, headers: Record<string, string>, timeout?: number, size?: number }) {
const timeout = args.timeout || 10 * 1000; const timeout = args.timeout || 10 * SECOND;
const controller = new AbortController(); const controller = new AbortController();
setTimeout(() => { setTimeout(() => {
@ -70,7 +71,7 @@ const cache = new CacheableLookup({
*/ */
const _http = new http.Agent({ const _http = new http.Agent({
keepAlive: true, keepAlive: true,
keepAliveMsecs: 30 * 1000, keepAliveMsecs: 30 * SECOND,
lookup: cache.lookup, lookup: cache.lookup,
} as http.AgentOptions); } as http.AgentOptions);
@ -79,7 +80,7 @@ const _http = new http.Agent({
*/ */
const _https = new https.Agent({ const _https = new https.Agent({
keepAlive: true, keepAlive: true,
keepAliveMsecs: 30 * 1000, keepAliveMsecs: 30 * SECOND,
lookup: cache.lookup, lookup: cache.lookup,
} as https.AgentOptions); } as https.AgentOptions);
@ -91,7 +92,7 @@ const maxSockets = Math.max(256, config.deliverJobConcurrency || 128);
export const httpAgent = config.proxy export const httpAgent = config.proxy
? new HttpProxyAgent({ ? new HttpProxyAgent({
keepAlive: true, keepAlive: true,
keepAliveMsecs: 30 * 1000, keepAliveMsecs: 30 * SECOND,
maxSockets, maxSockets,
maxFreeSockets: 256, maxFreeSockets: 256,
scheduling: 'lifo', scheduling: 'lifo',
@ -105,7 +106,7 @@ export const httpAgent = config.proxy
export const httpsAgent = config.proxy export const httpsAgent = config.proxy
? new HttpsProxyAgent({ ? new HttpsProxyAgent({
keepAlive: true, keepAlive: true,
keepAliveMsecs: 30 * 1000, keepAliveMsecs: 30 * SECOND,
maxSockets, maxSockets,
maxFreeSockets: 256, maxFreeSockets: 256,
scheduling: 'lifo', scheduling: 'lifo',

View file

@ -6,6 +6,7 @@ import { DriveFile } from '@/models/entities/drive-file.js';
import { Webhook, webhookEventTypes } from '@/models/entities/webhook.js'; import { Webhook, webhookEventTypes } from '@/models/entities/webhook.js';
import { IActivity } from '@/remote/activitypub/type.js'; import { IActivity } from '@/remote/activitypub/type.js';
import { envOption } from '@/env.js'; import { envOption } from '@/env.js';
import { MINUTE } from '@/const.js';
import processDeliver from './processors/deliver.js'; import processDeliver from './processors/deliver.js';
import processInbox from './processors/inbox.js'; import processInbox from './processors/inbox.js';
@ -96,7 +97,7 @@ export function deliver(user: ThinUser, content: unknown, to: string | null) {
return deliverQueue.add(data, { return deliverQueue.add(data, {
attempts: config.deliverJobMaxAttempts || 12, attempts: config.deliverJobMaxAttempts || 12,
timeout: 1 * 60 * 1000, // 1min timeout: MINUTE,
backoff: { backoff: {
type: 'apBackoff', type: 'apBackoff',
}, },
@ -113,7 +114,7 @@ export function inbox(activity: IActivity, signature: httpSignature.IParsedSigna
return inboxQueue.add(data, { return inboxQueue.add(data, {
attempts: config.inboxJobMaxAttempts || 8, attempts: config.inboxJobMaxAttempts || 8,
timeout: 5 * 60 * 1000, // 5min timeout: 5 * MINUTE,
backoff: { backoff: {
type: 'apBackoff', type: 'apBackoff',
}, },
@ -278,7 +279,7 @@ export function webhookDeliver(webhook: Webhook, type: typeof webhookEventTypes[
return webhookDeliverQueue.add(data, { return webhookDeliverQueue.add(data, {
attempts: 4, attempts: 4,
timeout: 1 * 60 * 1000, // 1min timeout: MINUTE,
backoff: { backoff: {
type: 'apBackoff', type: 'apBackoff',
}, },

View file

@ -1,4 +1,5 @@
import Bull from 'bull'; import Bull from 'bull';
import { SECOND, MINUTE, HOUR } from '@/const.js';
import config from '@/config/index.js'; import config from '@/config/index.js';
import { getRedisOptions } from '@/config/redis.js'; import { getRedisOptions } from '@/config/redis.js';
@ -8,7 +9,7 @@ export function initialize<T>(name: string, limitPerSec = -1): Bull.Queue<T> {
prefix: config.redis.prefix ? `${config.redis.prefix}:queue` : 'queue', prefix: config.redis.prefix ? `${config.redis.prefix}:queue` : 'queue',
limiter: limitPerSec > 0 ? { limiter: limitPerSec > 0 ? {
max: limitPerSec, max: limitPerSec,
duration: 1000, duration: SECOND,
} : undefined, } : undefined,
settings: { settings: {
backoffStrategies: { backoffStrategies: {
@ -20,8 +21,8 @@ export function initialize<T>(name: string, limitPerSec = -1): Bull.Queue<T> {
// ref. https://github.com/misskey-dev/misskey/pull/7635#issue-971097019 // ref. https://github.com/misskey-dev/misskey/pull/7635#issue-971097019
function apBackoff(attemptsMade: number, err: Error) { function apBackoff(attemptsMade: number, err: Error) {
const baseDelay = 60 * 1000; // 1min const baseDelay = MINUTE;
const maxBackoff = 8 * 60 * 60 * 1000; // 8hours const maxBackoff = 8 * HOUR;
let backoff = (Math.pow(2, attemptsMade) - 1) * baseDelay; let backoff = (Math.pow(2, attemptsMade) - 1) * baseDelay;
backoff = Math.min(backoff, maxBackoff); backoff = Math.min(backoff, maxBackoff);
backoff += Math.round(backoff * Math.random() * 0.2); backoff += Math.round(backoff * Math.random() * 0.2);

View file

@ -3,6 +3,7 @@ import Bull from 'bull';
import { format as dateFormat } from 'date-fns'; import { format as dateFormat } from 'date-fns';
import { In, MoreThan, Not } from 'typeorm'; import { In, MoreThan, Not } from 'typeorm';
import { MONTH } from '@/const.js';
import { getFullApAccount } from '@/misc/convert-host.js'; import { getFullApAccount } from '@/misc/convert-host.js';
import { createTemp } from '@/misc/create-temp.js'; import { createTemp } from '@/misc/create-temp.js';
import { Following } from '@/models/entities/following.js'; import { Following } from '@/models/entities/following.js';
@ -61,7 +62,7 @@ export async function exportFollowing(job: Bull.Job<DbUserJobData>, done: () =>
continue; continue;
} }
if (job.data.excludeInactive && u.updatedAt && (Date.now() - u.updatedAt.getTime() > 1000 * 60 * 60 * 24 * 90)) { if (job.data.excludeInactive && u.updatedAt && (Date.now() - u.updatedAt.getTime() > 3 * MONTH)) {
continue; continue;
} }

View file

@ -1,3 +1,4 @@
import { DAY } from '@/const.js';
import { CacheableRemoteUser } from '@/models/entities/user.js'; import { CacheableRemoteUser } from '@/models/entities/user.js';
import { IObject } from './type.js'; import { IObject } from './type.js';
import { performActivity } from './kernel/index.js'; import { performActivity } from './kernel/index.js';
@ -6,9 +7,9 @@ import { updatePerson } from './models/person.js';
export default async (actor: CacheableRemoteUser, activity: IObject): Promise<void> => { export default async (actor: CacheableRemoteUser, activity: IObject): Promise<void> => {
await performActivity(actor, activity); await performActivity(actor, activity);
// ついでにリモートユーザーの情報が古かったら更新しておく // And while I'm at it, I'll update the remote user information if it's out of date.
if (actor.uri) { if (actor.uri) {
if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) { if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > DAY) {
setImmediate(() => { setImmediate(() => {
updatePerson(actor.uri!); updatePerson(actor.uri!);
}); });

View file

@ -1,6 +1,7 @@
import { URL } from 'node:url'; import { URL } from 'node:url';
import chalk from 'chalk'; import chalk from 'chalk';
import { IsNull } from 'typeorm'; import { IsNull } from 'typeorm';
import { DAY } from '@/const.js';
import config from '@/config/index.js'; import config from '@/config/index.js';
import { isSelfHost, toPuny } from '@/misc/convert-host.js'; import { isSelfHost, toPuny } from '@/misc/convert-host.js';
import { User, IRemoteUser } from '@/models/entities/user.js'; import { User, IRemoteUser } from '@/models/entities/user.js';
@ -49,9 +50,9 @@ export async function resolveUser(username: string, idnHost: string | null): Pro
return await createPerson(self.href); return await createPerson(self.href);
} }
// ユーザー情報が古い場合は、WebFilgerからやりなおして返す // If user information is out of date, start over with webfinger
if (user.lastFetchedAt == null || Date.now() - user.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) { if (user.lastFetchedAt == null || Date.now() - user.lastFetchedAt.getTime() > DAY) {
// 繋がらないインスタンスに何回も試行するのを防ぐ, 後続の同様処理の連続試行を防ぐ ため 試行前にも更新する // Prevent race conditions
await Users.update(user.id, { await Users.update(user.id, {
lastFetchedAt: new Date(), lastFetchedAt: new Date(),
}); });

View file

@ -1,4 +1,5 @@
import rndstr from 'rndstr'; import rndstr from 'rndstr';
import { DAY } from '@/const.js';
import { Note } from '@/models/entities/note.js'; import { Note } from '@/models/entities/note.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
import { Notes, UserProfiles, NoteReactions } from '@/models/index.js'; import { Notes, UserProfiles, NoteReactions } from '@/models/index.js';
@ -16,13 +17,13 @@ export async function injectFeatured(timeline: Note[], user?: User | null) {
} }
const max = 30; const max = 30;
const day = 1000 * 60 * 60 * 24 * 3; // 3日前まで const offset = 3 * DAY;
const query = Notes.createQueryBuilder('note') const query = Notes.createQueryBuilder('note')
.addSelect('note.score') .addSelect('note.score')
.where('note.userHost IS NULL') .where('note.userHost IS NULL')
.andWhere('note.score > 0') .andWhere('note.score > 0')
.andWhere('note.createdAt > :date', { date: new Date(Date.now() - day) }) .andWhere('note.createdAt > :date', { date: new Date(Date.now() - offset) })
.andWhere("note.visibility = 'public'") .andWhere("note.visibility = 'public'")
.innerJoinAndSelect('note.user', 'user'); .innerJoinAndSelect('note.user', 'user');

View file

@ -1,3 +1,4 @@
import { DAY } from '@/const.js';
import { Users } from '@/models/index.js'; import { Users } from '@/models/index.js';
import define from '../../define.js'; import define from '../../define.js';
@ -46,7 +47,7 @@ export default define(meta, paramDef, async (ps, me) => {
case 'admin': query.where('user.isAdmin = TRUE'); break; case 'admin': query.where('user.isAdmin = TRUE'); break;
case 'moderator': query.where('user.isModerator = TRUE'); break; case 'moderator': query.where('user.isModerator = TRUE'); break;
case 'adminOrModerator': query.where('user.isAdmin = TRUE OR user.isModerator = TRUE'); break; case 'adminOrModerator': query.where('user.isAdmin = TRUE OR user.isModerator = TRUE'); break;
case 'alive': query.where('user.updatedAt > :date', { date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 5) }); break; case 'alive': query.where('user.updatedAt > :date', { date: new Date(Date.now() - 5 * DAY) }); break;
case 'silenced': query.where('user.isSilenced = TRUE'); break; case 'silenced': query.where('user.isSilenced = TRUE'); break;
case 'suspended': query.where('user.isSuspended = TRUE'); break; case 'suspended': query.where('user.isSuspended = TRUE'); break;
} }

View file

@ -1,3 +1,4 @@
import { DAY } from '@/const.js';
import { GalleryPosts } from '@/models/index.js'; import { GalleryPosts } from '@/models/index.js';
import define from '../../define.js'; import define from '../../define.js';
@ -26,7 +27,7 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, me) => { export default define(meta, paramDef, async (ps, me) => {
const query = GalleryPosts.createQueryBuilder('post') const query = GalleryPosts.createQueryBuilder('post')
.andWhere('post.createdAt > :date', { date: new Date(Date.now() - (1000 * 60 * 60 * 24 * 3)) }) .andWhere('post.createdAt > :date', { date: new Date(Date.now() - 3 * DAY) })
.andWhere('post.likedCount > 0') .andWhere('post.likedCount > 0')
.orderBy('post.likedCount', 'DESC'); .orderBy('post.likedCount', 'DESC');

View file

@ -1,4 +1,5 @@
import { Brackets } from 'typeorm'; import { Brackets } from 'typeorm';
import { MINUTE, HOUR } from '@/const.js';
import { fetchMeta } from '@/misc/fetch-meta.js'; import { fetchMeta } from '@/misc/fetch-meta.js';
import { Notes } from '@/models/index.js'; import { Notes } from '@/models/index.js';
import { Note } from '@/models/entities/note.js'; import { Note } from '@/models/entities/note.js';
@ -13,8 +14,8 @@ import define from '../../define.js';
..PostgreSQLでどうするのか分からないので単にAの内に投稿されたユニーク投稿数が多いハッシュタグ ..PostgreSQLでどうするのか分からないので単にAの内に投稿されたユニーク投稿数が多いハッシュタグ
*/ */
const rangeA = 1000 * 60 * 60; // 60分 const rangeA = HOUR;
//const rangeB = 1000 * 60 * 120; // 2時間 //const rangeB = 2 * HOUR;
//const coefficient = 1.25; // 「n倍」の部分 //const coefficient = 1.25; // 「n倍」の部分
//const requiredUsers = 3; // 最低何人がそのタグを投稿している必要があるか //const requiredUsers = 3; // 最低何人がそのタグを投稿している必要があるか
@ -116,8 +117,7 @@ export default define(meta, paramDef, async () => {
const range = 20; const range = 20;
// 10分 const interval = 10 * MINUTE;
const interval = 1000 * 60 * 10;
for (let i = 0; i < range; i++) { for (let i = 0; i < range; i++) {
countPromises.push(Promise.all(hots.map(tag => Notes.createQueryBuilder('note') countPromises.push(Promise.all(hots.map(tag => Notes.createQueryBuilder('note')

View file

@ -1,3 +1,4 @@
import { DAY } from '@/const.js';
import { Users } from '@/models/index.js'; import { Users } from '@/models/index.js';
import { normalizeForSearch } from '@/misc/normalize-for-search.js'; import { normalizeForSearch } from '@/misc/normalize-for-search.js';
import define from '../../define.js'; import define from '../../define.js';
@ -35,7 +36,7 @@ export default define(meta, paramDef, async (ps, me) => {
const query = Users.createQueryBuilder('user') const query = Users.createQueryBuilder('user')
.where(':tag = ANY(user.tags)', { tag: normalizeForSearch(ps.tag) }); .where(':tag = ANY(user.tags)', { tag: normalizeForSearch(ps.tag) });
const recent = new Date(Date.now() - (1000 * 60 * 60 * 24 * 5)); const recent = new Date(Date.now() - 5 * DAY);
if (ps.state === 'alive') { if (ps.state === 'alive') {
query.andWhere('user.updatedAt > :date', { date: recent }); query.andWhere('user.updatedAt > :date', { date: recent });

View file

@ -1,6 +1,7 @@
import { promisify } from 'node:util'; import { promisify } from 'node:util';
import bcrypt from 'bcryptjs'; import bcrypt from 'bcryptjs';
import * as cbor from 'cbor'; import * as cbor from 'cbor';
import { MINUTE } from '@/const.js';
import { import {
UserProfiles, UserProfiles,
UserSecurityKeys, UserSecurityKeys,
@ -112,10 +113,10 @@ export default define(meta, paramDef, async (ps, user) => {
id: ps.challengeId, id: ps.challengeId,
}); });
// Expired challenge (> 5min old) // Expired challenge
if ( if (
new Date().getTime() - attestationChallenge.createdAt.getTime() >= new Date().getTime() - attestationChallenge.createdAt.getTime() >=
5 * 60 * 1000 5 * MINUTE
) { ) {
throw new Error('expired challenge'); throw new Error('expired challenge');
} }

View file

@ -1,3 +1,4 @@
import { DAY } from '@/const.js';
import { Notes } from '@/models/index.js'; import { Notes } from '@/models/index.js';
import define from '../../define.js'; import define from '../../define.js';
import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js';
@ -31,7 +32,7 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, user) => { export default define(meta, paramDef, async (ps, user) => {
const max = 30; const max = 30;
const day = 1000 * 60 * 60 * 24 * 3; // 3日前まで const day = 3 * DAY;
const query = Notes.createQueryBuilder('note') const query = Notes.createQueryBuilder('note')
.addSelect('note.score') .addSelect('note.score')

View file

@ -1,3 +1,4 @@
import { DAY } from '@/const.js';
import { Users } from '@/models/index.js'; import { Users } from '@/models/index.js';
import define from '../define.js'; import define from '../define.js';
import { generateMutedUserQueryForUsers } from '../common/generate-muted-user-query.js'; import { generateMutedUserQueryForUsers } from '../common/generate-muted-user-query.js';
@ -46,7 +47,7 @@ export default define(meta, paramDef, async (ps, me) => {
case 'admin': query.andWhere('user.isAdmin = TRUE'); break; case 'admin': query.andWhere('user.isAdmin = TRUE'); break;
case 'moderator': query.andWhere('user.isModerator = TRUE'); break; case 'moderator': query.andWhere('user.isModerator = TRUE'); break;
case 'adminOrModerator': query.andWhere('user.isAdmin = TRUE OR user.isModerator = TRUE'); break; case 'adminOrModerator': query.andWhere('user.isAdmin = TRUE OR user.isModerator = TRUE'); break;
case 'alive': query.andWhere('user.updatedAt > :date', { date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 5) }); break; case 'alive': query.andWhere('user.updatedAt > :date', { date: new Date(Date.now() - 5 * DAY) }); break;
} }
switch (ps.origin) { switch (ps.origin) {

View file

@ -1,3 +1,4 @@
import { MONTH } from '@/const.js';
import { Brackets } from 'typeorm'; import { Brackets } from 'typeorm';
import { Followings, Users } from '@/models/index.js'; import { Followings, Users } from '@/models/index.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
@ -39,7 +40,7 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, me) => { export default define(meta, paramDef, async (ps, me) => {
const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日 const activeThreshold = new Date(Date.now() - MONTH);
if (ps.host) { if (ps.host) {
const q = Users.createQueryBuilder('user') const q = Users.createQueryBuilder('user')

View file

@ -1,4 +1,5 @@
import { Brackets } from 'typeorm'; import { Brackets } from 'typeorm';
import { MONTH } from '@/const.js';
import { UserProfiles, Users } from '@/models/index.js'; import { UserProfiles, Users } from '@/models/index.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
import define from '../../define.js'; import define from '../../define.js';
@ -35,7 +36,7 @@ export const paramDef = {
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default define(meta, paramDef, async (ps, me) => { export default define(meta, paramDef, async (ps, me) => {
const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日 const activeThreshold = new Date(Date.now() - MONTH);
const isUsername = ps.query.startsWith('@'); const isUsername = ps.query.startsWith('@');

View file

@ -3,6 +3,7 @@ import { IsNull } from 'typeorm';
import Koa from 'koa'; import Koa from 'koa';
import bcrypt from 'bcryptjs'; import bcrypt from 'bcryptjs';
import * as speakeasy from 'speakeasy'; import * as speakeasy from 'speakeasy';
import { SECOND, MINUTE, HOUR } from '@/const.js';
import config from '@/config/index.js'; import config from '@/config/index.js';
import { Users, Signins, UserProfiles, UserSecurityKeys, AttestationChallenges } from '@/models/index.js'; import { Users, Signins, UserProfiles, UserSecurityKeys, AttestationChallenges } from '@/models/index.js';
import { ILocalUser } from '@/models/entities/user.js'; import { ILocalUser } from '@/models/entities/user.js';
@ -38,7 +39,7 @@ export default async (ctx: Koa.Context) => {
try { try {
// not more than 1 attempt per second and not more than 10 attempts per hour // not more than 1 attempt per second and not more than 10 attempts per hour
await limiter({ key: 'signin', duration: 60 * 60 * 1000, max: 10, minInterval: 1000 }, getIpHash(ctx.ip)); await limiter({ key: 'signin', duration: HOUR, max: 10, minInterval: SECOND }, getIpHash(ctx.ip));
} catch (err) { } catch (err) {
error(new ApiError('RATE_LIMIT_EXCEEDED')); error(new ApiError('RATE_LIMIT_EXCEEDED'));
return; return;
@ -149,7 +150,7 @@ export default async (ctx: Koa.Context) => {
id: body.challengeId, id: body.challengeId,
}); });
if (new Date().getTime() - challenge.createdAt.getTime() >= 5 * 60 * 1000) { if (new Date().getTime() - challenge.createdAt.getTime() >= 5 * MINUTE) {
await fail(); await fail();
return; return;
} }

View file

@ -1,13 +1,10 @@
import { WEEK, MONTH, YEAR } from '@/const.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
import Chart, { KVs } from '../core.js'; import Chart, { KVs } from '../core.js';
import { name, schema } from './entities/active-users.js'; import { name, schema } from './entities/active-users.js';
const week = 1000 * 60 * 60 * 24 * 7;
const month = 1000 * 60 * 60 * 24 * 30;
const year = 1000 * 60 * 60 * 24 * 365;
/** /**
* * Chart on Active Users
*/ */
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default class ActiveUsersChart extends Chart<typeof schema> { export default class ActiveUsersChart extends Chart<typeof schema> {
@ -26,12 +23,12 @@ export default class ActiveUsersChart extends Chart<typeof schema> {
public async read(user: { id: User['id'], host: null, createdAt: User['createdAt'] }): Promise<void> { public async read(user: { id: User['id'], host: null, createdAt: User['createdAt'] }): Promise<void> {
await this.commit({ await this.commit({
'read': [user.id], 'read': [user.id],
'registeredWithinWeek': (Date.now() - user.createdAt.getTime() < week) ? [user.id] : [], 'registeredWithinWeek': (Date.now() - user.createdAt.getTime() < WEEK) ? [user.id] : [],
'registeredWithinMonth': (Date.now() - user.createdAt.getTime() < month) ? [user.id] : [], 'registeredWithinMonth': (Date.now() - user.createdAt.getTime() < MONTH) ? [user.id] : [],
'registeredWithinYear': (Date.now() - user.createdAt.getTime() < year) ? [user.id] : [], 'registeredWithinYear': (Date.now() - user.createdAt.getTime() < YEAR) ? [user.id] : [],
'registeredOutsideWeek': (Date.now() - user.createdAt.getTime() > week) ? [user.id] : [], 'registeredOutsideWeek': (Date.now() - user.createdAt.getTime() > WEEK) ? [user.id] : [],
'registeredOutsideMonth': (Date.now() - user.createdAt.getTime() > month) ? [user.id] : [], 'registeredOutsideMonth': (Date.now() - user.createdAt.getTime() > MONTH) ? [user.id] : [],
'registeredOutsideYear': (Date.now() - user.createdAt.getTime() > year) ? [user.id] : [], 'registeredOutsideYear': (Date.now() - user.createdAt.getTime() > YEAR) ? [user.id] : [],
}); });
} }

View file

@ -1,3 +1,4 @@
import { MONTH } from '@/const.js';
import { Followings, Instances } from '@/models/index.js'; import { Followings, Instances } from '@/models/index.js';
import { fetchMeta } from '@/misc/fetch-meta.js'; import { fetchMeta } from '@/misc/fetch-meta.js';
import Chart, { KVs } from '../core.js'; import Chart, { KVs } from '../core.js';
@ -65,7 +66,7 @@ export default class FederationChart extends Chart<typeof schema> {
.where(`instance.host IN (${ subInstancesQuery.getQuery() })`) .where(`instance.host IN (${ subInstancesQuery.getQuery() })`)
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT IN (:...blocked)', { blocked: meta.blockedHosts }) .andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT IN (:...blocked)', { blocked: meta.blockedHosts })
.andWhere('instance.isSuspended = false') .andWhere('instance.isSuspended = false')
.andWhere('instance.lastCommunicatedAt > :gt', { gt: new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)) }) .andWhere('instance.lastCommunicatedAt > :gt', { gt: new Date(Date.now() - MONTH) })
.getRawOne() .getRawOne()
.then(x => parseInt(x.count, 10)), .then(x => parseInt(x.count, 10)),
Instances.createQueryBuilder('instance') Instances.createQueryBuilder('instance')
@ -73,7 +74,7 @@ export default class FederationChart extends Chart<typeof schema> {
.where(`instance.host IN (${ pubInstancesQuery.getQuery() })`) .where(`instance.host IN (${ pubInstancesQuery.getQuery() })`)
.andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT IN (:...blocked)', { blocked: meta.blockedHosts }) .andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT IN (:...blocked)', { blocked: meta.blockedHosts })
.andWhere('instance.isSuspended = false') .andWhere('instance.isSuspended = false')
.andWhere('instance.lastCommunicatedAt > :gt', { gt: new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)) }) .andWhere('instance.lastCommunicatedAt > :gt', { gt: new Date(Date.now() - MONTH) })
.getRawOne() .getRawOne()
.then(x => parseInt(x.count, 10)), .then(x => parseInt(x.count, 10)),
]); ]);

View file

@ -2,6 +2,7 @@ import { URL } from 'node:url';
import { DOMWindow, JSDOM } from 'jsdom'; import { DOMWindow, JSDOM } from 'jsdom';
import fetch from 'node-fetch'; import fetch from 'node-fetch';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import { DAY } from '@/const.js';
import { getJson, getHtml, getAgentByUrl } from '@/misc/fetch.js'; import { getJson, getHtml, getAgentByUrl } from '@/misc/fetch.js';
import { Instance } from '@/models/entities/instance.js'; import { Instance } from '@/models/entities/instance.js';
import { Instances } from '@/models/index.js'; import { Instances } from '@/models/index.js';
@ -16,7 +17,7 @@ export async function fetchInstanceMetadata(instance: Instance, force = false):
if (!force) { if (!force) {
const _instance = await Instances.findOneBy({ host: instance.host }); const _instance = await Instances.findOneBy({ host: instance.host });
const now = Date.now(); const now = Date.now();
if (_instance && _instance.infoUpdatedAt && (now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 24)) { if (_instance && _instance.infoUpdatedAt && (now - _instance.infoUpdatedAt.getTime() < DAY)) {
unlock(); unlock();
return; return;
} }