Compare commits
60 Commits
develop
...
copilot/su
| Author | SHA1 | Date |
|---|---|---|
|
|
89140c552f | |
|
|
2a23054249 | |
|
|
8429e9f9ed | |
|
|
8b82f880c2 | |
|
|
fc43017439 | |
|
|
cf88d2357c | |
|
|
d8dc7e265f | |
|
|
607e4ed4de | |
|
|
707e2647c1 | |
|
|
3ce3bacccc | |
|
|
bc63e367bc | |
|
|
7ae0aa5bd8 | |
|
|
9aa3e5de4c | |
|
|
c1c21e2c16 | |
|
|
a49f2943ba | |
|
|
de55462bd8 | |
|
|
689b20b033 | |
|
|
f0d7a9da21 | |
|
|
21d04e246f | |
|
|
e2ca887d65 | |
|
|
71550eaa3a | |
|
|
c52425886e | |
|
|
e6a960e060 | |
|
|
789bdd255f | |
|
|
37207f6e1d | |
|
|
e47e6fc527 | |
|
|
b2edff4888 | |
|
|
cb6d054c71 | |
|
|
c306cdbdd9 | |
|
|
0770ee82eb | |
|
|
a629985ef6 | |
|
|
7f425ddc77 | |
|
|
335c77e9e5 | |
|
|
113728797f | |
|
|
3dbeb4659b | |
|
|
ec92919cb1 | |
|
|
40cfaf2b87 | |
|
|
c2b1718863 | |
|
|
66f7e5acd5 | |
|
|
deebcb29da | |
|
|
ac61d49873 | |
|
|
104505fe5a | |
|
|
54f1fc3d79 | |
|
|
737019c03f | |
|
|
263f0a8bba | |
|
|
c508318627 | |
|
|
5c78dd3e34 | |
|
|
50a5e7a5dc | |
|
|
7b53b88209 | |
|
|
d381eaa309 | |
|
|
179b18b347 | |
|
|
70415bdab5 | |
|
|
90e2dfef4e | |
|
|
46edd40409 | |
|
|
1b999c6536 | |
|
|
e4f85f59ff | |
|
|
6c1b17510d | |
|
|
5d043b0049 | |
|
|
aa36ebb39b | |
|
|
026e9897ca |
|
|
@ -9,6 +9,7 @@
|
||||||
### Server
|
### Server
|
||||||
- Enhance: メモリ使用量を削減しました
|
- Enhance: メモリ使用量を削減しました
|
||||||
- Enhance: ActivityPubアクティビティを送信する際のパフォーマンス向上
|
- Enhance: ActivityPubアクティビティを送信する際のパフォーマンス向上
|
||||||
|
- Enhance: 依存関係の更新
|
||||||
|
|
||||||
|
|
||||||
## 2025.11.1
|
## 2025.11.1
|
||||||
|
|
|
||||||
|
|
@ -40,17 +40,17 @@
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@swc/core-android-arm64": "1.3.11",
|
"@swc/core-android-arm64": "1.3.11",
|
||||||
"@swc/core-darwin-arm64": "1.15.2",
|
"@swc/core-darwin-arm64": "1.15.3",
|
||||||
"@swc/core-darwin-x64": "1.15.2",
|
"@swc/core-darwin-x64": "1.15.3",
|
||||||
"@swc/core-freebsd-x64": "1.3.11",
|
"@swc/core-freebsd-x64": "1.3.11",
|
||||||
"@swc/core-linux-arm-gnueabihf": "1.15.2",
|
"@swc/core-linux-arm-gnueabihf": "1.15.3",
|
||||||
"@swc/core-linux-arm64-gnu": "1.15.2",
|
"@swc/core-linux-arm64-gnu": "1.15.3",
|
||||||
"@swc/core-linux-arm64-musl": "1.15.2",
|
"@swc/core-linux-arm64-musl": "1.15.3",
|
||||||
"@swc/core-linux-x64-gnu": "1.15.2",
|
"@swc/core-linux-x64-gnu": "1.15.3",
|
||||||
"@swc/core-linux-x64-musl": "1.15.2",
|
"@swc/core-linux-x64-musl": "1.15.3",
|
||||||
"@swc/core-win32-arm64-msvc": "1.15.2",
|
"@swc/core-win32-arm64-msvc": "1.15.3",
|
||||||
"@swc/core-win32-ia32-msvc": "1.15.2",
|
"@swc/core-win32-ia32-msvc": "1.15.3",
|
||||||
"@swc/core-win32-x64-msvc": "1.15.2",
|
"@swc/core-win32-x64-msvc": "1.15.3",
|
||||||
"@tensorflow/tfjs": "4.22.0",
|
"@tensorflow/tfjs": "4.22.0",
|
||||||
"@tensorflow/tfjs-node": "4.22.0",
|
"@tensorflow/tfjs-node": "4.22.0",
|
||||||
"bufferutil": "4.0.9",
|
"bufferutil": "4.0.9",
|
||||||
|
|
@ -70,17 +70,17 @@
|
||||||
"utf-8-validate": "6.0.5"
|
"utf-8-validate": "6.0.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "3.936.0",
|
"@aws-sdk/client-s3": "3.937.0",
|
||||||
"@aws-sdk/lib-storage": "3.936.0",
|
"@aws-sdk/lib-storage": "3.937.0",
|
||||||
"@discordapp/twemoji": "16.0.1",
|
"@discordapp/twemoji": "16.0.1",
|
||||||
"@fastify/accepts": "5.0.3",
|
"@fastify/accepts": "5.0.3",
|
||||||
"@fastify/cookie": "11.0.2",
|
"@fastify/cookie": "11.0.2",
|
||||||
"@fastify/cors": "10.1.0",
|
"@fastify/cors": "11.1.0",
|
||||||
"@fastify/express": "4.0.2",
|
"@fastify/express": "4.0.2",
|
||||||
"@fastify/http-proxy": "10.0.2",
|
"@fastify/http-proxy": "11.3.0",
|
||||||
"@fastify/multipart": "9.3.0",
|
"@fastify/multipart": "9.3.0",
|
||||||
"@fastify/static": "8.3.0",
|
"@fastify/static": "8.3.0",
|
||||||
"@fastify/view": "10.0.2",
|
"@fastify/view": "11.1.1",
|
||||||
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
||||||
"@misskey-dev/summaly": "5.2.5",
|
"@misskey-dev/summaly": "5.2.5",
|
||||||
"@napi-rs/canvas": "0.1.82",
|
"@napi-rs/canvas": "0.1.82",
|
||||||
|
|
@ -90,33 +90,33 @@
|
||||||
"@peertube/http-signature": "1.7.0",
|
"@peertube/http-signature": "1.7.0",
|
||||||
"@sentry/node": "10.26.0",
|
"@sentry/node": "10.26.0",
|
||||||
"@sentry/profiling-node": "10.26.0",
|
"@sentry/profiling-node": "10.26.0",
|
||||||
"@simplewebauthn/server": "12.0.0",
|
"@simplewebauthn/server": "13.2.2",
|
||||||
"@sinonjs/fake-timers": "11.3.1",
|
"@sinonjs/fake-timers": "15.0.0",
|
||||||
"@smithy/node-http-handler": "2.5.0",
|
"@smithy/node-http-handler": "4.4.5",
|
||||||
"@swc/cli": "0.7.9",
|
"@swc/cli": "0.7.9",
|
||||||
"@swc/core": "1.15.2",
|
"@swc/core": "1.15.3",
|
||||||
"@twemoji/parser": "16.0.0",
|
"@twemoji/parser": "16.0.0",
|
||||||
"@types/redis-info": "3.0.3",
|
"@types/redis-info": "3.0.3",
|
||||||
"accepts": "1.3.8",
|
"accepts": "1.3.8",
|
||||||
"ajv": "8.17.1",
|
"ajv": "8.17.1",
|
||||||
"archiver": "7.0.1",
|
"archiver": "7.0.1",
|
||||||
"async-mutex": "0.5.0",
|
"async-mutex": "0.5.0",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "3.0.3",
|
||||||
"blurhash": "2.0.5",
|
"blurhash": "2.0.5",
|
||||||
"body-parser": "1.20.3",
|
"body-parser": "2.2.0",
|
||||||
"bullmq": "5.63.2",
|
"bullmq": "5.64.1",
|
||||||
"cacheable-lookup": "7.0.0",
|
"cacheable-lookup": "7.0.0",
|
||||||
"cbor": "9.0.2",
|
"cbor": "10.0.11",
|
||||||
"chalk": "5.6.2",
|
"chalk": "5.6.2",
|
||||||
"chalk-template": "1.1.2",
|
"chalk-template": "1.1.2",
|
||||||
"chokidar": "4.0.3",
|
"chokidar": "4.0.3",
|
||||||
"color-convert": "2.0.1",
|
"color-convert": "3.1.3",
|
||||||
"content-disposition": "0.5.4",
|
"content-disposition": "1.0.1",
|
||||||
"date-fns": "2.30.0",
|
"date-fns": "4.1.0",
|
||||||
"deep-email-validator": "0.1.21",
|
"deep-email-validator": "0.1.21",
|
||||||
"fastify": "5.6.2",
|
"fastify": "5.6.2",
|
||||||
"fastify-raw-body": "5.0.0",
|
"fastify-raw-body": "5.0.0",
|
||||||
"feed": "4.2.2",
|
"feed": "5.1.0",
|
||||||
"file-type": "21.1.1",
|
"file-type": "21.1.1",
|
||||||
"fluent-ffmpeg": "2.1.3",
|
"fluent-ffmpeg": "2.1.3",
|
||||||
"form-data": "4.0.5",
|
"form-data": "4.0.5",
|
||||||
|
|
@ -126,16 +126,16 @@
|
||||||
"ioredis": "5.8.2",
|
"ioredis": "5.8.2",
|
||||||
"ip-cidr": "4.0.2",
|
"ip-cidr": "4.0.2",
|
||||||
"ipaddr.js": "2.2.0",
|
"ipaddr.js": "2.2.0",
|
||||||
"is-svg": "5.1.0",
|
"is-svg": "6.1.0",
|
||||||
"js-yaml": "4.1.1",
|
"js-yaml": "4.1.1",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"jsonld": "8.3.3",
|
"jsonld": "9.0.0",
|
||||||
"jsrsasign": "11.1.0",
|
"jsrsasign": "11.1.0",
|
||||||
"juice": "11.0.3",
|
"juice": "11.0.3",
|
||||||
"meilisearch": "0.54.0",
|
"meilisearch": "0.54.0",
|
||||||
"mfm-js": "0.25.0",
|
"mfm-js": "0.25.0",
|
||||||
"microformats-parser": "2.0.4",
|
"microformats-parser": "2.0.4",
|
||||||
"mime-types": "2.1.35",
|
"mime-types": "3.0.2",
|
||||||
"misskey-js": "workspace:*",
|
"misskey-js": "workspace:*",
|
||||||
"misskey-reversi": "workspace:*",
|
"misskey-reversi": "workspace:*",
|
||||||
"ms": "3.0.0-canary.202508261828",
|
"ms": "3.0.0-canary.202508261828",
|
||||||
|
|
@ -151,7 +151,7 @@
|
||||||
"os-utils": "0.0.14",
|
"os-utils": "0.0.14",
|
||||||
"otpauth": "9.4.1",
|
"otpauth": "9.4.1",
|
||||||
"pg": "8.16.3",
|
"pg": "8.16.3",
|
||||||
"pkce-challenge": "4.1.0",
|
"pkce-challenge": "5.0.0",
|
||||||
"probe-image-size": "7.2.3",
|
"probe-image-size": "7.2.3",
|
||||||
"promise-limit": "2.7.0",
|
"promise-limit": "2.7.0",
|
||||||
"pug": "3.0.3",
|
"pug": "3.0.3",
|
||||||
|
|
@ -160,13 +160,12 @@
|
||||||
"ratelimiter": "3.4.1",
|
"ratelimiter": "3.4.1",
|
||||||
"re2": "1.22.3",
|
"re2": "1.22.3",
|
||||||
"redis-info": "3.1.0",
|
"redis-info": "3.1.0",
|
||||||
"redis-lock": "0.1.4",
|
|
||||||
"reflect-metadata": "0.2.2",
|
"reflect-metadata": "0.2.2",
|
||||||
"rename": "1.0.4",
|
"rename": "1.0.4",
|
||||||
"rss-parser": "3.13.0",
|
"rss-parser": "3.13.0",
|
||||||
"rxjs": "7.8.2",
|
"rxjs": "7.8.2",
|
||||||
"sanitize-html": "2.17.0",
|
"sanitize-html": "2.17.0",
|
||||||
"secure-json-parse": "3.0.2",
|
"secure-json-parse": "4.1.0",
|
||||||
"semver": "7.7.3",
|
"semver": "7.7.3",
|
||||||
"sharp": "0.33.5",
|
"sharp": "0.33.5",
|
||||||
"slacc": "0.0.10",
|
"slacc": "0.0.10",
|
||||||
|
|
@ -179,7 +178,7 @@
|
||||||
"tsconfig-paths": "4.2.0",
|
"tsconfig-paths": "4.2.0",
|
||||||
"typeorm": "0.3.27",
|
"typeorm": "0.3.27",
|
||||||
"typescript": "5.9.3",
|
"typescript": "5.9.3",
|
||||||
"ulid": "2.4.0",
|
"ulid": "3.0.1",
|
||||||
"vary": "1.1.2",
|
"vary": "1.1.2",
|
||||||
"web-push": "3.6.7",
|
"web-push": "3.6.7",
|
||||||
"ws": "8.18.3",
|
"ws": "8.18.3",
|
||||||
|
|
@ -187,13 +186,12 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@jest/globals": "29.7.0",
|
"@jest/globals": "29.7.0",
|
||||||
"@nestjs/platform-express": "10.4.20",
|
"@nestjs/platform-express": "11.1.9",
|
||||||
"@sentry/vue": "10.26.0",
|
"@sentry/vue": "10.26.0",
|
||||||
"@simplewebauthn/types": "12.0.0",
|
"@simplewebauthn/types": "12.0.0",
|
||||||
"@swc/jest": "0.2.39",
|
"@swc/jest": "0.2.39",
|
||||||
"@types/accepts": "1.3.7",
|
"@types/accepts": "1.3.7",
|
||||||
"@types/archiver": "6.0.4",
|
"@types/archiver": "7.0.0",
|
||||||
"@types/bcryptjs": "2.4.6",
|
|
||||||
"@types/body-parser": "1.19.6",
|
"@types/body-parser": "1.19.6",
|
||||||
"@types/color-convert": "2.0.4",
|
"@types/color-convert": "2.0.4",
|
||||||
"@types/content-disposition": "0.5.9",
|
"@types/content-disposition": "0.5.9",
|
||||||
|
|
@ -203,10 +201,10 @@
|
||||||
"@types/js-yaml": "4.0.9",
|
"@types/js-yaml": "4.0.9",
|
||||||
"@types/jsonld": "1.5.15",
|
"@types/jsonld": "1.5.15",
|
||||||
"@types/jsrsasign": "10.5.15",
|
"@types/jsrsasign": "10.5.15",
|
||||||
"@types/mime-types": "2.1.4",
|
"@types/mime-types": "3.0.1",
|
||||||
"@types/ms": "0.7.34",
|
"@types/ms": "2.1.0",
|
||||||
"@types/node": "24.10.1",
|
"@types/node": "24.10.1",
|
||||||
"@types/nodemailer": "6.4.21",
|
"@types/nodemailer": "7.0.4",
|
||||||
"@types/oauth": "0.9.6",
|
"@types/oauth": "0.9.6",
|
||||||
"@types/oauth2orize": "1.11.5",
|
"@types/oauth2orize": "1.11.5",
|
||||||
"@types/oauth2orize-pkce": "0.1.2",
|
"@types/oauth2orize-pkce": "0.1.2",
|
||||||
|
|
@ -219,7 +217,7 @@
|
||||||
"@types/sanitize-html": "2.16.0",
|
"@types/sanitize-html": "2.16.0",
|
||||||
"@types/semver": "7.7.1",
|
"@types/semver": "7.7.1",
|
||||||
"@types/simple-oauth2": "5.0.7",
|
"@types/simple-oauth2": "5.0.7",
|
||||||
"@types/sinonjs__fake-timers": "8.1.5",
|
"@types/sinonjs__fake-timers": "15.0.1",
|
||||||
"@types/supertest": "6.0.3",
|
"@types/supertest": "6.0.3",
|
||||||
"@types/tinycolor2": "1.4.6",
|
"@types/tinycolor2": "1.4.6",
|
||||||
"@types/tmp": "0.2.6",
|
"@types/tmp": "0.2.6",
|
||||||
|
|
@ -229,14 +227,15 @@
|
||||||
"@typescript-eslint/eslint-plugin": "8.47.0",
|
"@typescript-eslint/eslint-plugin": "8.47.0",
|
||||||
"@typescript-eslint/parser": "8.47.0",
|
"@typescript-eslint/parser": "8.47.0",
|
||||||
"aws-sdk-client-mock": "4.1.0",
|
"aws-sdk-client-mock": "4.1.0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "10.1.0",
|
||||||
"eslint-plugin-import": "2.32.0",
|
"eslint-plugin-import": "2.32.0",
|
||||||
"execa": "8.0.1",
|
"execa": "9.6.0",
|
||||||
"fkill": "9.0.0",
|
"fkill": "10.0.1",
|
||||||
"jest": "29.7.0",
|
"jest": "29.7.0",
|
||||||
"jest-mock": "29.7.0",
|
"jest-mock": "29.7.0",
|
||||||
|
"jest-util": "29.7.0",
|
||||||
"nodemon": "3.1.11",
|
"nodemon": "3.1.11",
|
||||||
"pid-port": "1.0.2",
|
"pid-port": "2.0.0",
|
||||||
"simple-oauth2": "5.1.0",
|
"simple-oauth2": "5.1.0",
|
||||||
"supertest": "7.1.4"
|
"supertest": "7.1.4"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare module 'redis-lock' {
|
|
||||||
import type Redis from 'ioredis';
|
|
||||||
|
|
||||||
type Lock = (lockName: string, timeout?: number, taskToPerform?: () => Promise<void>) => void;
|
|
||||||
function redisLock(client: Redis.Redis, retryDelay: number): Lock;
|
|
||||||
|
|
||||||
export = redisLock;
|
|
||||||
}
|
|
||||||
|
|
@ -3,42 +3,37 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { promisify } from 'node:util';
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import redisLock from 'redis-lock';
|
|
||||||
import * as Redis from 'ioredis';
|
import * as Redis from 'ioredis';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { acquireApObjectLock, acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
/**
|
|
||||||
* Retry delay (ms) for lock acquisition
|
|
||||||
*/
|
|
||||||
const retryDelay = 100;
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AppLockService {
|
export class AppLockService {
|
||||||
private lock: (key: string, timeout?: number, _?: (() => Promise<void>) | undefined) => Promise<() => void>;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.redis)
|
@Inject(DI.redis)
|
||||||
private redisClient: Redis.Redis,
|
private redisClient: Redis.Redis,
|
||||||
) {
|
) {
|
||||||
this.lock = promisify(redisLock(this.redisClient, retryDelay));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get AP Object lock
|
* Get AP Object lock
|
||||||
* @param uri AP object ID
|
* @param uri AP object ID
|
||||||
* @param timeout Lock timeout (ms), The timeout releases previous lock.
|
|
||||||
* @returns Unlock function
|
* @returns Unlock function
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public getApLock(uri: string, timeout = 30 * 1000): Promise<() => void> {
|
public getApLock(uri: string): Promise<() => Promise<void>> {
|
||||||
return this.lock(`ap-object:${uri}`, timeout);
|
return acquireApObjectLock(this.redisClient, uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get chart insert lock
|
||||||
|
* @param lockKey Lock key
|
||||||
|
* @returns Unlock function
|
||||||
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public getChartInsertLock(lockKey: string, timeout = 30 * 1000): Promise<() => void> {
|
public getChartInsertLock(lockKey: string): Promise<() => Promise<void>> {
|
||||||
return this.lock(`chart-insert:${lockKey}`, timeout);
|
return acquireChartInsertLock(this.redisClient, lockKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ import { ChannelMutingService } from '@/core/ChannelMutingService.js';
|
||||||
import { AccountMoveService } from './AccountMoveService.js';
|
import { AccountMoveService } from './AccountMoveService.js';
|
||||||
import { AccountUpdateService } from './AccountUpdateService.js';
|
import { AccountUpdateService } from './AccountUpdateService.js';
|
||||||
import { AiService } from './AiService.js';
|
import { AiService } from './AiService.js';
|
||||||
|
import { AppLockService } from './AppLockService.js';
|
||||||
import { AnnouncementService } from './AnnouncementService.js';
|
import { AnnouncementService } from './AnnouncementService.js';
|
||||||
import { AntennaService } from './AntennaService.js';
|
import { AntennaService } from './AntennaService.js';
|
||||||
import { AppLockService } from './AppLockService.js';
|
|
||||||
import { AchievementService } from './AchievementService.js';
|
import { AchievementService } from './AchievementService.js';
|
||||||
import { AvatarDecorationService } from './AvatarDecorationService.js';
|
import { AvatarDecorationService } from './AvatarDecorationService.js';
|
||||||
import { CaptchaService } from './CaptchaService.js';
|
import { CaptchaService } from './CaptchaService.js';
|
||||||
|
|
@ -164,9 +164,9 @@ const $AbuseReportNotificationService: Provider = { provide: 'AbuseReportNotific
|
||||||
const $AccountMoveService: Provider = { provide: 'AccountMoveService', useExisting: AccountMoveService };
|
const $AccountMoveService: Provider = { provide: 'AccountMoveService', useExisting: AccountMoveService };
|
||||||
const $AccountUpdateService: Provider = { provide: 'AccountUpdateService', useExisting: AccountUpdateService };
|
const $AccountUpdateService: Provider = { provide: 'AccountUpdateService', useExisting: AccountUpdateService };
|
||||||
const $AiService: Provider = { provide: 'AiService', useExisting: AiService };
|
const $AiService: Provider = { provide: 'AiService', useExisting: AiService };
|
||||||
|
const $AppLockService: Provider = { provide: 'AppLockService', useExisting: AppLockService };
|
||||||
const $AnnouncementService: Provider = { provide: 'AnnouncementService', useExisting: AnnouncementService };
|
const $AnnouncementService: Provider = { provide: 'AnnouncementService', useExisting: AnnouncementService };
|
||||||
const $AntennaService: Provider = { provide: 'AntennaService', useExisting: AntennaService };
|
const $AntennaService: Provider = { provide: 'AntennaService', useExisting: AntennaService };
|
||||||
const $AppLockService: Provider = { provide: 'AppLockService', useExisting: AppLockService };
|
|
||||||
const $AchievementService: Provider = { provide: 'AchievementService', useExisting: AchievementService };
|
const $AchievementService: Provider = { provide: 'AchievementService', useExisting: AchievementService };
|
||||||
const $AvatarDecorationService: Provider = { provide: 'AvatarDecorationService', useExisting: AvatarDecorationService };
|
const $AvatarDecorationService: Provider = { provide: 'AvatarDecorationService', useExisting: AvatarDecorationService };
|
||||||
const $CaptchaService: Provider = { provide: 'CaptchaService', useExisting: CaptchaService };
|
const $CaptchaService: Provider = { provide: 'CaptchaService', useExisting: CaptchaService };
|
||||||
|
|
@ -318,9 +318,9 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
AccountMoveService,
|
AccountMoveService,
|
||||||
AccountUpdateService,
|
AccountUpdateService,
|
||||||
AiService,
|
AiService,
|
||||||
|
AppLockService,
|
||||||
AnnouncementService,
|
AnnouncementService,
|
||||||
AntennaService,
|
AntennaService,
|
||||||
AppLockService,
|
|
||||||
AchievementService,
|
AchievementService,
|
||||||
AvatarDecorationService,
|
AvatarDecorationService,
|
||||||
CaptchaService,
|
CaptchaService,
|
||||||
|
|
@ -468,9 +468,9 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$AccountMoveService,
|
$AccountMoveService,
|
||||||
$AccountUpdateService,
|
$AccountUpdateService,
|
||||||
$AiService,
|
$AiService,
|
||||||
|
$AppLockService,
|
||||||
$AnnouncementService,
|
$AnnouncementService,
|
||||||
$AntennaService,
|
$AntennaService,
|
||||||
$AppLockService,
|
|
||||||
$AchievementService,
|
$AchievementService,
|
||||||
$AvatarDecorationService,
|
$AvatarDecorationService,
|
||||||
$CaptchaService,
|
$CaptchaService,
|
||||||
|
|
@ -619,9 +619,9 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
AccountMoveService,
|
AccountMoveService,
|
||||||
AccountUpdateService,
|
AccountUpdateService,
|
||||||
AiService,
|
AiService,
|
||||||
|
AppLockService,
|
||||||
AnnouncementService,
|
AnnouncementService,
|
||||||
AntennaService,
|
AntennaService,
|
||||||
AppLockService,
|
|
||||||
AchievementService,
|
AchievementService,
|
||||||
AvatarDecorationService,
|
AvatarDecorationService,
|
||||||
CaptchaService,
|
CaptchaService,
|
||||||
|
|
@ -768,9 +768,9 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$AccountMoveService,
|
$AccountMoveService,
|
||||||
$AccountUpdateService,
|
$AccountUpdateService,
|
||||||
$AiService,
|
$AiService,
|
||||||
|
$AppLockService,
|
||||||
$AnnouncementService,
|
$AnnouncementService,
|
||||||
$AntennaService,
|
$AntennaService,
|
||||||
$AppLockService,
|
|
||||||
$AchievementService,
|
$AchievementService,
|
||||||
$AvatarDecorationService,
|
$AvatarDecorationService,
|
||||||
$CaptchaService,
|
$CaptchaService,
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,6 @@ export class WebAuthnService {
|
||||||
userID: isoUint8Array.fromUTF8String(userId),
|
userID: isoUint8Array.fromUTF8String(userId),
|
||||||
userName: userName,
|
userName: userName,
|
||||||
userDisplayName: userDisplayName,
|
userDisplayName: userDisplayName,
|
||||||
attestationType: 'indirect',
|
|
||||||
excludeCredentials: keys.map(key => (<{ id: string; transports?: AuthenticatorTransportFuture[]; }>{
|
excludeCredentials: keys.map(key => (<{ id: string; transports?: AuthenticatorTransportFuture[]; }>{
|
||||||
id: key.id,
|
id: key.id,
|
||||||
transports: key.transports ?? undefined,
|
transports: key.transports ?? undefined,
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ import { UserBlockingService } from '@/core/UserBlockingService.js';
|
||||||
import { NoteDeleteService } from '@/core/NoteDeleteService.js';
|
import { NoteDeleteService } from '@/core/NoteDeleteService.js';
|
||||||
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
||||||
import { concat, toArray, toSingle, unique } from '@/misc/prelude/array.js';
|
import { concat, toArray, toSingle, unique } from '@/misc/prelude/array.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { StatusError } from '@/misc/status-error.js';
|
import { StatusError } from '@/misc/status-error.js';
|
||||||
|
|
@ -29,6 +28,7 @@ import type { MiRemoteUser } from '@/models/User.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
import { AbuseReportService } from '@/core/AbuseReportService.js';
|
import { AbuseReportService } from '@/core/AbuseReportService.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
|
import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
|
||||||
import { ApNoteService } from './models/ApNoteService.js';
|
import { ApNoteService } from './models/ApNoteService.js';
|
||||||
import { ApLoggerService } from './ApLoggerService.js';
|
import { ApLoggerService } from './ApLoggerService.js';
|
||||||
|
|
@ -48,9 +48,6 @@ export class ApInboxService {
|
||||||
@Inject(DI.config)
|
@Inject(DI.config)
|
||||||
private config: Config,
|
private config: Config,
|
||||||
|
|
||||||
@Inject(DI.meta)
|
|
||||||
private meta: MiMeta,
|
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
@Inject(DI.usersRepository)
|
||||||
private usersRepository: UsersRepository,
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
|
|
@ -76,7 +73,6 @@ export class ApInboxService {
|
||||||
private userBlockingService: UserBlockingService,
|
private userBlockingService: UserBlockingService,
|
||||||
private noteCreateService: NoteCreateService,
|
private noteCreateService: NoteCreateService,
|
||||||
private noteDeleteService: NoteDeleteService,
|
private noteDeleteService: NoteDeleteService,
|
||||||
private appLockService: AppLockService,
|
|
||||||
private apResolverService: ApResolverService,
|
private apResolverService: ApResolverService,
|
||||||
private apDbResolverService: ApDbResolverService,
|
private apDbResolverService: ApDbResolverService,
|
||||||
private apLoggerService: ApLoggerService,
|
private apLoggerService: ApLoggerService,
|
||||||
|
|
@ -85,6 +81,7 @@ export class ApInboxService {
|
||||||
private apQuestionService: ApQuestionService,
|
private apQuestionService: ApQuestionService,
|
||||||
private queueService: QueueService,
|
private queueService: QueueService,
|
||||||
private globalEventService: GlobalEventService,
|
private globalEventService: GlobalEventService,
|
||||||
|
private appLockService: AppLockService,
|
||||||
) {
|
) {
|
||||||
this.logger = this.apLoggerService.logger;
|
this.logger = this.apLoggerService.logger;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import type { MiRemoteUser } from '@/models/User.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
import { toArray, toSingle, unique } from '@/misc/prelude/array.js';
|
import { toArray, toSingle, unique } from '@/misc/prelude/array.js';
|
||||||
import type { MiEmoji } from '@/models/Emoji.js';
|
import type { MiEmoji } from '@/models/Emoji.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
|
|
@ -23,6 +22,7 @@ import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { checkHttps } from '@/misc/check-https.js';
|
import { checkHttps } from '@/misc/check-https.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { getOneApId, getApId, getOneApHrefNullable, validPost, isEmoji, getApType } from '../type.js';
|
import { getOneApId, getApId, getOneApHrefNullable, validPost, isEmoji, getApType } from '../type.js';
|
||||||
import { ApLoggerService } from '../ApLoggerService.js';
|
import { ApLoggerService } from '../ApLoggerService.js';
|
||||||
import { ApMfmService } from '../ApMfmService.js';
|
import { ApMfmService } from '../ApMfmService.js';
|
||||||
|
|
@ -67,11 +67,11 @@ export class ApNoteService {
|
||||||
private apMentionService: ApMentionService,
|
private apMentionService: ApMentionService,
|
||||||
private apImageService: ApImageService,
|
private apImageService: ApImageService,
|
||||||
private apQuestionService: ApQuestionService,
|
private apQuestionService: ApQuestionService,
|
||||||
private appLockService: AppLockService,
|
|
||||||
private pollService: PollService,
|
private pollService: PollService,
|
||||||
private noteCreateService: NoteCreateService,
|
private noteCreateService: NoteCreateService,
|
||||||
private apDbResolverService: ApDbResolverService,
|
private apDbResolverService: ApDbResolverService,
|
||||||
private apLoggerService: ApLoggerService,
|
private apLoggerService: ApLoggerService,
|
||||||
|
private appLockService: AppLockService,
|
||||||
) {
|
) {
|
||||||
this.logger = this.apLoggerService.logger;
|
this.logger = this.apLoggerService.logger;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,12 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import * as Redis from 'ioredis';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/active-users.js';
|
import { name, schema } from './entities/active-users.js';
|
||||||
|
|
@ -28,11 +29,13 @@ export default class ActiveUsersChart extends Chart<typeof schema> { // eslint-d
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), chartLoggerService.logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,10 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import * as Redis from 'ioredis';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/ap-request.js';
|
import { name, schema } from './entities/ap-request.js';
|
||||||
|
|
@ -22,10 +23,12 @@ export default class ApRequestChart extends Chart<typeof schema> { // eslint-dis
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), chartLoggerService.logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/drive.js';
|
import { name, schema } from './entities/drive.js';
|
||||||
|
|
@ -23,10 +24,12 @@ export default class DriveChart extends Chart<typeof schema> { // eslint-disable
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), chartLoggerService.logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { FollowingsRepository, InstancesRepository, MiMeta } from '@/models/_.js';
|
import type { FollowingsRepository, InstancesRepository, MiMeta } from '@/models/_.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/federation.js';
|
import { name, schema } from './entities/federation.js';
|
||||||
|
|
@ -26,16 +27,18 @@ export default class FederationChart extends Chart<typeof schema> { // eslint-di
|
||||||
@Inject(DI.meta)
|
@Inject(DI.meta)
|
||||||
private meta: MiMeta,
|
private meta: MiMeta,
|
||||||
|
|
||||||
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.followingsRepository)
|
@Inject(DI.followingsRepository)
|
||||||
private followingsRepository: FollowingsRepository,
|
private followingsRepository: FollowingsRepository,
|
||||||
|
|
||||||
@Inject(DI.instancesRepository)
|
@Inject(DI.instancesRepository)
|
||||||
private instancesRepository: InstancesRepository,
|
private instancesRepository: InstancesRepository,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), chartLoggerService.logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,14 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { DriveFilesRepository, FollowingsRepository, UsersRepository, NotesRepository } from '@/models/_.js';
|
import type { DriveFilesRepository, FollowingsRepository, UsersRepository, NotesRepository } from '@/models/_.js';
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/instance.js';
|
import { name, schema } from './entities/instance.js';
|
||||||
|
|
@ -26,6 +27,9 @@ export default class InstanceChart extends Chart<typeof schema> { // eslint-disa
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
@Inject(DI.usersRepository)
|
||||||
private usersRepository: UsersRepository,
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
|
|
@ -39,10 +43,9 @@ export default class InstanceChart extends Chart<typeof schema> { // eslint-disa
|
||||||
private followingsRepository: FollowingsRepository,
|
private followingsRepository: FollowingsRepository,
|
||||||
|
|
||||||
private utilityService: UtilityService,
|
private utilityService: UtilityService,
|
||||||
private appLockService: AppLockService,
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema, true);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), chartLoggerService.logger, name, schema, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,12 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { Not, IsNull, DataSource } from 'typeorm';
|
import { Not, IsNull, DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { NotesRepository } from '@/models/_.js';
|
import type { NotesRepository } from '@/models/_.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/notes.js';
|
import { name, schema } from './entities/notes.js';
|
||||||
|
|
@ -24,13 +25,15 @@ export default class NotesChart extends Chart<typeof schema> { // eslint-disable
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.notesRepository)
|
@Inject(DI.notesRepository)
|
||||||
private notesRepository: NotesRepository,
|
private notesRepository: NotesRepository,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), chartLoggerService.logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,13 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { DriveFilesRepository } from '@/models/_.js';
|
import type { DriveFilesRepository } from '@/models/_.js';
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/per-user-drive.js';
|
import { name, schema } from './entities/per-user-drive.js';
|
||||||
|
|
@ -25,14 +26,16 @@ export default class PerUserDriveChart extends Chart<typeof schema> { // eslint-
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.driveFilesRepository)
|
@Inject(DI.driveFilesRepository)
|
||||||
private driveFilesRepository: DriveFilesRepository,
|
private driveFilesRepository: DriveFilesRepository,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
|
||||||
private driveFileEntityService: DriveFileEntityService,
|
private driveFileEntityService: DriveFileEntityService,
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema, true);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), chartLoggerService.logger, name, schema, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,13 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { Not, IsNull, DataSource } from 'typeorm';
|
import { Not, IsNull, DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import type { FollowingsRepository } from '@/models/_.js';
|
import type { FollowingsRepository } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/per-user-following.js';
|
import { name, schema } from './entities/per-user-following.js';
|
||||||
|
|
@ -25,14 +26,16 @@ export default class PerUserFollowingChart extends Chart<typeof schema> { // esl
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.followingsRepository)
|
@Inject(DI.followingsRepository)
|
||||||
private followingsRepository: FollowingsRepository,
|
private followingsRepository: FollowingsRepository,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema, true);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), chartLoggerService.logger, name, schema, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,13 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { NotesRepository } from '@/models/_.js';
|
import type { NotesRepository } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/per-user-notes.js';
|
import { name, schema } from './entities/per-user-notes.js';
|
||||||
|
|
@ -25,13 +26,15 @@ export default class PerUserNotesChart extends Chart<typeof schema> { // eslint-
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.notesRepository)
|
@Inject(DI.notesRepository)
|
||||||
private notesRepository: NotesRepository,
|
private notesRepository: NotesRepository,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema, true);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), chartLoggerService.logger, name, schema, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/per-user-pv.js';
|
import { name, schema } from './entities/per-user-pv.js';
|
||||||
|
|
@ -23,10 +24,12 @@ export default class PerUserPvChart extends Chart<typeof schema> { // eslint-dis
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema, true);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), chartLoggerService.logger, name, schema, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,13 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/per-user-reactions.js';
|
import { name, schema } from './entities/per-user-reactions.js';
|
||||||
|
|
@ -25,11 +26,13 @@ export default class PerUserReactionsChart extends Chart<typeof schema> { // esl
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema, true);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), chartLoggerService.logger, name, schema, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import * as Redis from 'ioredis';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { name, schema } from './entities/test-grouped.js';
|
import { name, schema } from './entities/test-grouped.js';
|
||||||
import type { KVs } from '../core.js';
|
import type { KVs } from '../core.js';
|
||||||
|
|
@ -24,10 +25,12 @@ export default class TestGroupedChart extends Chart<typeof schema> { // eslint-d
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), logger, name, schema, true);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), logger, name, schema, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(group: string): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import * as Redis from 'ioredis';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { name, schema } from './entities/test-intersection.js';
|
import { name, schema } from './entities/test-intersection.js';
|
||||||
import type { KVs } from '../core.js';
|
import type { KVs } from '../core.js';
|
||||||
|
|
@ -22,10 +23,12 @@ export default class TestIntersectionChart extends Chart<typeof schema> { // esl
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import * as Redis from 'ioredis';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { name, schema } from './entities/test-unique.js';
|
import { name, schema } from './entities/test-unique.js';
|
||||||
import type { KVs } from '../core.js';
|
import type { KVs } from '../core.js';
|
||||||
|
|
@ -22,10 +23,12 @@ export default class TestUniqueChart extends Chart<typeof schema> { // eslint-di
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import * as Redis from 'ioredis';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { name, schema } from './entities/test.js';
|
import { name, schema } from './entities/test.js';
|
||||||
import type { KVs } from '../core.js';
|
import type { KVs } from '../core.js';
|
||||||
|
|
@ -24,10 +25,12 @@ export default class TestChart extends Chart<typeof schema> { // eslint-disable-
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,13 @@
|
||||||
|
|
||||||
import { Injectable, Inject } from '@nestjs/common';
|
import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { Not, IsNull, DataSource } from 'typeorm';
|
import { Not, IsNull, DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import type { UsersRepository } from '@/models/_.js';
|
import type { UsersRepository } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { acquireChartInsertLock } from '@/misc/distributed-lock.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/users.js';
|
import { name, schema } from './entities/users.js';
|
||||||
|
|
@ -25,14 +26,16 @@ export default class UsersChart extends Chart<typeof schema> { // eslint-disable
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
@Inject(DI.usersRepository)
|
||||||
private usersRepository: UsersRepository,
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
private appLockService: AppLockService,
|
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private chartLoggerService: ChartLoggerService,
|
private chartLoggerService: ChartLoggerService,
|
||||||
) {
|
) {
|
||||||
super(db, (k) => appLockService.getChartInsertLock(k), chartLoggerService.logger, name, schema);
|
super(db, (k) => acquireChartInsertLock(redisClient, k), chartLoggerService.logger, name, schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
protected async tickMajor(): Promise<Partial<KVs<typeof schema>>> {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
|
|
||||||
|
export async function acquireDistributedLock(
|
||||||
|
redis: Redis.Redis,
|
||||||
|
name: string,
|
||||||
|
timeout: number,
|
||||||
|
maxRetries: number,
|
||||||
|
retryInterval: number,
|
||||||
|
): Promise<() => Promise<void>> {
|
||||||
|
const lockKey = `lock:${name}`;
|
||||||
|
const identifier = Math.random().toString(36).slice(2);
|
||||||
|
|
||||||
|
let retries = 0;
|
||||||
|
while (retries < maxRetries) {
|
||||||
|
const result = await redis.set(lockKey, identifier, 'PX', timeout, 'NX');
|
||||||
|
if (result === 'OK') {
|
||||||
|
return async () => {
|
||||||
|
const currentIdentifier = await redis.get(lockKey);
|
||||||
|
if (currentIdentifier === identifier) {
|
||||||
|
await redis.del(lockKey);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await new Promise(resolve => setTimeout(resolve, retryInterval));
|
||||||
|
retries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Failed to acquire lock ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function acquireApObjectLock(
|
||||||
|
redis: Redis.Redis,
|
||||||
|
uri: string,
|
||||||
|
): Promise<() => Promise<void>> {
|
||||||
|
return acquireDistributedLock(redis, `ap-object:${uri}`, 30 * 1000, 50, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function acquireChartInsertLock(
|
||||||
|
redis: Redis.Redis,
|
||||||
|
name: string,
|
||||||
|
): Promise<() => Promise<void>> {
|
||||||
|
return acquireDistributedLock(redis, `chart-insert:${name}`, 30 * 1000, 50, 500);
|
||||||
|
}
|
||||||
|
|
@ -9,3 +9,4 @@ beforeAll(async () => {
|
||||||
await initTestDb(false);
|
await initTestDb(false);
|
||||||
await sendEnvResetRequest();
|
await sendEnvResetRequest();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||||
import { secureRndstr } from '@/misc/secure-rndstr.js';
|
import { secureRndstr } from '@/misc/secure-rndstr.js';
|
||||||
import type { TestingModule } from '@nestjs/testing';
|
import type { TestingModule } from '@nestjs/testing';
|
||||||
import type { MockFunctionMetadata } from 'jest-mock';
|
import type { MockMetadata } from 'jest-mock';
|
||||||
|
|
||||||
const moduleMocker = new ModuleMocker(global);
|
const moduleMocker = new ModuleMocker(global);
|
||||||
|
|
||||||
|
|
@ -84,7 +84,7 @@ describe('AnnouncementService', () => {
|
||||||
log: jest.fn(),
|
log: jest.fn(),
|
||||||
};
|
};
|
||||||
} else if (typeof token === 'function') {
|
} else if (typeof token === 'function') {
|
||||||
const mockMetadata = moduleMocker.getMetadata(token) as MockFunctionMetadata<any, any>;
|
const mockMetadata = moduleMocker.getMetadata(token) as MockMetadata<any, any>;
|
||||||
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
|
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
|
||||||
return new Mock();
|
return new Mock();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -446,7 +446,7 @@ describe('CaptchaService', () => {
|
||||||
if (!res.success) {
|
if (!res.success) {
|
||||||
expect(res.error.code).toBe(code);
|
expect(res.error.code).toBe(code);
|
||||||
}
|
}
|
||||||
expect(metaService.update).not.toBeCalled();
|
expect(metaService.update).not.toHaveBeenCalled();
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('invalidParameters', () => {
|
describe('invalidParameters', () => {
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ describe('DriveService', () => {
|
||||||
s3Mock.on(DeleteObjectCommand)
|
s3Mock.on(DeleteObjectCommand)
|
||||||
.rejects(new InvalidObjectState({ $metadata: {}, message: '' }));
|
.rejects(new InvalidObjectState({ $metadata: {}, message: '' }));
|
||||||
|
|
||||||
await expect(driveService.deleteObjectStorageFile('unexpected')).rejects.toThrowError(Error);
|
await expect(driveService.deleteObjectStorageFile('unexpected')).rejects.toThrow(Error);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('delete a file with no valid key', async () => {
|
test('delete a file with no valid key', async () => {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import { FileInfo, FileInfoService } from '@/core/FileInfoService.js';
|
||||||
import { AiService } from '@/core/AiService.js';
|
import { AiService } from '@/core/AiService.js';
|
||||||
import { LoggerService } from '@/core/LoggerService.js';
|
import { LoggerService } from '@/core/LoggerService.js';
|
||||||
import type { TestingModule } from '@nestjs/testing';
|
import type { TestingModule } from '@nestjs/testing';
|
||||||
import type { MockFunctionMetadata } from 'jest-mock';
|
import type { MockMetadata } from 'jest-mock';
|
||||||
|
|
||||||
const _filename = fileURLToPath(import.meta.url);
|
const _filename = fileURLToPath(import.meta.url);
|
||||||
const _dirname = dirname(_filename);
|
const _dirname = dirname(_filename);
|
||||||
|
|
@ -34,7 +34,7 @@ describe('FileInfoService', () => {
|
||||||
delete fi.sensitive;
|
delete fi.sensitive;
|
||||||
delete fi.blurhash;
|
delete fi.blurhash;
|
||||||
delete fi.porn;
|
delete fi.porn;
|
||||||
|
|
||||||
return fi;
|
return fi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ describe('FileInfoService', () => {
|
||||||
// return { };
|
// return { };
|
||||||
//}
|
//}
|
||||||
if (typeof token === 'function') {
|
if (typeof token === 'function') {
|
||||||
const mockMetadata = moduleMocker.getMetadata(token) as MockFunctionMetadata<any, any>;
|
const mockMetadata = moduleMocker.getMetadata(token) as MockMetadata<any, any>;
|
||||||
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
|
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
|
||||||
return new Mock();
|
return new Mock();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { jest } from '@jest/globals';
|
||||||
import { Test } from '@nestjs/testing';
|
import { Test } from '@nestjs/testing';
|
||||||
import { ModuleMocker } from 'jest-mock';
|
import { ModuleMocker } from 'jest-mock';
|
||||||
import type { TestingModule } from '@nestjs/testing';
|
import type { TestingModule } from '@nestjs/testing';
|
||||||
import type { MockFunctionMetadata } from 'jest-mock';
|
import type { MockMetadata } from 'jest-mock';
|
||||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
|
@ -45,7 +45,7 @@ describe('RelayService', () => {
|
||||||
return { deliver: jest.fn() };
|
return { deliver: jest.fn() };
|
||||||
}
|
}
|
||||||
if (typeof token === 'function') {
|
if (typeof token === 'function') {
|
||||||
const mockMetadata = moduleMocker.getMetadata(token) as MockFunctionMetadata<any, any>;
|
const mockMetadata = moduleMocker.getMetadata(token) as MockMetadata<any, any>;
|
||||||
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
|
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
|
||||||
return new Mock();
|
return new Mock();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import { ModuleMocker } from 'jest-mock';
|
||||||
import { Test } from '@nestjs/testing';
|
import { Test } from '@nestjs/testing';
|
||||||
import * as lolex from '@sinonjs/fake-timers';
|
import * as lolex from '@sinonjs/fake-timers';
|
||||||
import type { TestingModule } from '@nestjs/testing';
|
import type { TestingModule } from '@nestjs/testing';
|
||||||
import type { MockFunctionMetadata } from 'jest-mock';
|
import type { MockMetadata } from 'jest-mock';
|
||||||
import { GlobalModule } from '@/GlobalModule.js';
|
import { GlobalModule } from '@/GlobalModule.js';
|
||||||
import { RoleService } from '@/core/RoleService.js';
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
import {
|
import {
|
||||||
|
|
@ -104,6 +104,8 @@ describe('RoleService', () => {
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
clock = lolex.install({
|
clock = lolex.install({
|
||||||
|
// https://github.com/sinonjs/sinon/issues/2620
|
||||||
|
toFake: Object.keys(lolex.timers).filter((key) => !['nextTick', 'queueMicrotask'].includes(key)) as lolex.FakeMethod[],
|
||||||
now: new Date(),
|
now: new Date(),
|
||||||
shouldClearNativeTimers: true,
|
shouldClearNativeTimers: true,
|
||||||
});
|
});
|
||||||
|
|
@ -135,7 +137,7 @@ describe('RoleService', () => {
|
||||||
return { fetch: jest.fn() };
|
return { fetch: jest.fn() };
|
||||||
}
|
}
|
||||||
if (typeof token === 'function') {
|
if (typeof token === 'function') {
|
||||||
const mockMetadata = moduleMocker.getMetadata(token) as MockFunctionMetadata<any, any>;
|
const mockMetadata = moduleMocker.getMetadata(token) as MockMetadata<any, any>;
|
||||||
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
|
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
|
||||||
return new Mock();
|
return new Mock();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ describe('S3Service', () => {
|
||||||
Bucket: 'fake',
|
Bucket: 'fake',
|
||||||
Key: 'fake',
|
Key: 'fake',
|
||||||
Body: 'x',
|
Body: 'x',
|
||||||
})).rejects.toThrowError(Error);
|
})).rejects.toThrow(Error);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('upload a large file error', async () => {
|
test('upload a large file error', async () => {
|
||||||
|
|
@ -82,7 +82,7 @@ describe('S3Service', () => {
|
||||||
Bucket: 'fake',
|
Bucket: 'fake',
|
||||||
Key: 'fake',
|
Key: 'fake',
|
||||||
Body: 'x'.repeat(8 * 1024 * 1024 + 1), // デフォルトpartSizeにしている 8 * 1024 * 1024 を越えるサイズ
|
Body: 'x'.repeat(8 * 1024 * 1024 + 1), // デフォルトpartSizeにしている 8 * 1024 * 1024 を越えるサイズ
|
||||||
})).rejects.toThrowError(Error);
|
})).rejects.toThrow(Error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { FastifyReply, FastifyRequest } from 'fastify';
|
import { FastifyReply, FastifyRequest } from 'fastify';
|
||||||
import { AuthenticationResponseJSON } from '@simplewebauthn/types';
|
import { AuthenticationResponseJSON } from '@simplewebauthn/types';
|
||||||
import { HttpHeader } from 'fastify/types/utils.js';
|
import { HttpHeader } from 'fastify/types/utils.js';
|
||||||
import { MockFunctionMetadata, ModuleMocker } from 'jest-mock';
|
import { MockMetadata, ModuleMocker } from 'jest-mock';
|
||||||
import { MiUser } from '@/models/User.js';
|
import { MiUser } from '@/models/User.js';
|
||||||
import { MiUserProfile, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
import { MiUserProfile, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
|
@ -95,7 +95,7 @@ describe('SigninWithPasskeyApiService', () => {
|
||||||
],
|
],
|
||||||
}).useMocker((token) => {
|
}).useMocker((token) => {
|
||||||
if (typeof token === 'function') {
|
if (typeof token === 'function') {
|
||||||
const mockMetadata = moduleMocker.getMetadata(token) as MockFunctionMetadata<any, any>;
|
const mockMetadata = moduleMocker.getMetadata(token) as MockMetadata<any, any>;
|
||||||
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
|
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
|
||||||
return new Mock();
|
return new Mock();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import * as assert from 'assert';
|
||||||
import { jest } from '@jest/globals';
|
import { jest } from '@jest/globals';
|
||||||
import * as lolex from '@sinonjs/fake-timers';
|
import * as lolex from '@sinonjs/fake-timers';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import TestChart from '@/core/chart/charts/test.js';
|
import TestChart from '@/core/chart/charts/test.js';
|
||||||
import TestGroupedChart from '@/core/chart/charts/test-grouped.js';
|
import TestGroupedChart from '@/core/chart/charts/test-grouped.js';
|
||||||
import TestUniqueChart from '@/core/chart/charts/test-unique.js';
|
import TestUniqueChart from '@/core/chart/charts/test-unique.js';
|
||||||
|
|
@ -18,16 +19,16 @@ import { entity as TestGroupedChartEntity } from '@/core/chart/charts/entities/t
|
||||||
import { entity as TestUniqueChartEntity } from '@/core/chart/charts/entities/test-unique.js';
|
import { entity as TestUniqueChartEntity } from '@/core/chart/charts/entities/test-unique.js';
|
||||||
import { entity as TestIntersectionChartEntity } from '@/core/chart/charts/entities/test-intersection.js';
|
import { entity as TestIntersectionChartEntity } from '@/core/chart/charts/entities/test-intersection.js';
|
||||||
import { loadConfig } from '@/config.js';
|
import { loadConfig } from '@/config.js';
|
||||||
import type { AppLockService } from '@/core/AppLockService.js';
|
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
|
|
||||||
describe('Chart', () => {
|
describe('Chart', () => {
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
const appLockService = {
|
|
||||||
getChartInsertLock: () => () => Promise.resolve(() => {}),
|
|
||||||
} as unknown as jest.Mocked<AppLockService>;
|
|
||||||
|
|
||||||
let db: DataSource | undefined;
|
let db: DataSource | undefined;
|
||||||
|
let redisClient = {
|
||||||
|
set: () => Promise.resolve('OK'),
|
||||||
|
get: () => Promise.resolve(null),
|
||||||
|
} as unknown as jest.Mocked<Redis.Redis>;
|
||||||
|
|
||||||
let testChart: TestChart;
|
let testChart: TestChart;
|
||||||
let testGroupedChart: TestGroupedChart;
|
let testGroupedChart: TestGroupedChart;
|
||||||
|
|
@ -64,12 +65,14 @@ describe('Chart', () => {
|
||||||
await db.initialize();
|
await db.initialize();
|
||||||
|
|
||||||
const logger = new Logger('chart'); // TODO: モックにする
|
const logger = new Logger('chart'); // TODO: モックにする
|
||||||
testChart = new TestChart(db, appLockService, logger);
|
testChart = new TestChart(db, redisClient, logger);
|
||||||
testGroupedChart = new TestGroupedChart(db, appLockService, logger);
|
testGroupedChart = new TestGroupedChart(db, redisClient, logger);
|
||||||
testUniqueChart = new TestUniqueChart(db, appLockService, logger);
|
testUniqueChart = new TestUniqueChart(db, redisClient, logger);
|
||||||
testIntersectionChart = new TestIntersectionChart(db, appLockService, logger);
|
testIntersectionChart = new TestIntersectionChart(db, redisClient, logger);
|
||||||
|
|
||||||
clock = lolex.install({
|
clock = lolex.install({
|
||||||
|
// https://github.com/sinonjs/sinon/issues/2620
|
||||||
|
toFake: Object.keys(lolex.timers).filter((key) => !['nextTick', 'queueMicrotask'].includes(key)) as lolex.FakeMethod[],
|
||||||
now: new Date(Date.UTC(2000, 0, 1, 0, 0, 0)),
|
now: new Date(Date.UTC(2000, 0, 1, 0, 0, 0)),
|
||||||
shouldClearNativeTimers: true,
|
shouldClearNativeTimers: true,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,8 @@ describe('CheckModeratorsActivityProcessorService', () => {
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
clock = lolex.install({
|
clock = lolex.install({
|
||||||
|
// https://github.com/sinonjs/sinon/issues/2620
|
||||||
|
toFake: Object.keys(lolex.timers).filter((key) => !['nextTick', 'queueMicrotask'].includes(key)) as lolex.FakeMethod[],
|
||||||
now: new Date(baseDate),
|
now: new Date(baseDate),
|
||||||
shouldClearNativeTimers: true,
|
shouldClearNativeTimers: true,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
1194
pnpm-lock.yaml
1194
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -14,6 +14,7 @@ onlyBuiltDependencies:
|
||||||
- '@nestjs/core'
|
- '@nestjs/core'
|
||||||
- '@parcel/watcher'
|
- '@parcel/watcher'
|
||||||
- '@sentry/profiling-node'
|
- '@sentry/profiling-node'
|
||||||
|
- '@sentry-internal/node-cpu-profiler'
|
||||||
- '@swc/core'
|
- '@swc/core'
|
||||||
- '@tensorflow/tfjs-node'
|
- '@tensorflow/tfjs-node'
|
||||||
- bufferutil
|
- bufferutil
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue