mirror of
https://github.com/sim1222/misskey.git
synced 2025-08-05 16:24:41 +09:00
test
This commit is contained in:
@ -15,7 +15,7 @@ let isSupportedCpu: undefined | boolean = undefined;
|
||||
|
||||
@Injectable()
|
||||
export class AiService {
|
||||
#model: nsfw.NSFWJS;
|
||||
private model: nsfw.NSFWJS;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
@ -26,7 +26,7 @@ export class AiService {
|
||||
public async detectSensitive(path: string): Promise<nsfw.predictionType[] | null> {
|
||||
try {
|
||||
if (isSupportedCpu === undefined) {
|
||||
const cpuFlags = await this.#getCpuFlags();
|
||||
const cpuFlags = await this.getCpuFlags();
|
||||
isSupportedCpu = REQUIRED_CPU_FLAGS.every(required => cpuFlags.includes(required));
|
||||
}
|
||||
|
||||
@ -37,12 +37,12 @@ export class AiService {
|
||||
|
||||
const tf = await import('@tensorflow/tfjs-node');
|
||||
|
||||
if (this.#model == null) this.#model = await nsfw.load(`file://${_dirname}/../../nsfw-model/`, { size: 299 });
|
||||
if (this.model == null) this.model = await nsfw.load(`file://${_dirname}/../../nsfw-model/`, { size: 299 });
|
||||
|
||||
const buffer = await fs.promises.readFile(path);
|
||||
const image = await tf.node.decodeImage(buffer, 3) as any;
|
||||
try {
|
||||
const predictions = await this.#model.classify(image);
|
||||
const predictions = await this.model.classify(image);
|
||||
return predictions;
|
||||
} finally {
|
||||
image.dispose();
|
||||
@ -53,7 +53,7 @@ export class AiService {
|
||||
}
|
||||
}
|
||||
|
||||
async #getCpuFlags(): Promise<string[]> {
|
||||
private async getCpuFlags(): Promise<string[]> {
|
||||
const str = await si.cpuFlags();
|
||||
return str.split(/\s+/);
|
||||
}
|
||||
|
@ -16,9 +16,9 @@ import type { OnApplicationShutdown } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class AntennaService implements OnApplicationShutdown {
|
||||
#antennasFetched: boolean;
|
||||
#antennas: Antenna[];
|
||||
#blockingCache: Cache<User['id'][]>;
|
||||
private antennasFetched: boolean;
|
||||
private antennas: Antenna[];
|
||||
private blockingCache: Cache<User['id'][]>;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.redisSubscriber)
|
||||
@ -49,9 +49,9 @@ export class AntennaService implements OnApplicationShutdown {
|
||||
private idService: IdService,
|
||||
private globalEventServie: GlobalEventService,
|
||||
) {
|
||||
this.#antennasFetched = false;
|
||||
this.#antennas = [];
|
||||
this.#blockingCache = new Cache<User['id'][]>(1000 * 60 * 5);
|
||||
this.antennasFetched = false;
|
||||
this.antennas = [];
|
||||
this.blockingCache = new Cache<User['id'][]>(1000 * 60 * 5);
|
||||
|
||||
this.redisSubscriber.on('message', this.onRedisMessage);
|
||||
}
|
||||
@ -67,13 +67,13 @@ export class AntennaService implements OnApplicationShutdown {
|
||||
const { type, body } = obj.message;
|
||||
switch (type) {
|
||||
case 'antennaCreated':
|
||||
this.#antennas.push(body);
|
||||
this.antennas.push(body);
|
||||
break;
|
||||
case 'antennaUpdated':
|
||||
this.#antennas[this.#antennas.findIndex(a => a.id === body.id)] = body;
|
||||
this.antennas[this.antennas.findIndex(a => a.id === body.id)] = body;
|
||||
break;
|
||||
case 'antennaDeleted':
|
||||
this.#antennas = this.#antennas.filter(a => a.id !== body.id);
|
||||
this.antennas = this.antennas.filter(a => a.id !== body.id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -137,7 +137,7 @@ export class AntennaService implements OnApplicationShutdown {
|
||||
if (note.visibility === 'specified') return false;
|
||||
|
||||
// アンテナ作成者がノート作成者にブロックされていたらスキップ
|
||||
const blockings = await this.#blockingCache.fetch(noteUser.id, () => this.blockingsRepository.findBy({ blockerId: noteUser.id }).then(res => res.map(x => x.blockeeId)));
|
||||
const blockings = await this.blockingCache.fetch(noteUser.id, () => this.blockingsRepository.findBy({ blockerId: noteUser.id }).then(res => res.map(x => x.blockeeId)));
|
||||
if (blockings.some(blocking => blocking === antenna.userId)) return false;
|
||||
|
||||
if (note.visibility === 'followers') {
|
||||
@ -218,11 +218,11 @@ export class AntennaService implements OnApplicationShutdown {
|
||||
}
|
||||
|
||||
public async getAntennas() {
|
||||
if (!this.#antennasFetched) {
|
||||
this.#antennas = await this.antennasRepository.find();
|
||||
this.#antennasFetched = true;
|
||||
if (!this.antennasFetched) {
|
||||
this.antennas = await this.antennasRepository.find();
|
||||
this.antennasFetched = true;
|
||||
}
|
||||
|
||||
return this.#antennas;
|
||||
return this.antennas;
|
||||
}
|
||||
}
|
||||
|
@ -11,13 +11,13 @@ const retryDelay = 100;
|
||||
|
||||
@Injectable()
|
||||
export class AppLockService {
|
||||
#lock: (key: string, timeout?: number) => Promise<() => void>;
|
||||
private lock: (key: string, timeout?: number) => Promise<() => void>;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.redis)
|
||||
private redisClient: Redis.Redis,
|
||||
) {
|
||||
this.#lock = promisify(redisLock(this.redisClient, retryDelay));
|
||||
this.lock = promisify(redisLock(this.redisClient, retryDelay));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -27,14 +27,14 @@ export class AppLockService {
|
||||
* @returns Unlock function
|
||||
*/
|
||||
public getApLock(uri: string, timeout = 30 * 1000): Promise<() => void> {
|
||||
return this.#lock(`ap-object:${uri}`, timeout);
|
||||
return this.lock(`ap-object:${uri}`, timeout);
|
||||
}
|
||||
|
||||
public getFetchInstanceMetadataLock(host: string, timeout = 30 * 1000): Promise<() => void> {
|
||||
return this.#lock(`instance:${host}`, timeout);
|
||||
return this.lock(`instance:${host}`, timeout);
|
||||
}
|
||||
|
||||
public getChartInsertLock(lockKey: string, timeout = 30 * 1000): Promise<() => void> {
|
||||
return this.#lock(`chart-insert:${lockKey}`, timeout);
|
||||
return this.lock(`chart-insert:${lockKey}`, timeout);
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ export class CaptchaService {
|
||||
) {
|
||||
}
|
||||
|
||||
async #getCaptchaResponse(url: string, secret: string, response: string): Promise<CaptchaResponse> {
|
||||
private async getCaptchaResponse(url: string, secret: string, response: string): Promise<CaptchaResponse> {
|
||||
const params = new URLSearchParams({
|
||||
secret,
|
||||
response,
|
||||
@ -46,7 +46,7 @@ export class CaptchaService {
|
||||
}
|
||||
|
||||
public async verifyRecaptcha(secret: string, response: string): Promise<void> {
|
||||
const result = await this.#getCaptchaResponse('https://www.recaptcha.net/recaptcha/api/siteverify', secret, response).catch(e => {
|
||||
const result = await this.getCaptchaResponse('https://www.recaptcha.net/recaptcha/api/siteverify', secret, response).catch(e => {
|
||||
throw `recaptcha-request-failed: ${e}`;
|
||||
});
|
||||
|
||||
@ -57,7 +57,7 @@ export class CaptchaService {
|
||||
}
|
||||
|
||||
public async verifyHcaptcha(secret: string, response: string): Promise<void> {
|
||||
const result = await this.#getCaptchaResponse('https://hcaptcha.com/siteverify', secret, response).catch(e => {
|
||||
const result = await this.getCaptchaResponse('https://hcaptcha.com/siteverify', secret, response).catch(e => {
|
||||
throw `hcaptcha-request-failed: ${e}`;
|
||||
});
|
||||
|
||||
|
@ -78,8 +78,8 @@ export class CreateNotificationService {
|
||||
this.globalEventServie.publishMainStream(notifieeId, 'unreadNotification', packed);
|
||||
this.pushNotificationService.pushNotification(notifieeId, 'notification', packed);
|
||||
|
||||
if (type === 'follow') this.#emailNotificationFollow(notifieeId, await this.usersRepository.findOneByOrFail({ id: data.notifierId! }));
|
||||
if (type === 'receiveFollowRequest') this.#emailNotificationReceiveFollowRequest(notifieeId, await this.usersRepository.findOneByOrFail({ id: data.notifierId! }));
|
||||
if (type === 'follow') this.emailNotificationFollow(notifieeId, await this.usersRepository.findOneByOrFail({ id: data.notifierId! }));
|
||||
if (type === 'receiveFollowRequest') this.emailNotificationReceiveFollowRequest(notifieeId, await this.usersRepository.findOneByOrFail({ id: data.notifierId! }));
|
||||
}, 2000);
|
||||
|
||||
return notification;
|
||||
@ -90,7 +90,7 @@ export class CreateNotificationService {
|
||||
|
||||
// TODO: locale ファイルをクライアント用とサーバー用で分けたい
|
||||
|
||||
async #emailNotificationFollow(userId: User['id'], follower: User) {
|
||||
private async emailNotificationFollow(userId: User['id'], follower: User) {
|
||||
/*
|
||||
const userProfile = await UserProfiles.findOneByOrFail({ userId: userId });
|
||||
if (!userProfile.email || !userProfile.emailNotificationTypes.includes('follow')) return;
|
||||
@ -101,7 +101,7 @@ export class CreateNotificationService {
|
||||
*/
|
||||
}
|
||||
|
||||
async #emailNotificationReceiveFollowRequest(userId: User['id'], follower: User) {
|
||||
private async emailNotificationReceiveFollowRequest(userId: User['id'], follower: User) {
|
||||
/*
|
||||
const userProfile = await UserProfiles.findOneByOrFail({ userId: userId });
|
||||
if (!userProfile.email || !userProfile.emailNotificationTypes.includes('receiveFollowRequest')) return;
|
||||
|
@ -23,7 +23,7 @@ type PopulatedEmoji = {
|
||||
|
||||
@Injectable()
|
||||
export class CustomEmojiService {
|
||||
#cache: Cache<Emoji | null>;
|
||||
private cache: Cache<Emoji | null>;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
@ -40,7 +40,7 @@ export class CustomEmojiService {
|
||||
private utilityService: UtilityService,
|
||||
private reactionService: ReactionService,
|
||||
) {
|
||||
this.#cache = new Cache<Emoji | null>(1000 * 60 * 60 * 12);
|
||||
this.cache = new Cache<Emoji | null>(1000 * 60 * 60 * 12);
|
||||
}
|
||||
|
||||
public async add(data: {
|
||||
@ -67,7 +67,7 @@ export class CustomEmojiService {
|
||||
return emoji;
|
||||
}
|
||||
|
||||
#normalizeHost(src: string | undefined, noteUserHost: string | null): string | null {
|
||||
private normalizeHost(src: string | undefined, noteUserHost: string | null): string | null {
|
||||
// クエリに使うホスト
|
||||
let host = src === '.' ? null // .はローカルホスト (ここがマッチするのはリアクションのみ)
|
||||
: src === undefined ? noteUserHost // ノートなどでホスト省略表記の場合はローカルホスト (ここがリアクションにマッチすることはない)
|
||||
@ -79,14 +79,14 @@ export class CustomEmojiService {
|
||||
return host;
|
||||
}
|
||||
|
||||
#parseEmojiStr(emojiName: string, noteUserHost: string | null) {
|
||||
private parseEmojiStr(emojiName: string, noteUserHost: string | null) {
|
||||
const match = emojiName.match(/^(\w+)(?:@([\w.-]+))?$/);
|
||||
if (!match) return { name: null, host: null };
|
||||
|
||||
const name = match[1];
|
||||
|
||||
// ホスト正規化
|
||||
const host = this.utilityService.toPunyNullable(this.#normalizeHost(match[2], noteUserHost));
|
||||
const host = this.utilityService.toPunyNullable(this.normalizeHost(match[2], noteUserHost));
|
||||
|
||||
return { name, host };
|
||||
}
|
||||
@ -98,7 +98,7 @@ export class CustomEmojiService {
|
||||
* @returns 絵文字情報, nullは未マッチを意味する
|
||||
*/
|
||||
public async populateEmoji(emojiName: string, noteUserHost: string | null): Promise<PopulatedEmoji | null> {
|
||||
const { name, host } = this.#parseEmojiStr(emojiName, noteUserHost);
|
||||
const { name, host } = this.parseEmojiStr(emojiName, noteUserHost);
|
||||
if (name == null) return null;
|
||||
|
||||
const queryOrNull = async () => (await this.emojisRepository.findOneBy({
|
||||
@ -106,7 +106,7 @@ export class CustomEmojiService {
|
||||
host: host ?? IsNull(),
|
||||
})) ?? null;
|
||||
|
||||
const emoji = await this.#cache.fetch(`${name} ${host}`, queryOrNull);
|
||||
const emoji = await this.cache.fetch(`${name} ${host}`, queryOrNull);
|
||||
|
||||
if (emoji == null) return null;
|
||||
|
||||
@ -132,20 +132,20 @@ export class CustomEmojiService {
|
||||
let emojis: { name: string | null; host: string | null; }[] = [];
|
||||
for (const note of notes) {
|
||||
emojis = emojis.concat(note.emojis
|
||||
.map(e => this.#parseEmojiStr(e, note.userHost)));
|
||||
.map(e => this.parseEmojiStr(e, note.userHost)));
|
||||
if (note.renote) {
|
||||
emojis = emojis.concat(note.renote.emojis
|
||||
.map(e => this.#parseEmojiStr(e, note.renote!.userHost)));
|
||||
.map(e => this.parseEmojiStr(e, note.renote!.userHost)));
|
||||
if (note.renote.user) {
|
||||
emojis = emojis.concat(note.renote.user.emojis
|
||||
.map(e => this.#parseEmojiStr(e, note.renote!.userHost)));
|
||||
.map(e => this.parseEmojiStr(e, note.renote!.userHost)));
|
||||
}
|
||||
}
|
||||
const customReactions = Object.keys(note.reactions).map(x => this.reactionService.decodeReaction(x)).filter(x => x.name != null) as typeof emojis;
|
||||
emojis = emojis.concat(customReactions);
|
||||
if (note.user) {
|
||||
emojis = emojis.concat(note.user.emojis
|
||||
.map(e => this.#parseEmojiStr(e, note.userHost)));
|
||||
.map(e => this.parseEmojiStr(e, note.userHost)));
|
||||
}
|
||||
}
|
||||
return emojis.filter(x => x.name != null) as { name: string; host: string | null; }[];
|
||||
@ -155,7 +155,7 @@ export class CustomEmojiService {
|
||||
* 与えられた絵文字のリストをデータベースから取得し、キャッシュに追加します
|
||||
*/
|
||||
public async prefetchEmojis(emojis: { name: string; host: string | null; }[]): Promise<void> {
|
||||
const notCachedEmojis = emojis.filter(emoji => this.#cache.get(`${emoji.name} ${emoji.host}`) == null);
|
||||
const notCachedEmojis = emojis.filter(emoji => this.cache.get(`${emoji.name} ${emoji.host}`) == null);
|
||||
const emojisQuery: any[] = [];
|
||||
const hosts = new Set(notCachedEmojis.map(e => e.host));
|
||||
for (const host of hosts) {
|
||||
@ -169,7 +169,7 @@ export class CustomEmojiService {
|
||||
select: ['name', 'host', 'originalUrl', 'publicUrl'],
|
||||
}) : [];
|
||||
for (const emoji of _emojis) {
|
||||
this.#cache.set(`${emoji.name} ${emoji.host}`, emoji);
|
||||
this.cache.set(`${emoji.name} ${emoji.host}`, emoji);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ const pipeline = util.promisify(stream.pipeline);
|
||||
|
||||
@Injectable()
|
||||
export class DownloadService {
|
||||
#logger: Logger;
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
@ -27,11 +27,11 @@ export class DownloadService {
|
||||
private httpRequestService: HttpRequestService,
|
||||
private loggerService: LoggerService,
|
||||
) {
|
||||
this.#logger = this.loggerService.getLogger('download');
|
||||
this.logger = this.loggerService.getLogger('download');
|
||||
}
|
||||
|
||||
public async downloadUrl(url: string, path: string): Promise<void> {
|
||||
this.#logger.info(`Downloading ${chalk.cyan(url)} ...`);
|
||||
this.logger.info(`Downloading ${chalk.cyan(url)} ...`);
|
||||
|
||||
const timeout = 30 * 1000;
|
||||
const operationTimeout = 60 * 1000;
|
||||
@ -60,8 +60,8 @@ export class DownloadService {
|
||||
},
|
||||
}).on('response', (res: Got.Response) => {
|
||||
if ((process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test') && !this.config.proxy && res.ip) {
|
||||
if (this.#isPrivateIp(res.ip)) {
|
||||
this.#logger.warn(`Blocked address: ${res.ip}`);
|
||||
if (this.isPrivateIp(res.ip)) {
|
||||
this.logger.warn(`Blocked address: ${res.ip}`);
|
||||
req.destroy();
|
||||
}
|
||||
}
|
||||
@ -70,13 +70,13 @@ export class DownloadService {
|
||||
if (contentLength != null) {
|
||||
const size = Number(contentLength);
|
||||
if (size > maxSize) {
|
||||
this.#logger.warn(`maxSize exceeded (${size} > ${maxSize}) on response`);
|
||||
this.logger.warn(`maxSize exceeded (${size} > ${maxSize}) on response`);
|
||||
req.destroy();
|
||||
}
|
||||
}
|
||||
}).on('downloadProgress', (progress: Got.Progress) => {
|
||||
if (progress.transferred > maxSize) {
|
||||
this.#logger.warn(`maxSize exceeded (${progress.transferred} > ${maxSize}) on downloadProgress`);
|
||||
this.logger.warn(`maxSize exceeded (${progress.transferred} > ${maxSize}) on downloadProgress`);
|
||||
req.destroy();
|
||||
}
|
||||
});
|
||||
@ -91,14 +91,14 @@ export class DownloadService {
|
||||
}
|
||||
}
|
||||
|
||||
this.#logger.succ(`Download finished: ${chalk.cyan(url)}`);
|
||||
this.logger.succ(`Download finished: ${chalk.cyan(url)}`);
|
||||
}
|
||||
|
||||
public async downloadTextFile(url: string): Promise<string> {
|
||||
// Create temp file
|
||||
const [path, cleanup] = await createTemp();
|
||||
|
||||
this.#logger.info(`text file: Temp file is ${path}`);
|
||||
this.logger.info(`text file: Temp file is ${path}`);
|
||||
|
||||
try {
|
||||
// write content at URL to temp file
|
||||
@ -112,7 +112,7 @@ export class DownloadService {
|
||||
}
|
||||
}
|
||||
|
||||
#isPrivateIp(ip: string): boolean {
|
||||
private isPrivateIp(ip: string): boolean {
|
||||
for (const net of this.config.allowedPrivateNetworks ?? []) {
|
||||
const cidr = new IPCIDR(net);
|
||||
if (cidr.contains(ip)) {
|
||||
|
@ -74,8 +74,8 @@ type UploadFromUrlArgs = {
|
||||
|
||||
@Injectable()
|
||||
export class DriveService {
|
||||
#registerLogger: Logger;
|
||||
#downloaderLogger: Logger;
|
||||
private registerLogger: Logger;
|
||||
private downloaderLogger: Logger;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
@ -110,8 +110,8 @@ export class DriveService {
|
||||
private instanceChart: InstanceChart,
|
||||
) {
|
||||
const logger = new Logger('drive', 'blue');
|
||||
this.#registerLogger = logger.createSubLogger('register', 'yellow');
|
||||
this.#downloaderLogger = logger.createSubLogger('downloader');
|
||||
this.registerLogger = logger.createSubLogger('register', 'yellow');
|
||||
this.downloaderLogger = logger.createSubLogger('downloader');
|
||||
}
|
||||
|
||||
/***
|
||||
@ -122,7 +122,7 @@ export class DriveService {
|
||||
* @param hash Hash for original
|
||||
* @param size Size for original
|
||||
*/
|
||||
async #save(file: DriveFile, path: string, name: string, type: string, hash: string, size: number): Promise<DriveFile> {
|
||||
private async save(file: DriveFile, path: string, name: string, type: string, hash: string, size: number): Promise<DriveFile> {
|
||||
// thunbnail, webpublic を必要なら生成
|
||||
const alts = await this.generateAlts(path, type, !file.uri);
|
||||
|
||||
@ -161,25 +161,25 @@ export class DriveService {
|
||||
//#endregion
|
||||
|
||||
//#region Uploads
|
||||
this.#registerLogger.info(`uploading original: ${key}`);
|
||||
this.registerLogger.info(`uploading original: ${key}`);
|
||||
const uploads = [
|
||||
this.#upload(key, fs.createReadStream(path), type, name),
|
||||
this.upload(key, fs.createReadStream(path), type, name),
|
||||
];
|
||||
|
||||
if (alts.webpublic) {
|
||||
webpublicKey = `${meta.objectStoragePrefix}/webpublic-${uuid()}.${alts.webpublic.ext}`;
|
||||
webpublicUrl = `${ baseUrl }/${ webpublicKey }`;
|
||||
|
||||
this.#registerLogger.info(`uploading webpublic: ${webpublicKey}`);
|
||||
uploads.push(this.#upload(webpublicKey, alts.webpublic.data, alts.webpublic.type, name));
|
||||
this.registerLogger.info(`uploading webpublic: ${webpublicKey}`);
|
||||
uploads.push(this.upload(webpublicKey, alts.webpublic.data, alts.webpublic.type, name));
|
||||
}
|
||||
|
||||
if (alts.thumbnail) {
|
||||
thumbnailKey = `${meta.objectStoragePrefix}/thumbnail-${uuid()}.${alts.thumbnail.ext}`;
|
||||
thumbnailUrl = `${ baseUrl }/${ thumbnailKey }`;
|
||||
|
||||
this.#registerLogger.info(`uploading thumbnail: ${thumbnailKey}`);
|
||||
uploads.push(this.#upload(thumbnailKey, alts.thumbnail.data, alts.thumbnail.type));
|
||||
this.registerLogger.info(`uploading thumbnail: ${thumbnailKey}`);
|
||||
uploads.push(this.upload(thumbnailKey, alts.thumbnail.data, alts.thumbnail.type));
|
||||
}
|
||||
|
||||
await Promise.all(uploads);
|
||||
@ -211,12 +211,12 @@ export class DriveService {
|
||||
|
||||
if (alts.thumbnail) {
|
||||
thumbnailUrl = this.internalStorageService.saveFromBuffer(thumbnailAccessKey, alts.thumbnail.data);
|
||||
this.#registerLogger.info(`thumbnail stored: ${thumbnailAccessKey}`);
|
||||
this.registerLogger.info(`thumbnail stored: ${thumbnailAccessKey}`);
|
||||
}
|
||||
|
||||
if (alts.webpublic) {
|
||||
webpublicUrl = this.internalStorageService.saveFromBuffer(webpublicAccessKey, alts.webpublic.data);
|
||||
this.#registerLogger.info(`web stored: ${webpublicAccessKey}`);
|
||||
this.registerLogger.info(`web stored: ${webpublicAccessKey}`);
|
||||
}
|
||||
|
||||
file.storedInternal = true;
|
||||
@ -251,7 +251,7 @@ export class DriveService {
|
||||
thumbnail,
|
||||
};
|
||||
} catch (err) {
|
||||
this.#registerLogger.warn(`GenerateVideoThumbnail failed: ${err}`);
|
||||
this.registerLogger.warn(`GenerateVideoThumbnail failed: ${err}`);
|
||||
return {
|
||||
webpublic: null,
|
||||
thumbnail: null,
|
||||
@ -260,7 +260,7 @@ export class DriveService {
|
||||
}
|
||||
|
||||
if (!['image/jpeg', 'image/png', 'image/webp', 'image/svg+xml'].includes(type)) {
|
||||
this.#registerLogger.debug('web image and thumbnail not created (not an required file)');
|
||||
this.registerLogger.debug('web image and thumbnail not created (not an required file)');
|
||||
return {
|
||||
webpublic: null,
|
||||
thumbnail: null,
|
||||
@ -290,7 +290,7 @@ export class DriveService {
|
||||
metadata.height && metadata.height <= 2048
|
||||
);
|
||||
} catch (err) {
|
||||
this.#registerLogger.warn(`sharp failed: ${err}`);
|
||||
this.registerLogger.warn(`sharp failed: ${err}`);
|
||||
return {
|
||||
webpublic: null,
|
||||
thumbnail: null,
|
||||
@ -301,7 +301,7 @@ export class DriveService {
|
||||
let webpublic: IImage | null = null;
|
||||
|
||||
if (generateWeb && !satisfyWebpublic) {
|
||||
this.#registerLogger.info('creating web image');
|
||||
this.registerLogger.info('creating web image');
|
||||
|
||||
try {
|
||||
if (['image/jpeg', 'image/webp'].includes(type)) {
|
||||
@ -311,14 +311,14 @@ export class DriveService {
|
||||
} else if (['image/svg+xml'].includes(type)) {
|
||||
webpublic = await this.imageProcessingService.convertSharpToPng(img, 2048, 2048);
|
||||
} else {
|
||||
this.#registerLogger.debug('web image not created (not an required image)');
|
||||
this.registerLogger.debug('web image not created (not an required image)');
|
||||
}
|
||||
} catch (err) {
|
||||
this.#registerLogger.warn('web image not created (an error occured)', err as Error);
|
||||
this.registerLogger.warn('web image not created (an error occured)', err as Error);
|
||||
}
|
||||
} else {
|
||||
if (satisfyWebpublic) this.#registerLogger.info('web image not created (original satisfies webpublic)');
|
||||
else this.#registerLogger.info('web image not created (from remote)');
|
||||
if (satisfyWebpublic) this.registerLogger.info('web image not created (original satisfies webpublic)');
|
||||
else this.registerLogger.info('web image not created (from remote)');
|
||||
}
|
||||
// #endregion webpublic
|
||||
|
||||
@ -329,10 +329,10 @@ export class DriveService {
|
||||
if (['image/jpeg', 'image/webp', 'image/png', 'image/svg+xml'].includes(type)) {
|
||||
thumbnail = await this.imageProcessingService.convertSharpToWebp(img, 498, 280);
|
||||
} else {
|
||||
this.#registerLogger.debug('thumbnail not created (not an required file)');
|
||||
this.registerLogger.debug('thumbnail not created (not an required file)');
|
||||
}
|
||||
} catch (err) {
|
||||
this.#registerLogger.warn('thumbnail not created (an error occured)', err as Error);
|
||||
this.registerLogger.warn('thumbnail not created (an error occured)', err as Error);
|
||||
}
|
||||
// #endregion thumbnail
|
||||
|
||||
@ -345,7 +345,7 @@ export class DriveService {
|
||||
/**
|
||||
* Upload to ObjectStorage
|
||||
*/
|
||||
async #upload(key: string, stream: fs.ReadStream | Buffer, type: string, filename?: string) {
|
||||
private async upload(key: string, stream: fs.ReadStream | Buffer, type: string, filename?: string) {
|
||||
if (type === 'image/apng') type = 'image/png';
|
||||
if (!FILE_TYPE_BROWSERSAFE.includes(type)) type = 'application/octet-stream';
|
||||
|
||||
@ -369,10 +369,10 @@ export class DriveService {
|
||||
});
|
||||
|
||||
const result = await upload.promise();
|
||||
if (result) this.#registerLogger.debug(`Uploaded: ${result.Bucket}/${result.Key} => ${result.Location}`);
|
||||
if (result) this.registerLogger.debug(`Uploaded: ${result.Bucket}/${result.Key} => ${result.Location}`);
|
||||
}
|
||||
|
||||
async #deleteOldFile(user: IRemoteUser) {
|
||||
private async deleteOldFile(user: IRemoteUser) {
|
||||
const q = this.driveFilesRepository.createQueryBuilder('file')
|
||||
.where('file.userId = :userId', { userId: user.id })
|
||||
.andWhere('file.isLink = FALSE');
|
||||
@ -430,7 +430,7 @@ export class DriveService {
|
||||
sensitiveThresholdForPorn: 0.75,
|
||||
enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos,
|
||||
});
|
||||
this.#registerLogger.info(`${JSON.stringify(info)}`);
|
||||
this.registerLogger.info(`${JSON.stringify(info)}`);
|
||||
|
||||
// 現状 false positive が多すぎて実用に耐えない
|
||||
//if (info.porn && instance.disallowUploadWhenPredictedAsPorn) {
|
||||
@ -448,7 +448,7 @@ export class DriveService {
|
||||
});
|
||||
|
||||
if (much) {
|
||||
this.#registerLogger.info(`file with same hash is found: ${much.id}`);
|
||||
this.registerLogger.info(`file with same hash is found: ${much.id}`);
|
||||
return much;
|
||||
}
|
||||
}
|
||||
@ -463,11 +463,11 @@ export class DriveService {
|
||||
|
||||
if (this.userEntityService.isLocalUser(user) && u?.driveCapacityOverrideMb != null) {
|
||||
driveCapacity = 1024 * 1024 * u.driveCapacityOverrideMb;
|
||||
this.#registerLogger.debug('drive capacity override applied');
|
||||
this.#registerLogger.debug(`overrideCap: ${driveCapacity}bytes, usage: ${usage}bytes, u+s: ${usage + info.size}bytes`);
|
||||
this.registerLogger.debug('drive capacity override applied');
|
||||
this.registerLogger.debug(`overrideCap: ${driveCapacity}bytes, usage: ${usage}bytes, u+s: ${usage + info.size}bytes`);
|
||||
}
|
||||
|
||||
this.#registerLogger.debug(`drive usage is ${usage} (max: ${driveCapacity})`);
|
||||
this.registerLogger.debug(`drive usage is ${usage} (max: ${driveCapacity})`);
|
||||
|
||||
// If usage limit exceeded
|
||||
if (usage + info.size > driveCapacity) {
|
||||
@ -475,7 +475,7 @@ export class DriveService {
|
||||
throw new IdentifiableError('c6244ed2-a39a-4e1c-bf93-f0fbd7764fa6', 'No free space.');
|
||||
} else {
|
||||
// (アバターまたはバナーを含まず)最も古いファイルを削除する
|
||||
this.#deleteOldFile(await this.usersRepository.findOneByOrFail({ id: user.id }) as IRemoteUser);
|
||||
this.deleteOldFile(await this.usersRepository.findOneByOrFail({ id: user.id }) as IRemoteUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -566,22 +566,22 @@ export class DriveService {
|
||||
} catch (err) {
|
||||
// duplicate key error (when already registered)
|
||||
if (isDuplicateKeyValueError(err)) {
|
||||
this.#registerLogger.info(`already registered ${file.uri}`);
|
||||
this.registerLogger.info(`already registered ${file.uri}`);
|
||||
|
||||
file = await this.driveFilesRepository.findOneBy({
|
||||
uri: file.uri!,
|
||||
userId: user ? user.id : IsNull(),
|
||||
}) as DriveFile;
|
||||
} else {
|
||||
this.#registerLogger.error(err as Error);
|
||||
this.registerLogger.error(err as Error);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
file = await (this.#save(file, path, detectedName, info.type.mime, info.md5, info.size));
|
||||
file = await (this.save(file, path, detectedName, info.type.mime, info.md5, info.size));
|
||||
}
|
||||
|
||||
this.#registerLogger.succ(`drive file has been created ${file.id}`);
|
||||
this.registerLogger.succ(`drive file has been created ${file.id}`);
|
||||
|
||||
if (user) {
|
||||
this.driveFileEntityService.pack(file, { self: true }).then(packedFile => {
|
||||
@ -624,7 +624,7 @@ export class DriveService {
|
||||
}
|
||||
}
|
||||
|
||||
this.#deletePostProcess(file, isExpired);
|
||||
this.deletePostProcess(file, isExpired);
|
||||
}
|
||||
|
||||
public async deleteFileSync(file: DriveFile, isExpired = false) {
|
||||
@ -654,10 +654,10 @@ export class DriveService {
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
this.#deletePostProcess(file, isExpired);
|
||||
this.deletePostProcess(file, isExpired);
|
||||
}
|
||||
|
||||
async #deletePostProcess(file: DriveFile, isExpired = false) {
|
||||
private async deletePostProcess(file: DriveFile, isExpired = false) {
|
||||
// リモートファイル期限切れ削除後は直リンクにする
|
||||
if (isExpired && file.userHost !== null && file.uri != null) {
|
||||
this.driveFilesRepository.update(file.id, {
|
||||
@ -725,10 +725,10 @@ export class DriveService {
|
||||
await this.downloadService.downloadUrl(url, path);
|
||||
|
||||
const driveFile = await this.addFile({ user, path, name, comment, folderId, force, isLink, url, uri, sensitive, requestIp, requestHeaders });
|
||||
this.#downloaderLogger.succ(`Got: ${driveFile.id}`);
|
||||
this.downloaderLogger.succ(`Got: ${driveFile.id}`);
|
||||
return driveFile!;
|
||||
} catch (err) {
|
||||
this.#downloaderLogger.error(`Failed to create drive file: ${err}`, {
|
||||
this.downloaderLogger.error(`Failed to create drive file: ${err}`, {
|
||||
url: url,
|
||||
e: err,
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ import { LoggerService } from '@/core/LoggerService.js';
|
||||
|
||||
@Injectable()
|
||||
export class EmailService {
|
||||
#logger: Logger;
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
@ -22,7 +22,7 @@ export class EmailService {
|
||||
private metaService: MetaService,
|
||||
private loggerService: LoggerService,
|
||||
) {
|
||||
this.#logger = this.loggerService.getLogger('email');
|
||||
this.logger = this.loggerService.getLogger('email');
|
||||
}
|
||||
|
||||
public async sendEmail(to: string, subject: string, html: string, text: string) {
|
||||
@ -134,9 +134,9 @@ export class EmailService {
|
||||
</html>`,
|
||||
});
|
||||
|
||||
this.#logger.info(`Message sent: ${info.messageId}`);
|
||||
this.logger.info(`Message sent: ${info.messageId}`);
|
||||
} catch (err) {
|
||||
this.#logger.error(err as Error);
|
||||
this.logger.error(err as Error);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import { UtilityService } from './UtilityService.js';
|
||||
|
||||
@Injectable()
|
||||
export class FederatedInstanceService {
|
||||
#cache: Cache<Instance>;
|
||||
private cache: Cache<Instance>;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.instancesRepository)
|
||||
@ -17,13 +17,13 @@ export class FederatedInstanceService {
|
||||
private utilityService: UtilityService,
|
||||
private idService: IdService,
|
||||
) {
|
||||
this.#cache = new Cache<Instance>(1000 * 60 * 60);
|
||||
this.cache = new Cache<Instance>(1000 * 60 * 60);
|
||||
}
|
||||
|
||||
public async registerOrFetchInstanceDoc(host: string): Promise<Instance> {
|
||||
host = this.utilityService.toPuny(host);
|
||||
|
||||
const cached = this.#cache.get(host);
|
||||
const cached = this.cache.get(host);
|
||||
if (cached) return cached;
|
||||
|
||||
const index = await this.instancesRepository.findOneBy({ host });
|
||||
@ -36,10 +36,10 @@ export class FederatedInstanceService {
|
||||
lastCommunicatedAt: new Date(),
|
||||
}).then(x => this.instancesRepository.findOneByOrFail(x.identifiers[0]));
|
||||
|
||||
this.#cache.set(host, i);
|
||||
this.cache.set(host, i);
|
||||
return i;
|
||||
} else {
|
||||
this.#cache.set(host, index);
|
||||
this.cache.set(host, index);
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ type NodeInfo = {
|
||||
|
||||
@Injectable()
|
||||
export class FetchInstanceMetadataService {
|
||||
#logger: Logger;
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.instancesRepository)
|
||||
@ -42,7 +42,7 @@ export class FetchInstanceMetadataService {
|
||||
private httpRequestService: HttpRequestService,
|
||||
private loggerService: LoggerService,
|
||||
) {
|
||||
this.#logger = this.loggerService.getLogger('metadata', 'cyan');
|
||||
this.logger = this.loggerService.getLogger('metadata', 'cyan');
|
||||
}
|
||||
|
||||
public async fetchInstanceMetadata(instance: Instance, force = false): Promise<void> {
|
||||
@ -57,24 +57,24 @@ export class FetchInstanceMetadataService {
|
||||
}
|
||||
}
|
||||
|
||||
this.#logger.info(`Fetching metadata of ${instance.host} ...`);
|
||||
this.logger.info(`Fetching metadata of ${instance.host} ...`);
|
||||
|
||||
try {
|
||||
const [info, dom, manifest] = await Promise.all([
|
||||
this.#fetchNodeinfo(instance).catch(() => null),
|
||||
this.#fetchDom(instance).catch(() => null),
|
||||
this.#fetchManifest(instance).catch(() => null),
|
||||
this.fetchNodeinfo(instance).catch(() => null),
|
||||
this.fetchDom(instance).catch(() => null),
|
||||
this.fetchManifest(instance).catch(() => null),
|
||||
]);
|
||||
|
||||
const [favicon, icon, themeColor, name, description] = await Promise.all([
|
||||
this.#fetchFaviconUrl(instance, dom).catch(() => null),
|
||||
this.#fetchIconUrl(instance, dom, manifest).catch(() => null),
|
||||
this.#getThemeColor(info, dom, manifest).catch(() => null),
|
||||
this.#getSiteName(info, dom, manifest).catch(() => null),
|
||||
this.#getDescription(info, dom, manifest).catch(() => null),
|
||||
this.fetchFaviconUrl(instance, dom).catch(() => null),
|
||||
this.fetchIconUrl(instance, dom, manifest).catch(() => null),
|
||||
this.getThemeColor(info, dom, manifest).catch(() => null),
|
||||
this.getSiteName(info, dom, manifest).catch(() => null),
|
||||
this.getDescription(info, dom, manifest).catch(() => null),
|
||||
]);
|
||||
|
||||
this.#logger.succ(`Successfuly fetched metadata of ${instance.host}`);
|
||||
this.logger.succ(`Successfuly fetched metadata of ${instance.host}`);
|
||||
|
||||
const updates = {
|
||||
infoUpdatedAt: new Date(),
|
||||
@ -96,16 +96,16 @@ export class FetchInstanceMetadataService {
|
||||
|
||||
await this.instancesRepository.update(instance.id, updates);
|
||||
|
||||
this.#logger.succ(`Successfuly updated metadata of ${instance.host}`);
|
||||
this.logger.succ(`Successfuly updated metadata of ${instance.host}`);
|
||||
} catch (e) {
|
||||
this.#logger.error(`Failed to update metadata of ${instance.host}: ${e}`);
|
||||
this.logger.error(`Failed to update metadata of ${instance.host}: ${e}`);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
async #fetchNodeinfo(instance: Instance): Promise<NodeInfo> {
|
||||
this.#logger.info(`Fetching nodeinfo of ${instance.host} ...`);
|
||||
private async fetchNodeinfo(instance: Instance): Promise<NodeInfo> {
|
||||
this.logger.info(`Fetching nodeinfo of ${instance.host} ...`);
|
||||
|
||||
try {
|
||||
const wellknown = await this.httpRequestService.getJson('https://' + instance.host + '/.well-known/nodeinfo')
|
||||
@ -137,18 +137,18 @@ export class FetchInstanceMetadataService {
|
||||
throw err.statusCode ?? err.message;
|
||||
});
|
||||
|
||||
this.#logger.succ(`Successfuly fetched nodeinfo of ${instance.host}`);
|
||||
this.logger.succ(`Successfuly fetched nodeinfo of ${instance.host}`);
|
||||
|
||||
return info as NodeInfo;
|
||||
} catch (err) {
|
||||
this.#logger.error(`Failed to fetch nodeinfo of ${instance.host}: ${err}`);
|
||||
this.logger.error(`Failed to fetch nodeinfo of ${instance.host}: ${err}`);
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async #fetchDom(instance: Instance): Promise<DOMWindow['document']> {
|
||||
this.#logger.info(`Fetching HTML of ${instance.host} ...`);
|
||||
private async fetchDom(instance: Instance): Promise<DOMWindow['document']> {
|
||||
this.logger.info(`Fetching HTML of ${instance.host} ...`);
|
||||
|
||||
const url = 'https://' + instance.host;
|
||||
|
||||
@ -160,7 +160,7 @@ export class FetchInstanceMetadataService {
|
||||
return doc;
|
||||
}
|
||||
|
||||
async #fetchManifest(instance: Instance): Promise<Record<string, unknown> | null> {
|
||||
private async fetchManifest(instance: Instance): Promise<Record<string, unknown> | null> {
|
||||
const url = 'https://' + instance.host;
|
||||
|
||||
const manifestUrl = url + '/manifest.json';
|
||||
@ -170,7 +170,7 @@ export class FetchInstanceMetadataService {
|
||||
return manifest;
|
||||
}
|
||||
|
||||
async #fetchFaviconUrl(instance: Instance, doc: DOMWindow['document'] | null): Promise<string | null> {
|
||||
private async fetchFaviconUrl(instance: Instance, doc: DOMWindow['document'] | null): Promise<string | null> {
|
||||
const url = 'https://' + instance.host;
|
||||
|
||||
if (doc) {
|
||||
@ -197,7 +197,7 @@ export class FetchInstanceMetadataService {
|
||||
return null;
|
||||
}
|
||||
|
||||
async #fetchIconUrl(instance: Instance, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
||||
private async fetchIconUrl(instance: Instance, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
||||
if (manifest && manifest.icons && manifest.icons.length > 0 && manifest.icons[0].src) {
|
||||
const url = 'https://' + instance.host;
|
||||
return (new URL(manifest.icons[0].src, url)).href;
|
||||
@ -225,7 +225,7 @@ export class FetchInstanceMetadataService {
|
||||
return null;
|
||||
}
|
||||
|
||||
async #getThemeColor(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
||||
private async getThemeColor(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
||||
const themeColor = info?.metadata?.themeColor ?? doc?.querySelector('meta[name="theme-color"]')?.getAttribute('content') ?? manifest?.theme_color;
|
||||
|
||||
if (themeColor) {
|
||||
@ -236,7 +236,7 @@ export class FetchInstanceMetadataService {
|
||||
return null;
|
||||
}
|
||||
|
||||
async #getSiteName(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
||||
private async getSiteName(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
||||
if (info && info.metadata) {
|
||||
if (info.metadata.nodeName || info.metadata.name) {
|
||||
return info.metadata.nodeName ?? info.metadata.name;
|
||||
@ -258,7 +258,7 @@ export class FetchInstanceMetadataService {
|
||||
return null;
|
||||
}
|
||||
|
||||
async #getDescription(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
||||
private async getDescription(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
||||
if (info && info.metadata) {
|
||||
if (info.metadata.nodeDescription || info.metadata.description) {
|
||||
return info.metadata.nodeDescription ?? info.metadata.description;
|
||||
|
@ -61,7 +61,7 @@ export class FileInfoService {
|
||||
const warnings = [] as string[];
|
||||
|
||||
const size = await this.getFileSize(path);
|
||||
const md5 = await this.#calcHash(path);
|
||||
const md5 = await this.calcHash(path);
|
||||
|
||||
let type = await this.detectType(path);
|
||||
|
||||
@ -71,7 +71,7 @@ export class FileInfoService {
|
||||
let orientation: number | undefined;
|
||||
|
||||
if (['image/jpeg', 'image/gif', 'image/png', 'image/apng', 'image/webp', 'image/bmp', 'image/tiff', 'image/svg+xml', 'image/vnd.adobe.photoshop'].includes(type.mime)) {
|
||||
const imageSize = await this.#detectImageSize(path).catch(e => {
|
||||
const imageSize = await this.detectImageSize(path).catch(e => {
|
||||
warnings.push(`detectImageSize failed: ${e}`);
|
||||
return undefined;
|
||||
});
|
||||
@ -98,7 +98,7 @@ export class FileInfoService {
|
||||
let blurhash: string | undefined;
|
||||
|
||||
if (['image/jpeg', 'image/gif', 'image/png', 'image/apng', 'image/webp', 'image/svg+xml'].includes(type.mime)) {
|
||||
blurhash = await this.#getBlurhash(path).catch(e => {
|
||||
blurhash = await this.getBlurhash(path).catch(e => {
|
||||
warnings.push(`getBlurhash failed: ${e}`);
|
||||
return undefined;
|
||||
});
|
||||
@ -108,7 +108,7 @@ export class FileInfoService {
|
||||
let porn = false;
|
||||
|
||||
if (!opts.skipSensitiveDetection) {
|
||||
await this.#detectSensitivity(
|
||||
await this.detectSensitivity(
|
||||
path,
|
||||
type.mime,
|
||||
opts.sensitiveThreshold ?? 0.5,
|
||||
@ -135,7 +135,7 @@ export class FileInfoService {
|
||||
};
|
||||
}
|
||||
|
||||
async #detectSensitivity(source: string, mime: string, sensitiveThreshold: number, sensitiveThresholdForPorn: number, analyzeVideo: boolean): Promise<[sensitive: boolean, porn: boolean]> {
|
||||
private async detectSensitivity(source: string, mime: string, sensitiveThreshold: number, sensitiveThresholdForPorn: number, analyzeVideo: boolean): Promise<[sensitive: boolean, porn: boolean]> {
|
||||
let sensitive = false;
|
||||
let porn = false;
|
||||
|
||||
@ -204,7 +204,7 @@ export class FileInfoService {
|
||||
let frameIndex = 0;
|
||||
let targetIndex = 0;
|
||||
let nextIndex = 1;
|
||||
for await (const path of this.#asyncIterateFrames(outDir, command)) {
|
||||
for await (const path of this.asyncIterateFrames(outDir, command)) {
|
||||
try {
|
||||
const index = frameIndex++;
|
||||
if (index !== targetIndex) {
|
||||
@ -230,7 +230,7 @@ export class FileInfoService {
|
||||
return [sensitive, porn];
|
||||
}
|
||||
|
||||
async *#asyncIterateFrames(cwd: string, command: FFmpeg.FfmpegCommand): AsyncGenerator<string, void> {
|
||||
private async *asyncIterateFrames(cwd: string, command: FFmpeg.FfmpegCommand): AsyncGenerator<string, void> {
|
||||
const watcher = new FSWatcher({
|
||||
cwd,
|
||||
disableGlobbing: true,
|
||||
@ -245,7 +245,7 @@ export class FileInfoService {
|
||||
const current = `${i}.png`;
|
||||
const next = `${i + 1}.png`;
|
||||
const framePath = join(cwd, current);
|
||||
if (await this.#exists(join(cwd, next))) {
|
||||
if (await this.exists(join(cwd, next))) {
|
||||
yield framePath;
|
||||
} else if (!finished) { // eslint-disable-line @typescript-eslint/no-unnecessary-condition
|
||||
watcher.add(next);
|
||||
@ -261,7 +261,7 @@ export class FileInfoService {
|
||||
command.once('error', reject);
|
||||
});
|
||||
yield framePath;
|
||||
} else if (await this.#exists(framePath)) {
|
||||
} else if (await this.exists(framePath)) {
|
||||
yield framePath;
|
||||
} else {
|
||||
return;
|
||||
@ -269,7 +269,7 @@ export class FileInfoService {
|
||||
}
|
||||
}
|
||||
|
||||
#exists(path: string): Promise<boolean> {
|
||||
private exists(path: string): Promise<boolean> {
|
||||
return fs.promises.access(path).then(() => true, () => false);
|
||||
}
|
||||
|
||||
@ -333,7 +333,7 @@ export class FileInfoService {
|
||||
/**
|
||||
* Calculate MD5 hash
|
||||
*/
|
||||
async #calcHash(path: string): Promise<string> {
|
||||
private async calcHash(path: string): Promise<string> {
|
||||
const hash = crypto.createHash('md5').setEncoding('hex');
|
||||
await pipeline(fs.createReadStream(path), hash);
|
||||
return hash.read();
|
||||
@ -342,7 +342,7 @@ export class FileInfoService {
|
||||
/**
|
||||
* Detect dimensions of image
|
||||
*/
|
||||
async #detectImageSize(path: string): Promise<{
|
||||
private async detectImageSize(path: string): Promise<{
|
||||
width: number;
|
||||
height: number;
|
||||
wUnits: string;
|
||||
@ -358,7 +358,7 @@ export class FileInfoService {
|
||||
/**
|
||||
* Calculate average color of image
|
||||
*/
|
||||
#getBlurhash(path: string): Promise<string> {
|
||||
private getBlurhash(path: string): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
sharp(path)
|
||||
.raw()
|
||||
|
@ -15,12 +15,12 @@ export class HttpRequestService {
|
||||
/**
|
||||
* Get http non-proxy agent
|
||||
*/
|
||||
#http: http.Agent;
|
||||
private http: http.Agent;
|
||||
|
||||
/**
|
||||
* Get https non-proxy agent
|
||||
*/
|
||||
#https: https.Agent;
|
||||
private https: https.Agent;
|
||||
|
||||
/**
|
||||
* Get http proxy or non-proxy agent
|
||||
@ -42,13 +42,13 @@ export class HttpRequestService {
|
||||
lookup: false, // nativeのdns.lookupにfallbackしない
|
||||
});
|
||||
|
||||
this.#http = new http.Agent({
|
||||
this.http = new http.Agent({
|
||||
keepAlive: true,
|
||||
keepAliveMsecs: 30 * 1000,
|
||||
lookup: cache.lookup,
|
||||
} as http.AgentOptions);
|
||||
|
||||
this.#https = new https.Agent({
|
||||
this.https = new https.Agent({
|
||||
keepAlive: true,
|
||||
keepAliveMsecs: 30 * 1000,
|
||||
lookup: cache.lookup,
|
||||
@ -65,7 +65,7 @@ export class HttpRequestService {
|
||||
scheduling: 'lifo',
|
||||
proxy: config.proxy,
|
||||
})
|
||||
: this.#http;
|
||||
: this.http;
|
||||
|
||||
this.httpsAgent = config.proxy
|
||||
? new HttpsProxyAgent({
|
||||
@ -76,7 +76,7 @@ export class HttpRequestService {
|
||||
scheduling: 'lifo',
|
||||
proxy: config.proxy,
|
||||
})
|
||||
: this.#https;
|
||||
: this.https;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,7 +86,7 @@ export class HttpRequestService {
|
||||
*/
|
||||
public getAgentByUrl(url: URL, bypassProxy = false): http.Agent | https.Agent {
|
||||
if (bypassProxy || (this.config.proxyBypassHosts || []).includes(url.hostname)) {
|
||||
return url.protocol === 'http:' ? this.#http : this.#https;
|
||||
return url.protocol === 'http:' ? this.http : this.https;
|
||||
} else {
|
||||
return url.protocol === 'http:' ? this.httpAgent : this.httpsAgent;
|
||||
}
|
||||
|
@ -9,19 +9,19 @@ import { genObjectId } from '@/misc/id/object-id.js';
|
||||
|
||||
@Injectable()
|
||||
export class IdService {
|
||||
#metohd: string;
|
||||
private metohd: string;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
) {
|
||||
this.#metohd = config.id.toLowerCase();
|
||||
this.metohd = config.id.toLowerCase();
|
||||
}
|
||||
|
||||
public genId(date?: Date): string {
|
||||
if (!date || (date > new Date())) date = new Date();
|
||||
|
||||
switch (this.#metohd) {
|
||||
switch (this.metohd) {
|
||||
case 'aid': return genAid(date);
|
||||
case 'meid': return genMeid(date);
|
||||
case 'meidg': return genMeidg(date);
|
||||
|
@ -10,7 +10,7 @@ const ACTOR_USERNAME = 'instance.actor' as const;
|
||||
|
||||
@Injectable()
|
||||
export class InstanceActorService {
|
||||
#cache: Cache<ILocalUser>;
|
||||
private cache: Cache<ILocalUser>;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.usersRepository)
|
||||
@ -18,11 +18,11 @@ export class InstanceActorService {
|
||||
|
||||
private createSystemUserService: CreateSystemUserService,
|
||||
) {
|
||||
this.#cache = new Cache<ILocalUser>(Infinity);
|
||||
this.cache = new Cache<ILocalUser>(Infinity);
|
||||
}
|
||||
|
||||
public async getInstanceActor(): Promise<ILocalUser> {
|
||||
const cached = this.#cache.get(null);
|
||||
const cached = this.cache.get(null);
|
||||
if (cached) return cached;
|
||||
|
||||
const user = await this.usersRepository.findOneBy({
|
||||
@ -31,11 +31,11 @@ export class InstanceActorService {
|
||||
}) as ILocalUser | undefined;
|
||||
|
||||
if (user) {
|
||||
this.#cache.set(null, user);
|
||||
this.cache.set(null, user);
|
||||
return user;
|
||||
} else {
|
||||
const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME) as ILocalUser;
|
||||
this.#cache.set(null, created);
|
||||
this.cache.set(null, created);
|
||||
return created;
|
||||
}
|
||||
}
|
||||
|
@ -6,14 +6,14 @@ import Logger from '@/logger.js';
|
||||
|
||||
@Injectable()
|
||||
export class LoggerService {
|
||||
#syslogClient;
|
||||
private syslogClient;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
) {
|
||||
if (this.config.syslog) {
|
||||
this.#syslogClient = new SyslogPro.RFC5424({
|
||||
this.syslogClient = new SyslogPro.RFC5424({
|
||||
applacationName: 'Misskey',
|
||||
timestamp: true,
|
||||
encludeStructuredData: true,
|
||||
@ -28,6 +28,6 @@ export class LoggerService {
|
||||
}
|
||||
|
||||
public getLogger(domain: string, color?: string | undefined, store?: boolean) {
|
||||
return new Logger(domain, color, store, this.#syslogClient);
|
||||
return new Logger(domain, color, store, this.syslogClient);
|
||||
}
|
||||
}
|
||||
|
@ -142,10 +142,10 @@ export class MessagingService {
|
||||
|
||||
public async deleteMessage(message: MessagingMessage) {
|
||||
await this.messagingMessagesRepository.delete(message.id);
|
||||
this.#postDeleteMessage(message);
|
||||
this.postDeleteMessage(message);
|
||||
}
|
||||
|
||||
async #postDeleteMessage(message: MessagingMessage) {
|
||||
private async postDeleteMessage(message: MessagingMessage) {
|
||||
if (message.recipientId) {
|
||||
const user = await this.usersRepository.findOneByOrFail({ id: message.userId });
|
||||
const recipient = await this.usersRepository.findOneByOrFail({ id: message.recipientId });
|
||||
|
@ -7,24 +7,24 @@ import type { OnApplicationShutdown } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class MetaService implements OnApplicationShutdown {
|
||||
#cache: Meta | undefined;
|
||||
#intervalId: NodeJS.Timer;
|
||||
private cache: Meta | undefined;
|
||||
private intervalId: NodeJS.Timer;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.db)
|
||||
private db: DataSource,
|
||||
) {
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
this.#intervalId = setInterval(() => {
|
||||
this.intervalId = setInterval(() => {
|
||||
this.fetch(true).then(meta => {
|
||||
this.#cache = meta;
|
||||
this.cache = meta;
|
||||
});
|
||||
}, 1000 * 10);
|
||||
}
|
||||
}
|
||||
|
||||
async fetch(noCache = false): Promise<Meta> {
|
||||
if (!noCache && this.#cache) return this.#cache;
|
||||
if (!noCache && this.cache) return this.cache;
|
||||
|
||||
return await this.db.transaction(async transactionalEntityManager => {
|
||||
// 過去のバグでレコードが複数出来てしまっている可能性があるので新しいIDを優先する
|
||||
@ -37,7 +37,7 @@ export class MetaService implements OnApplicationShutdown {
|
||||
const meta = metas[0];
|
||||
|
||||
if (meta) {
|
||||
this.#cache = meta;
|
||||
this.cache = meta;
|
||||
return meta;
|
||||
} else {
|
||||
// metaが空のときfetchMetaが同時に呼ばれるとここが同時に呼ばれてしまうことがあるのでフェイルセーフなupsertを使う
|
||||
@ -51,13 +51,13 @@ export class MetaService implements OnApplicationShutdown {
|
||||
)
|
||||
.then((x) => transactionalEntityManager.findOneByOrFail(Meta, x.identifiers[0]));
|
||||
|
||||
this.#cache = saved;
|
||||
this.cache = saved;
|
||||
return saved;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public onApplicationShutdown(signal?: string | undefined) {
|
||||
clearInterval(this.#intervalId);
|
||||
clearInterval(this.intervalId);
|
||||
}
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ export class NoteCreateService {
|
||||
|
||||
emojis = data.apEmojis ?? extractCustomEmojisFromMfm(combinedTokens);
|
||||
|
||||
mentionedUsers = data.apMentions ?? await this.#extractMentionedUsers(user, combinedTokens);
|
||||
mentionedUsers = data.apMentions ?? await this.extractMentionedUsers(user, combinedTokens);
|
||||
}
|
||||
|
||||
tags = tags.filter(tag => Array.from(tag ?? '').length <= 128).splice(0, 32);
|
||||
@ -300,14 +300,14 @@ export class NoteCreateService {
|
||||
}
|
||||
}
|
||||
|
||||
const note = await this.#insertNote(user, data, tags, emojis, mentionedUsers);
|
||||
const note = await this.insertNote(user, data, tags, emojis, mentionedUsers);
|
||||
|
||||
setImmediate(() => this.#postNoteCreated(note, user, data, silent, tags!, mentionedUsers!));
|
||||
setImmediate(() => this.postNoteCreated(note, user, data, silent, tags!, mentionedUsers!));
|
||||
|
||||
return note;
|
||||
}
|
||||
|
||||
async #insertNote(user: { id: User['id']; host: User['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: MinimumUser[]) {
|
||||
private async insertNote(user: { id: User['id']; host: User['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: MinimumUser[]) {
|
||||
const insert = new Note({
|
||||
id: this.idService.genId(data.createdAt!),
|
||||
createdAt: data.createdAt!,
|
||||
@ -403,7 +403,7 @@ export class NoteCreateService {
|
||||
}
|
||||
}
|
||||
|
||||
async #postNoteCreated(note: Note, user: {
|
||||
private async postNoteCreated(note: Note, user: {
|
||||
id: User['id'];
|
||||
username: User['username'];
|
||||
host: User['host'];
|
||||
@ -428,7 +428,7 @@ export class NoteCreateService {
|
||||
}
|
||||
|
||||
// Increment notes count (user)
|
||||
this.#incNotesCountOfUser(user);
|
||||
this.incNotesCountOfUser(user);
|
||||
|
||||
// Word mute
|
||||
mutedWordsCache.fetch(null, () => this.userProfilesRepository.find({
|
||||
@ -473,12 +473,12 @@ export class NoteCreateService {
|
||||
}
|
||||
|
||||
if (data.reply) {
|
||||
this.#saveReply(data.reply, note);
|
||||
this.saveReply(data.reply, note);
|
||||
}
|
||||
|
||||
// この投稿を除く指定したユーザーによる指定したノートのリノートが存在しないとき
|
||||
if (data.renote && (await this.noteEntityService.countSameRenotes(user.id, data.renote.id, note.id) === 0)) {
|
||||
this.#incRenoteCount(data.renote);
|
||||
this.incRenoteCount(data.renote);
|
||||
}
|
||||
|
||||
if (data.poll && data.poll.expiresAt) {
|
||||
@ -536,7 +536,7 @@ export class NoteCreateService {
|
||||
const nm = new NotificationManager(this.mutingsRepository, this.createNotificationService, user, note);
|
||||
const nmRelatedPromises = [];
|
||||
|
||||
await this.#createMentionedEvents(mentionedUsers, note, nm);
|
||||
await this.createMentionedEvents(mentionedUsers, note, nm);
|
||||
|
||||
// If has in reply to note
|
||||
if (data.reply) {
|
||||
@ -590,7 +590,7 @@ export class NoteCreateService {
|
||||
//#region AP deliver
|
||||
if (this.userEntityService.isLocalUser(user)) {
|
||||
(async () => {
|
||||
const noteActivity = await this.#renderNoteOrRenoteActivity(data, note);
|
||||
const noteActivity = await this.renderNoteOrRenoteActivity(data, note);
|
||||
const dm = this.apDeliverManagerService.createDeliverManager(user, noteActivity);
|
||||
|
||||
// メンションされたリモートユーザーに配送
|
||||
@ -644,10 +644,10 @@ export class NoteCreateService {
|
||||
}
|
||||
|
||||
// Register to search database
|
||||
this.#index(note);
|
||||
this.index(note);
|
||||
}
|
||||
|
||||
#incRenoteCount(renote: Note) {
|
||||
private incRenoteCount(renote: Note) {
|
||||
this.notesRepository.createQueryBuilder().update()
|
||||
.set({
|
||||
renoteCount: () => '"renoteCount" + 1',
|
||||
@ -657,7 +657,7 @@ export class NoteCreateService {
|
||||
.execute();
|
||||
}
|
||||
|
||||
async #createMentionedEvents(mentionedUsers: MinimumUser[], note: Note, nm: NotificationManager) {
|
||||
private async createMentionedEvents(mentionedUsers: MinimumUser[], note: Note, nm: NotificationManager) {
|
||||
for (const u of mentionedUsers.filter(u => this.userEntityService.isLocalUser(u))) {
|
||||
const threadMuted = await this.noteThreadMutingsRepository.findOneBy({
|
||||
userId: u.id,
|
||||
@ -686,11 +686,11 @@ export class NoteCreateService {
|
||||
}
|
||||
}
|
||||
|
||||
#saveReply(reply: Note, note: Note) {
|
||||
private saveReply(reply: Note, note: Note) {
|
||||
this.notesRepository.increment({ id: reply.id }, 'repliesCount', 1);
|
||||
}
|
||||
|
||||
async #renderNoteOrRenoteActivity(data: Option, note: Note) {
|
||||
private async renderNoteOrRenoteActivity(data: Option, note: Note) {
|
||||
if (data.localOnly) return null;
|
||||
|
||||
const content = data.renote && data.text == null && data.poll == null && (data.files == null || data.files.length === 0)
|
||||
@ -700,7 +700,7 @@ export class NoteCreateService {
|
||||
return this.apRendererService.renderActivity(content);
|
||||
}
|
||||
|
||||
#index(note: Note) {
|
||||
private index(note: Note) {
|
||||
if (note.text == null || this.config.elasticsearch == null) return;
|
||||
/*
|
||||
es!.index({
|
||||
@ -714,7 +714,7 @@ export class NoteCreateService {
|
||||
});*/
|
||||
}
|
||||
|
||||
#incNotesCountOfUser(user: { id: User['id']; }) {
|
||||
private incNotesCountOfUser(user: { id: User['id']; }) {
|
||||
this.usersRepository.createQueryBuilder().update()
|
||||
.set({
|
||||
updatedAt: new Date(),
|
||||
@ -724,7 +724,7 @@ export class NoteCreateService {
|
||||
.execute();
|
||||
}
|
||||
|
||||
async #extractMentionedUsers(user: { host: User['host']; }, tokens: mfm.MfmNode[]): Promise<User[]> {
|
||||
private async extractMentionedUsers(user: { host: User['host']; }, tokens: mfm.MfmNode[]): Promise<User[]> {
|
||||
if (tokens == null) return [];
|
||||
|
||||
const mentions = extractMentions(tokens);
|
||||
|
@ -79,16 +79,16 @@ export class NoteDeleteService {
|
||||
? this.apRendererService.renderUndo(this.apRendererService.renderAnnounce(renote.uri ?? `${this.config.url}/notes/${renote.id}`, note), user)
|
||||
: this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${note.id}`), user));
|
||||
|
||||
this.#deliverToConcerned(user, note, content);
|
||||
this.deliverToConcerned(user, note, content);
|
||||
}
|
||||
|
||||
// also deliever delete activity to cascaded notes
|
||||
const cascadingNotes = (await this.#findCascadingNotes(note)).filter(note => !note.localOnly); // filter out local-only notes
|
||||
const cascadingNotes = (await this.findCascadingNotes(note)).filter(note => !note.localOnly); // filter out local-only notes
|
||||
for (const cascadingNote of cascadingNotes) {
|
||||
if (!cascadingNote.user) continue;
|
||||
if (!this.userEntityService.isLocalUser(cascadingNote.user)) continue;
|
||||
const content = this.apRendererService.renderActivity(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${cascadingNote.id}`), cascadingNote.user));
|
||||
this.#deliverToConcerned(cascadingNote.user, cascadingNote, content);
|
||||
this.deliverToConcerned(cascadingNote.user, cascadingNote, content);
|
||||
}
|
||||
//#endregion
|
||||
|
||||
@ -110,7 +110,7 @@ export class NoteDeleteService {
|
||||
});
|
||||
}
|
||||
|
||||
async #findCascadingNotes(note: Note) {
|
||||
private async findCascadingNotes(note: Note) {
|
||||
const cascadingNotes: Note[] = [];
|
||||
|
||||
const recursive = async (noteId: string) => {
|
||||
@ -132,7 +132,7 @@ export class NoteDeleteService {
|
||||
return cascadingNotes.filter(note => note.userHost === null); // filter out non-local users
|
||||
}
|
||||
|
||||
async #getMentionedRemoteUsers(note: Note) {
|
||||
private async getMentionedRemoteUsers(note: Note) {
|
||||
const where = [] as any[];
|
||||
|
||||
// mention / reply / dm
|
||||
@ -157,10 +157,10 @@ export class NoteDeleteService {
|
||||
}) as IRemoteUser[];
|
||||
}
|
||||
|
||||
async #deliverToConcerned(user: { id: ILocalUser['id']; host: null; }, note: Note, content: any) {
|
||||
private async deliverToConcerned(user: { id: ILocalUser['id']; host: null; }, note: Note, content: any) {
|
||||
this.apDeliverManagerService.deliverToFollowers(user, content);
|
||||
this.relayService.deliverToRelays(user, content);
|
||||
const remoteUsers = await this.#getMentionedRemoteUsers(note);
|
||||
const remoteUsers = await this.getMentionedRemoteUsers(note);
|
||||
for (const remoteUser of remoteUsers) {
|
||||
this.apDeliverManagerService.deliverToUser(user, content, remoteUser);
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ export class NotificationService {
|
||||
|
||||
if (result.affected === 0) return;
|
||||
|
||||
if (!await this.userEntityService.getHasUnreadNotification(userId)) return this.#postReadAllNotifications(userId);
|
||||
else return this.#postReadNotifications(userId, notificationIds);
|
||||
if (!await this.userEntityService.getHasUnreadNotification(userId)) return this.postReadAllNotifications(userId);
|
||||
else return this.postReadNotifications(userId, notificationIds);
|
||||
}
|
||||
|
||||
public async readNotificationByQuery(
|
||||
@ -55,12 +55,12 @@ export class NotificationService {
|
||||
return this.readNotification(userId, notificationIds);
|
||||
}
|
||||
|
||||
#postReadAllNotifications(userId: User['id']) {
|
||||
private postReadAllNotifications(userId: User['id']) {
|
||||
this.globalEventService.publishMainStream(userId, 'readAllNotifications');
|
||||
return this.pushNotificationService.pushNotification(userId, 'readAllNotifications', undefined);
|
||||
}
|
||||
|
||||
#postReadNotifications(userId: User['id'], notificationIds: Notification['id'][]) {
|
||||
private postReadNotifications(userId: User['id'], notificationIds: Notification['id'][]) {
|
||||
this.globalEventService.publishMainStream(userId, 'readNotifications', notificationIds);
|
||||
return this.pushNotificationService.pushNotification(userId, 'readNotifications', { notificationIds });
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ const ACTOR_USERNAME = 'relay.actor' as const;
|
||||
|
||||
@Injectable()
|
||||
export class RelayService {
|
||||
#relaysCache: Cache<Relay[]>;
|
||||
private relaysCache: Cache<Relay[]>;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.usersRepository)
|
||||
@ -28,10 +28,10 @@ export class RelayService {
|
||||
private createSystemUserService: CreateSystemUserService,
|
||||
private apRendererService: ApRendererService,
|
||||
) {
|
||||
this.#relaysCache = new Cache<Relay[]>(1000 * 60 * 10);
|
||||
this.relaysCache = new Cache<Relay[]>(1000 * 60 * 10);
|
||||
}
|
||||
|
||||
async #getRelayActor(): Promise<ILocalUser> {
|
||||
private async getRelayActor(): Promise<ILocalUser> {
|
||||
const user = await this.usersRepository.findOneBy({
|
||||
host: IsNull(),
|
||||
username: ACTOR_USERNAME,
|
||||
@ -50,7 +50,7 @@ export class RelayService {
|
||||
status: 'requesting',
|
||||
}).then(x => this.relaysRepository.findOneByOrFail(x.identifiers[0]));
|
||||
|
||||
const relayActor = await this.#getRelayActor();
|
||||
const relayActor = await this.getRelayActor();
|
||||
const follow = await this.apRendererService.renderFollowRelay(relay, relayActor);
|
||||
const activity = this.apRendererService.renderActivity(follow);
|
||||
this.queueService.deliver(relayActor, activity, relay.inbox);
|
||||
@ -67,7 +67,7 @@ export class RelayService {
|
||||
throw new Error('relay not found');
|
||||
}
|
||||
|
||||
const relayActor = await this.#getRelayActor();
|
||||
const relayActor = await this.getRelayActor();
|
||||
const follow = this.apRendererService.renderFollowRelay(relay, relayActor);
|
||||
const undo = this.apRendererService.renderUndo(follow, relayActor);
|
||||
const activity = this.apRendererService.renderActivity(undo);
|
||||
@ -100,7 +100,7 @@ export class RelayService {
|
||||
public async deliverToRelays(user: { id: User['id']; host: null; }, activity: any): Promise<void> {
|
||||
if (activity == null) return;
|
||||
|
||||
const relays = await this.#relaysCache.fetch(null, () => this.relaysRepository.findBy({
|
||||
const relays = await this.relaysCache.fetch(null, () => this.relaysRepository.findBy({
|
||||
status: 'accepted',
|
||||
}));
|
||||
if (relays.length === 0) return;
|
||||
|
@ -44,11 +44,11 @@ export class UserBlockingService {
|
||||
|
||||
public async block(blocker: User, blockee: User) {
|
||||
await Promise.all([
|
||||
this.#cancelRequest(blocker, blockee),
|
||||
this.#cancelRequest(blockee, blocker),
|
||||
this.#unFollow(blocker, blockee),
|
||||
this.#unFollow(blockee, blocker),
|
||||
this.#removeFromList(blockee, blocker),
|
||||
this.cancelRequest(blocker, blockee),
|
||||
this.cancelRequest(blockee, blocker),
|
||||
this.unFollow(blocker, blockee),
|
||||
this.unFollow(blockee, blocker),
|
||||
this.removeFromList(blockee, blocker),
|
||||
]);
|
||||
|
||||
const blocking = {
|
||||
@ -68,7 +68,7 @@ export class UserBlockingService {
|
||||
}
|
||||
}
|
||||
|
||||
async #cancelRequest(follower: User, followee: User) {
|
||||
private async cancelRequest(follower: User, followee: User) {
|
||||
const request = await this.followRequestsRepository.findOneBy({
|
||||
followeeId: followee.id,
|
||||
followerId: follower.id,
|
||||
@ -118,7 +118,7 @@ export class UserBlockingService {
|
||||
}
|
||||
}
|
||||
|
||||
async #unFollow(follower: User, followee: User) {
|
||||
private async unFollow(follower: User, followee: User) {
|
||||
const following = await this.followingsRepository.findOneBy({
|
||||
followerId: follower.id,
|
||||
followeeId: followee.id,
|
||||
@ -159,7 +159,7 @@ export class UserBlockingService {
|
||||
}
|
||||
}
|
||||
|
||||
async #removeFromList(listOwner: User, user: User) {
|
||||
private async removeFromList(listOwner: User, user: User) {
|
||||
const userLists = await this.userListsRepository.findBy({
|
||||
userId: listOwner.id,
|
||||
});
|
||||
|
@ -131,7 +131,7 @@ export class UserFollowingService {
|
||||
}
|
||||
}
|
||||
|
||||
await this.#insertFollowingDoc(followee, follower);
|
||||
await this.insertFollowingDoc(followee, follower);
|
||||
|
||||
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
|
||||
const content = this.apRendererService.renderActivity(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee));
|
||||
@ -139,7 +139,7 @@ export class UserFollowingService {
|
||||
}
|
||||
}
|
||||
|
||||
async #insertFollowingDoc(
|
||||
private async insertFollowingDoc(
|
||||
followee: {
|
||||
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']
|
||||
},
|
||||
@ -273,7 +273,7 @@ export class UserFollowingService {
|
||||
|
||||
await this.followingsRepository.delete(following.id);
|
||||
|
||||
this.#decrementFollowing(follower, followee);
|
||||
this.decrementFollowing(follower, followee);
|
||||
|
||||
// Publish unfollow event
|
||||
if (!silent && this.userEntityService.isLocalUser(follower)) {
|
||||
@ -304,7 +304,7 @@ export class UserFollowingService {
|
||||
}
|
||||
}
|
||||
|
||||
async #decrementFollowing(
|
||||
private async decrementFollowing(
|
||||
follower: {id: User['id']; host: User['host']; },
|
||||
followee: { id: User['id']; host: User['host']; },
|
||||
): Promise<void> {
|
||||
@ -445,7 +445,7 @@ export class UserFollowingService {
|
||||
throw new IdentifiableError('8884c2dd-5795-4ac9-b27e-6a01d38190f9', 'No follow request.');
|
||||
}
|
||||
|
||||
await this.#insertFollowingDoc(followee, follower);
|
||||
await this.insertFollowingDoc(followee, follower);
|
||||
|
||||
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
|
||||
const content = this.apRendererService.renderActivity(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, request.requestId!), followee));
|
||||
@ -477,13 +477,13 @@ export class UserFollowingService {
|
||||
*/
|
||||
public async rejectFollowRequest(user: Local, follower: Both): Promise<void> {
|
||||
if (this.userEntityService.isRemoteUser(follower)) {
|
||||
this.#deliverReject(user, follower);
|
||||
this.deliverReject(user, follower);
|
||||
}
|
||||
|
||||
await this.#removeFollowRequest(user, follower);
|
||||
await this.removeFollowRequest(user, follower);
|
||||
|
||||
if (this.userEntityService.isLocalUser(follower)) {
|
||||
this.#publishUnfollow(user, follower);
|
||||
this.publishUnfollow(user, follower);
|
||||
}
|
||||
}
|
||||
|
||||
@ -492,13 +492,13 @@ export class UserFollowingService {
|
||||
*/
|
||||
public async rejectFollow(user: Local, follower: Both): Promise<void> {
|
||||
if (this.userEntityService.isRemoteUser(follower)) {
|
||||
this.#deliverReject(user, follower);
|
||||
this.deliverReject(user, follower);
|
||||
}
|
||||
|
||||
await this.#removeFollow(user, follower);
|
||||
await this.removeFollow(user, follower);
|
||||
|
||||
if (this.userEntityService.isLocalUser(follower)) {
|
||||
this.#publishUnfollow(user, follower);
|
||||
this.publishUnfollow(user, follower);
|
||||
}
|
||||
}
|
||||
|
||||
@ -506,15 +506,15 @@ export class UserFollowingService {
|
||||
* AP Reject/Follow
|
||||
*/
|
||||
public async remoteReject(actor: Remote, follower: Local): Promise<void> {
|
||||
await this.#removeFollowRequest(actor, follower);
|
||||
await this.#removeFollow(actor, follower);
|
||||
this.#publishUnfollow(actor, follower);
|
||||
await this.removeFollowRequest(actor, follower);
|
||||
await this.removeFollow(actor, follower);
|
||||
this.publishUnfollow(actor, follower);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove follow request record
|
||||
*/
|
||||
async #removeFollowRequest(followee: Both, follower: Both): Promise<void> {
|
||||
private async removeFollowRequest(followee: Both, follower: Both): Promise<void> {
|
||||
const request = await this.followRequestsRepository.findOneBy({
|
||||
followeeId: followee.id,
|
||||
followerId: follower.id,
|
||||
@ -528,7 +528,7 @@ export class UserFollowingService {
|
||||
/**
|
||||
* Remove follow record
|
||||
*/
|
||||
async #removeFollow(followee: Both, follower: Both): Promise<void> {
|
||||
private async removeFollow(followee: Both, follower: Both): Promise<void> {
|
||||
const following = await this.followingsRepository.findOneBy({
|
||||
followeeId: followee.id,
|
||||
followerId: follower.id,
|
||||
@ -537,13 +537,13 @@ export class UserFollowingService {
|
||||
if (!following) return;
|
||||
|
||||
await this.followingsRepository.delete(following.id);
|
||||
this.#decrementFollowing(follower, followee);
|
||||
this.decrementFollowing(follower, followee);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deliver Reject to remote
|
||||
*/
|
||||
async #deliverReject(followee: Local, follower: Remote): Promise<void> {
|
||||
private async deliverReject(followee: Local, follower: Remote): Promise<void> {
|
||||
const request = await this.followRequestsRepository.findOneBy({
|
||||
followeeId: followee.id,
|
||||
followerId: follower.id,
|
||||
@ -556,7 +556,7 @@ export class UserFollowingService {
|
||||
/**
|
||||
* Publish unfollow to local
|
||||
*/
|
||||
async #publishUnfollow(followee: Both, follower: Local): Promise<void> {
|
||||
private async publishUnfollow(followee: Both, follower: Local): Promise<void> {
|
||||
const packedFollowee = await this.userEntityService.pack(followee.id, follower, {
|
||||
detail: true,
|
||||
});
|
||||
|
@ -7,16 +7,16 @@ import { DI } from '@/di-symbols.js';
|
||||
|
||||
@Injectable()
|
||||
export class UserKeypairStoreService {
|
||||
#cache: Cache<UserKeypair>;
|
||||
private cache: Cache<UserKeypair>;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.userKeypairsRepository)
|
||||
private userKeypairsRepository: UserKeypairsRepository,
|
||||
) {
|
||||
this.#cache = new Cache<UserKeypair>(Infinity);
|
||||
this.cache = new Cache<UserKeypair>(Infinity);
|
||||
}
|
||||
|
||||
public async getUserKeypair(userId: User['id']): Promise<UserKeypair> {
|
||||
return await this.#cache.fetch(userId, () => this.userKeypairsRepository.findOneByOrFail({ userId: userId }));
|
||||
return await this.cache.fetch(userId, () => this.userKeypairsRepository.findOneByOrFail({ userId: userId }));
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ import type { OnApplicationShutdown } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class WebhookService implements OnApplicationShutdown {
|
||||
#webhooksFetched = false;
|
||||
#webhooks: Webhook[] = [];
|
||||
private webhooksFetched = false;
|
||||
private webhooks: Webhook[] = [];
|
||||
|
||||
constructor(
|
||||
@Inject(DI.redisSubscriber)
|
||||
@ -22,14 +22,14 @@ export class WebhookService implements OnApplicationShutdown {
|
||||
}
|
||||
|
||||
public async getActiveWebhooks() {
|
||||
if (!this.#webhooksFetched) {
|
||||
this.#webhooks = await this.webhooksRepository.findBy({
|
||||
if (!this.webhooksFetched) {
|
||||
this.webhooks = await this.webhooksRepository.findBy({
|
||||
active: true,
|
||||
});
|
||||
this.#webhooksFetched = true;
|
||||
this.webhooksFetched = true;
|
||||
}
|
||||
|
||||
return this.#webhooks;
|
||||
return this.webhooks;
|
||||
}
|
||||
|
||||
private async onMessage(_, data) {
|
||||
@ -40,23 +40,23 @@ export class WebhookService implements OnApplicationShutdown {
|
||||
switch (type) {
|
||||
case 'webhookCreated':
|
||||
if (body.active) {
|
||||
this.#webhooks.push(body);
|
||||
this.webhooks.push(body);
|
||||
}
|
||||
break;
|
||||
case 'webhookUpdated':
|
||||
if (body.active) {
|
||||
const i = this.#webhooks.findIndex(a => a.id === body.id);
|
||||
const i = this.webhooks.findIndex(a => a.id === body.id);
|
||||
if (i > -1) {
|
||||
this.#webhooks[i] = body;
|
||||
this.webhooks[i] = body;
|
||||
} else {
|
||||
this.#webhooks.push(body);
|
||||
this.webhooks.push(body);
|
||||
}
|
||||
} else {
|
||||
this.#webhooks = this.#webhooks.filter(a => a.id !== body.id);
|
||||
this.webhooks = this.webhooks.filter(a => a.id !== body.id);
|
||||
}
|
||||
break;
|
||||
case 'webhookDeleted':
|
||||
this.#webhooks = this.#webhooks.filter(a => a.id !== body.id);
|
||||
this.webhooks = this.webhooks.filter(a => a.id !== body.id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -109,7 +109,7 @@ export function getJsonSchema<S extends Schema>(schema: S): ToJsonSchema<Unflatt
|
||||
*/
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default abstract class Chart<T extends Schema> {
|
||||
#logger: Logger;
|
||||
private logger: Logger;
|
||||
|
||||
public schema: T;
|
||||
|
||||
@ -242,7 +242,7 @@ export default abstract class Chart<T extends Schema> {
|
||||
this.name = name;
|
||||
this.schema = schema;
|
||||
this.lock = lock;
|
||||
this.#logger = logger;
|
||||
this.logger = logger;
|
||||
|
||||
const { hour, day } = Chart.schemaToEntity(name, schema, grouped);
|
||||
this.repositoryForHour = db.getRepository<{ id: number; group?: string | null; date: number; }>(hour);
|
||||
@ -333,7 +333,7 @@ export default abstract class Chart<T extends Schema> {
|
||||
// 初期ログデータを作成
|
||||
data = this.getNewLog(null);
|
||||
|
||||
this.#logger.info(`${this.name + (group ? `:${group}` : '')}(${span}): Initial commit created`);
|
||||
this.logger.info(`${this.name + (group ? `:${group}` : '')}(${span}): Initial commit created`);
|
||||
}
|
||||
|
||||
const date = Chart.dateToTimestamp(current);
|
||||
@ -363,7 +363,7 @@ export default abstract class Chart<T extends Schema> {
|
||||
...columns,
|
||||
}).then(x => repository.findOneByOrFail(x.identifiers[0])) as RawRecord<T>;
|
||||
|
||||
this.#logger.info(`${this.name + (group ? `:${group}` : '')}(${span}): New commit created`);
|
||||
this.logger.info(`${this.name + (group ? `:${group}` : '')}(${span}): New commit created`);
|
||||
|
||||
return log;
|
||||
} finally {
|
||||
@ -382,7 +382,7 @@ export default abstract class Chart<T extends Schema> {
|
||||
|
||||
public async save(): Promise<void> {
|
||||
if (this.buffer.length === 0) {
|
||||
this.#logger.info(`${this.name}: Write skipped`);
|
||||
this.logger.info(`${this.name}: Write skipped`);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -481,7 +481,7 @@ export default abstract class Chart<T extends Schema> {
|
||||
.execute(),
|
||||
]);
|
||||
|
||||
this.#logger.info(`${this.name + (logHour.group ? `:${logHour.group}` : '')}: Updated`);
|
||||
this.logger.info(`${this.name + (logHour.group ? `:${logHour.group}` : '')}: Updated`);
|
||||
|
||||
// TODO: この一連の処理が始まった後に新たにbufferに入ったものは消さないようにする
|
||||
this.buffer = this.buffer.filter(q => q.group != null && (q.group !== logHour.group));
|
||||
|
@ -68,7 +68,7 @@ export class NoteEntityService implements OnModuleInit {
|
||||
this.reactionService = this.moduleRef.get('ReactionService');
|
||||
}
|
||||
|
||||
async #hideNote(packedNote: Packed<'Note'>, meId: User['id'] | null) {
|
||||
private async hideNote(packedNote: Packed<'Note'>, meId: User['id'] | null) {
|
||||
// TODO: isVisibleForMe を使うようにしても良さそう(型違うけど)
|
||||
let hide = false;
|
||||
|
||||
@ -128,7 +128,7 @@ export class NoteEntityService implements OnModuleInit {
|
||||
}
|
||||
}
|
||||
|
||||
async #populatePoll(note: Note, meId: User['id'] | null) {
|
||||
private async populatePoll(note: Note, meId: User['id'] | null) {
|
||||
const poll = await this.pollsRepository.findOneByOrFail({ noteId: note.id });
|
||||
const choices = poll.choices.map(c => ({
|
||||
text: c,
|
||||
@ -166,7 +166,7 @@ export class NoteEntityService implements OnModuleInit {
|
||||
};
|
||||
}
|
||||
|
||||
async #populateMyReaction(note: Note, meId: User['id'], _hint_?: {
|
||||
private async populateMyReaction(note: Note, meId: User['id'], _hint_?: {
|
||||
myReactions: Map<Note['id'], NoteReaction | null>;
|
||||
}) {
|
||||
if (_hint_?.myReactions) {
|
||||
@ -319,10 +319,10 @@ export class NoteEntityService implements OnModuleInit {
|
||||
_hint_: options?._hint_,
|
||||
}) : undefined,
|
||||
|
||||
poll: note.hasPoll ? this.#populatePoll(note, meId) : undefined,
|
||||
poll: note.hasPoll ? this.populatePoll(note, meId) : undefined,
|
||||
|
||||
...(meId ? {
|
||||
myReaction: this.#populateMyReaction(note, meId, options?._hint_),
|
||||
myReaction: this.populateMyReaction(note, meId, options?._hint_),
|
||||
} : {}),
|
||||
} : {}),
|
||||
});
|
||||
@ -339,7 +339,7 @@ export class NoteEntityService implements OnModuleInit {
|
||||
}
|
||||
|
||||
if (!opts.skipHide) {
|
||||
await this.#hideNote(packed, meId);
|
||||
await this.hideNote(packed, meId);
|
||||
}
|
||||
|
||||
return packed;
|
||||
|
@ -48,7 +48,7 @@ export class UserEntityService implements OnModuleInit {
|
||||
private pageEntityService: PageEntityService;
|
||||
private customEmojiService: CustomEmojiService;
|
||||
private antennaService: AntennaService;
|
||||
#userInstanceCache: Cache<Instance | null>;
|
||||
private userInstanceCache: Cache<Instance | null>;
|
||||
|
||||
constructor(
|
||||
private moduleRef: ModuleRef,
|
||||
@ -119,7 +119,7 @@ export class UserEntityService implements OnModuleInit {
|
||||
//private customEmojiService: CustomEmojiService,
|
||||
//private antennaService: AntennaService,
|
||||
) {
|
||||
this.#userInstanceCache = new Cache<Instance | null>(1000 * 60 * 60 * 3);
|
||||
this.userInstanceCache = new Cache<Instance | null>(1000 * 60 * 60 * 3);
|
||||
}
|
||||
|
||||
onModuleInit() {
|
||||
@ -384,7 +384,7 @@ export class UserEntityService implements OnModuleInit {
|
||||
isModerator: user.isModerator ?? falsy,
|
||||
isBot: user.isBot ?? falsy,
|
||||
isCat: user.isCat ?? falsy,
|
||||
instance: user.host ? this.#userInstanceCache.fetch(user.host,
|
||||
instance: user.host ? this.userInstanceCache.fetch(user.host,
|
||||
() => this.instancesRepository.findOneBy({ host: user.host! }),
|
||||
v => v != null,
|
||||
).then(instance => instance ? {
|
||||
|
@ -14,7 +14,7 @@ import { ApPersonService } from './activitypub/models/ApPersonService.js';
|
||||
|
||||
@Injectable()
|
||||
export class ResolveUserService {
|
||||
#logger: Logger;
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
@ -28,14 +28,14 @@ export class ResolveUserService {
|
||||
private remoteLoggerService: RemoteLoggerService,
|
||||
private apPersonService: ApPersonService,
|
||||
) {
|
||||
this.#logger = this.remoteLoggerService.logger.createSubLogger('resolve-user');
|
||||
this.logger = this.remoteLoggerService.logger.createSubLogger('resolve-user');
|
||||
}
|
||||
|
||||
public async resolveUser(username: string, host: string | null): Promise<User> {
|
||||
const usernameLower = username.toLowerCase();
|
||||
|
||||
if (host == null) {
|
||||
this.#logger.info(`return local user: ${usernameLower}`);
|
||||
this.logger.info(`return local user: ${usernameLower}`);
|
||||
return await this.usersRepository.findOneBy({ usernameLower, host: IsNull() }).then(u => {
|
||||
if (u == null) {
|
||||
throw new Error('user not found');
|
||||
@ -48,7 +48,7 @@ export class ResolveUserService {
|
||||
host = this.utilityService.toPuny(host);
|
||||
|
||||
if (this.config.host === host) {
|
||||
this.#logger.info(`return local user: ${usernameLower}`);
|
||||
this.logger.info(`return local user: ${usernameLower}`);
|
||||
return await this.usersRepository.findOneBy({ usernameLower, host: IsNull() }).then(u => {
|
||||
if (u == null) {
|
||||
throw new Error('user not found');
|
||||
@ -63,9 +63,9 @@ export class ResolveUserService {
|
||||
const acctLower = `${usernameLower}@${host}`;
|
||||
|
||||
if (user == null) {
|
||||
const self = await this.#resolveSelf(acctLower);
|
||||
const self = await this.resolveSelf(acctLower);
|
||||
|
||||
this.#logger.succ(`return new remote user: ${chalk.magenta(acctLower)}`);
|
||||
this.logger.succ(`return new remote user: ${chalk.magenta(acctLower)}`);
|
||||
return await this.apPersonService.createPerson(self.href);
|
||||
}
|
||||
|
||||
@ -76,13 +76,13 @@ export class ResolveUserService {
|
||||
lastFetchedAt: new Date(),
|
||||
});
|
||||
|
||||
this.#logger.info(`try resync: ${acctLower}`);
|
||||
const self = await this.#resolveSelf(acctLower);
|
||||
this.logger.info(`try resync: ${acctLower}`);
|
||||
const self = await this.resolveSelf(acctLower);
|
||||
|
||||
if (user.uri !== self.href) {
|
||||
// if uri mismatch, Fix (user@host <=> AP's Person id(IRemoteUser.uri)) mapping.
|
||||
this.#logger.info(`uri missmatch: ${acctLower}`);
|
||||
this.#logger.info(`recovery missmatch uri for (username=${username}, host=${host}) from ${user.uri} to ${self.href}`);
|
||||
this.logger.info(`uri missmatch: ${acctLower}`);
|
||||
this.logger.info(`recovery missmatch uri for (username=${username}, host=${host}) from ${user.uri} to ${self.href}`);
|
||||
|
||||
// validate uri
|
||||
const uri = new URL(self.href);
|
||||
@ -97,12 +97,12 @@ export class ResolveUserService {
|
||||
uri: self.href,
|
||||
});
|
||||
} else {
|
||||
this.#logger.info(`uri is fine: ${acctLower}`);
|
||||
this.logger.info(`uri is fine: ${acctLower}`);
|
||||
}
|
||||
|
||||
await this.apPersonService.updatePerson(self.href);
|
||||
|
||||
this.#logger.info(`return resynced remote user: ${acctLower}`);
|
||||
this.logger.info(`return resynced remote user: ${acctLower}`);
|
||||
return await this.usersRepository.findOneBy({ uri: self.href }).then(u => {
|
||||
if (u == null) {
|
||||
throw new Error('user not found');
|
||||
@ -112,19 +112,19 @@ export class ResolveUserService {
|
||||
});
|
||||
}
|
||||
|
||||
this.#logger.info(`return existing remote user: ${acctLower}`);
|
||||
this.logger.info(`return existing remote user: ${acctLower}`);
|
||||
return user;
|
||||
}
|
||||
|
||||
async #resolveSelf(acctLower: string) {
|
||||
this.#logger.info(`WebFinger for ${chalk.yellow(acctLower)}`);
|
||||
private async resolveSelf(acctLower: string) {
|
||||
this.logger.info(`WebFinger for ${chalk.yellow(acctLower)}`);
|
||||
const finger = await this.webfingerService.webfinger(acctLower).catch(err => {
|
||||
this.#logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: ${ err.statusCode ?? err.message }`);
|
||||
this.logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: ${ err.statusCode ?? err.message }`);
|
||||
throw new Error(`Failed to WebFinger for ${acctLower}: ${ err.statusCode ?? err.message }`);
|
||||
});
|
||||
const self = finger.links.find(link => link.rel != null && link.rel.toLowerCase() === 'self');
|
||||
if (!self) {
|
||||
this.#logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: self link not found`);
|
||||
this.logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: self link not found`);
|
||||
throw new Error('self link not found');
|
||||
}
|
||||
return self;
|
||||
|
@ -26,12 +26,12 @@ export class WebfingerService {
|
||||
}
|
||||
|
||||
public async webfinger(query: string): Promise<IWebFinger> {
|
||||
const url = this.#genUrl(query);
|
||||
const url = this.genUrl(query);
|
||||
|
||||
return await this.httpRequestService.getJson(url, 'application/jrd+json, application/json') as IWebFinger;
|
||||
}
|
||||
|
||||
#genUrl(query: string): string {
|
||||
private genUrl(query: string): string {
|
||||
if (query.match(/^https?:\/\//)) {
|
||||
const u = new URL(query);
|
||||
return `${u.protocol}//${u.hostname}/.well-known/webfinger?` + urlQuery({ resource: query });
|
||||
|
@ -25,8 +25,8 @@ export class ApAudienceService {
|
||||
}
|
||||
|
||||
public async parseAudience(actor: CacheableRemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver): Promise<AudienceInfo> {
|
||||
const toGroups = this.#groupingAudience(getApIds(to), actor);
|
||||
const ccGroups = this.#groupingAudience(getApIds(cc), actor);
|
||||
const toGroups = this.groupingAudience(getApIds(to), actor);
|
||||
const ccGroups = this.groupingAudience(getApIds(cc), actor);
|
||||
|
||||
const others = unique(concat([toGroups.other, ccGroups.other]));
|
||||
|
||||
@ -66,7 +66,7 @@ export class ApAudienceService {
|
||||
};
|
||||
}
|
||||
|
||||
#groupingAudience(ids: string[], actor: CacheableRemoteUser) {
|
||||
private groupingAudience(ids: string[], actor: CacheableRemoteUser) {
|
||||
const groups = {
|
||||
public: [] as string[],
|
||||
followers: [] as string[],
|
||||
@ -74,9 +74,9 @@ export class ApAudienceService {
|
||||
};
|
||||
|
||||
for (const id of ids) {
|
||||
if (this.#isPublic(id)) {
|
||||
if (this.isPublic(id)) {
|
||||
groups.public.push(id);
|
||||
} else if (this.#isFollowers(id, actor)) {
|
||||
} else if (this.isFollowers(id, actor)) {
|
||||
groups.followers.push(id);
|
||||
} else {
|
||||
groups.other.push(id);
|
||||
@ -88,7 +88,7 @@ export class ApAudienceService {
|
||||
return groups;
|
||||
}
|
||||
|
||||
#isPublic(id: string) {
|
||||
private isPublic(id: string) {
|
||||
return [
|
||||
'https://www.w3.org/ns/activitystreams#Public',
|
||||
'as#Public',
|
||||
@ -96,7 +96,7 @@ export class ApAudienceService {
|
||||
].includes(id);
|
||||
}
|
||||
|
||||
#isFollowers(id: string, actor: CacheableRemoteUser) {
|
||||
private isFollowers(id: string, actor: CacheableRemoteUser) {
|
||||
return (
|
||||
id === (actor.followersUri ?? `${actor.uri}/followers`)
|
||||
);
|
||||
|
@ -31,8 +31,8 @@ export type UriParseResult = {
|
||||
|
||||
@Injectable()
|
||||
export class ApDbResolverService {
|
||||
#publicKeyCache: Cache<UserPublickey | null>;
|
||||
#publicKeyByUserIdCache: Cache<UserPublickey | null>;
|
||||
private publicKeyCache: Cache<UserPublickey | null>;
|
||||
private publicKeyByUserIdCache: Cache<UserPublickey | null>;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
@ -53,8 +53,8 @@ export class ApDbResolverService {
|
||||
private userCacheService: UserCacheService,
|
||||
private apPersonService: ApPersonService,
|
||||
) {
|
||||
this.#publicKeyCache = new Cache<UserPublickey | null>(Infinity);
|
||||
this.#publicKeyByUserIdCache = new Cache<UserPublickey | null>(Infinity);
|
||||
this.publicKeyCache = new Cache<UserPublickey | null>(Infinity);
|
||||
this.publicKeyByUserIdCache = new Cache<UserPublickey | null>(Infinity);
|
||||
}
|
||||
|
||||
public parseUri(value: string | IObject): UriParseResult {
|
||||
@ -140,7 +140,7 @@ export class ApDbResolverService {
|
||||
user: CacheableRemoteUser;
|
||||
key: UserPublickey;
|
||||
} | null> {
|
||||
const key = await this.#publicKeyCache.fetch(keyId, async () => {
|
||||
const key = await this.publicKeyCache.fetch(keyId, async () => {
|
||||
const key = await this.userPublickeysRepository.findOneBy({
|
||||
keyId,
|
||||
});
|
||||
@ -169,7 +169,7 @@ export class ApDbResolverService {
|
||||
|
||||
if (user == null) return null;
|
||||
|
||||
const key = await this.#publicKeyByUserIdCache.fetch(user.id, () => this.userPublickeysRepository.findOneBy({ userId: user.id }), v => v != null);
|
||||
const key = await this.publicKeyByUserIdCache.fetch(user.id, () => this.userPublickeysRepository.findOneBy({ userId: user.id }), v => v != null);
|
||||
|
||||
return {
|
||||
user,
|
||||
|
@ -34,7 +34,7 @@ import type { IAccept, IAdd, IAnnounce, IBlock, ICreate, IDelete, IFlag, IFollow
|
||||
|
||||
@Injectable()
|
||||
export class ApInboxService {
|
||||
#logger: Logger;
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
@ -81,7 +81,7 @@ export class ApInboxService {
|
||||
private queueService: QueueService,
|
||||
private messagingService: MessagingService,
|
||||
) {
|
||||
this.#logger = this.apLoggerService.logger;
|
||||
this.logger = this.apLoggerService.logger;
|
||||
}
|
||||
|
||||
public async performActivity(actor: CacheableRemoteUser, activity: IObject) {
|
||||
@ -93,7 +93,7 @@ export class ApInboxService {
|
||||
await this.performOneActivity(actor, act);
|
||||
} catch (err) {
|
||||
if (err instanceof Error || typeof err === 'string') {
|
||||
this.#logger.error(err);
|
||||
this.logger.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -115,39 +115,39 @@ export class ApInboxService {
|
||||
if (actor.isSuspended) return;
|
||||
|
||||
if (isCreate(activity)) {
|
||||
await this.#create(actor, activity);
|
||||
await this.create(actor, activity);
|
||||
} else if (isDelete(activity)) {
|
||||
await this.#delete(actor, activity);
|
||||
await this.delete(actor, activity);
|
||||
} else if (isUpdate(activity)) {
|
||||
await this.#update(actor, activity);
|
||||
await this.update(actor, activity);
|
||||
} else if (isRead(activity)) {
|
||||
await this.#read(actor, activity);
|
||||
await this.read(actor, activity);
|
||||
} else if (isFollow(activity)) {
|
||||
await this.#follow(actor, activity);
|
||||
await this.follow(actor, activity);
|
||||
} else if (isAccept(activity)) {
|
||||
await this.#accept(actor, activity);
|
||||
await this.accept(actor, activity);
|
||||
} else if (isReject(activity)) {
|
||||
await this.#reject(actor, activity);
|
||||
await this.reject(actor, activity);
|
||||
} else if (isAdd(activity)) {
|
||||
await this.#add(actor, activity).catch(err => this.#logger.error(err));
|
||||
await this.add(actor, activity).catch(err => this.logger.error(err));
|
||||
} else if (isRemove(activity)) {
|
||||
await this.#remove(actor, activity).catch(err => this.#logger.error(err));
|
||||
await this.remove(actor, activity).catch(err => this.logger.error(err));
|
||||
} else if (isAnnounce(activity)) {
|
||||
await this.#announce(actor, activity);
|
||||
await this.announce(actor, activity);
|
||||
} else if (isLike(activity)) {
|
||||
await this.#like(actor, activity);
|
||||
await this.like(actor, activity);
|
||||
} else if (isUndo(activity)) {
|
||||
await this.#undo(actor, activity);
|
||||
await this.undo(actor, activity);
|
||||
} else if (isBlock(activity)) {
|
||||
await this.#block(actor, activity);
|
||||
await this.block(actor, activity);
|
||||
} else if (isFlag(activity)) {
|
||||
await this.#flag(actor, activity);
|
||||
await this.flag(actor, activity);
|
||||
} else {
|
||||
this.#logger.warn(`unrecognized activity type: ${(activity as any).type}`);
|
||||
this.logger.warn(`unrecognized activity type: ${(activity as any).type}`);
|
||||
}
|
||||
}
|
||||
|
||||
async #follow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
||||
private async follow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
||||
const followee = await this.apDbResolverService.getUserFromApId(activity.object);
|
||||
|
||||
if (followee == null) {
|
||||
@ -162,7 +162,7 @@ export class ApInboxService {
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
async #like(actor: CacheableRemoteUser, activity: ILike): Promise<string> {
|
||||
private async like(actor: CacheableRemoteUser, activity: ILike): Promise<string> {
|
||||
const targetUri = getApId(activity.object);
|
||||
|
||||
const note = await this.apNoteService.fetchNote(targetUri);
|
||||
@ -179,7 +179,7 @@ export class ApInboxService {
|
||||
}).then(() => 'ok');
|
||||
}
|
||||
|
||||
async #read(actor: CacheableRemoteUser, activity: IRead): Promise<string> {
|
||||
private async read(actor: CacheableRemoteUser, activity: IRead): Promise<string> {
|
||||
const id = await getApId(activity.object);
|
||||
|
||||
if (!this.utilityService.isSelfHost(this.utilityService.extractDbHost(id))) {
|
||||
@ -201,24 +201,24 @@ export class ApInboxService {
|
||||
return `ok: mark as read (${message.userId} => ${message.recipientId} ${message.id})`;
|
||||
}
|
||||
|
||||
async #accept(actor: CacheableRemoteUser, activity: IAccept): Promise<string> {
|
||||
private async accept(actor: CacheableRemoteUser, activity: IAccept): Promise<string> {
|
||||
const uri = activity.id ?? activity;
|
||||
|
||||
this.#logger.info(`Accept: ${uri}`);
|
||||
this.logger.info(`Accept: ${uri}`);
|
||||
|
||||
const resolver = this.apResolverService.createResolver();
|
||||
|
||||
const object = await resolver.resolve(activity.object).catch(err => {
|
||||
this.#logger.error(`Resolution failed: ${err}`);
|
||||
this.logger.error(`Resolution failed: ${err}`);
|
||||
throw err;
|
||||
});
|
||||
|
||||
if (isFollow(object)) return await this.#acceptFollow(actor, object);
|
||||
if (isFollow(object)) return await this.acceptFollow(actor, object);
|
||||
|
||||
return `skip: Unknown Accept type: ${getApType(object)}`;
|
||||
}
|
||||
|
||||
async #acceptFollow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
||||
private async acceptFollow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
||||
// ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある
|
||||
|
||||
const follower = await this.apDbResolverService.getUserFromApId(activity.actor);
|
||||
@ -241,7 +241,7 @@ export class ApInboxService {
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
async #add(actor: CacheableRemoteUser, activity: IAdd): Promise<void> {
|
||||
private async add(actor: CacheableRemoteUser, activity: IAdd): Promise<void> {
|
||||
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||
throw new Error('invalid actor');
|
||||
}
|
||||
@ -260,17 +260,17 @@ export class ApInboxService {
|
||||
throw new Error(`unknown target: ${activity.target}`);
|
||||
}
|
||||
|
||||
async #announce(actor: CacheableRemoteUser, activity: IAnnounce): Promise<void> {
|
||||
private async announce(actor: CacheableRemoteUser, activity: IAnnounce): Promise<void> {
|
||||
const uri = getApId(activity);
|
||||
|
||||
this.#logger.info(`Announce: ${uri}`);
|
||||
this.logger.info(`Announce: ${uri}`);
|
||||
|
||||
const targetUri = getApId(activity.object);
|
||||
|
||||
this.#announceNote(actor, activity, targetUri);
|
||||
this.announceNote(actor, activity, targetUri);
|
||||
}
|
||||
|
||||
async #announceNote(actor: CacheableRemoteUser, activity: IAnnounce, targetUri: string): Promise<void> {
|
||||
private async announceNote(actor: CacheableRemoteUser, activity: IAnnounce, targetUri: string): Promise<void> {
|
||||
const uri = getApId(activity);
|
||||
|
||||
if (actor.isSuspended) {
|
||||
@ -298,18 +298,18 @@ export class ApInboxService {
|
||||
// 対象が4xxならスキップ
|
||||
if (err instanceof StatusError) {
|
||||
if (err.isClientError) {
|
||||
this.#logger.warn(`Ignored announce target ${targetUri} - ${err.statusCode}`);
|
||||
this.logger.warn(`Ignored announce target ${targetUri} - ${err.statusCode}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.#logger.warn(`Error in announce target ${targetUri} - ${err.statusCode ?? err}`);
|
||||
this.logger.warn(`Error in announce target ${targetUri} - ${err.statusCode ?? err}`);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (!await this.noteEntityService.isVisibleForMe(renote, actor.id)) return 'skip: invalid actor for this activity';
|
||||
|
||||
this.#logger.info(`Creating the (Re)Note: ${uri}`);
|
||||
this.logger.info(`Creating the (Re)Note: ${uri}`);
|
||||
|
||||
const activityAudience = await this.apAudienceService.parseAudience(actor, activity.to, activity.cc);
|
||||
|
||||
@ -325,7 +325,7 @@ export class ApInboxService {
|
||||
}
|
||||
}
|
||||
|
||||
async #block(actor: CacheableRemoteUser, activity: IBlock): Promise<string> {
|
||||
private async block(actor: CacheableRemoteUser, activity: IBlock): Promise<string> {
|
||||
// ※ activity.objectにブロック対象があり、それは存在するローカルユーザーのはず
|
||||
|
||||
const blockee = await this.apDbResolverService.getUserFromApId(activity.object);
|
||||
@ -342,10 +342,10 @@ export class ApInboxService {
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
async #create(actor: CacheableRemoteUser, activity: ICreate): Promise<void> {
|
||||
private async create(actor: CacheableRemoteUser, activity: ICreate): Promise<void> {
|
||||
const uri = getApId(activity);
|
||||
|
||||
this.#logger.info(`Create: ${uri}`);
|
||||
this.logger.info(`Create: ${uri}`);
|
||||
|
||||
// copy audiences between activity <=> object.
|
||||
if (typeof activity.object === 'object') {
|
||||
@ -366,18 +366,18 @@ export class ApInboxService {
|
||||
const resolver = this.apResolverService.createResolver();
|
||||
|
||||
const object = await resolver.resolve(activity.object).catch(e => {
|
||||
this.#logger.error(`Resolution failed: ${e}`);
|
||||
this.logger.error(`Resolution failed: ${e}`);
|
||||
throw e;
|
||||
});
|
||||
|
||||
if (isPost(object)) {
|
||||
this.#createNote(resolver, actor, object, false, activity);
|
||||
this.createNote(resolver, actor, object, false, activity);
|
||||
} else {
|
||||
this.#logger.warn(`Unknown type: ${getApType(object)}`);
|
||||
this.logger.warn(`Unknown type: ${getApType(object)}`);
|
||||
}
|
||||
}
|
||||
|
||||
async #createNote(resolver: Resolver, actor: CacheableRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise<string> {
|
||||
private async createNote(resolver: Resolver, actor: CacheableRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise<string> {
|
||||
const uri = getApId(note);
|
||||
|
||||
if (typeof note === 'object') {
|
||||
@ -411,7 +411,7 @@ export class ApInboxService {
|
||||
}
|
||||
}
|
||||
|
||||
async #delete(actor: CacheableRemoteUser, activity: IDelete): Promise<string> {
|
||||
private async delete(actor: CacheableRemoteUser, activity: IDelete): Promise<string> {
|
||||
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||
throw new Error('invalid actor');
|
||||
}
|
||||
@ -444,16 +444,16 @@ export class ApInboxService {
|
||||
}
|
||||
|
||||
if (validPost.includes(formerType)) {
|
||||
return await this.#deleteNote(actor, uri);
|
||||
return await this.deleteNote(actor, uri);
|
||||
} else if (validActor.includes(formerType)) {
|
||||
return await this.#deleteActor(actor, uri);
|
||||
return await this.deleteActor(actor, uri);
|
||||
} else {
|
||||
return `Unknown type ${formerType}`;
|
||||
}
|
||||
}
|
||||
|
||||
async #deleteActor(actor: CacheableRemoteUser, uri: string): Promise<string> {
|
||||
this.#logger.info(`Deleting the Actor: ${uri}`);
|
||||
private async deleteActor(actor: CacheableRemoteUser, uri: string): Promise<string> {
|
||||
this.logger.info(`Deleting the Actor: ${uri}`);
|
||||
|
||||
if (actor.uri !== uri) {
|
||||
return `skip: delete actor ${actor.uri} !== ${uri}`;
|
||||
@ -461,7 +461,7 @@ export class ApInboxService {
|
||||
|
||||
const user = await this.usersRepository.findOneByOrFail({ id: actor.id });
|
||||
if (user.isDeleted) {
|
||||
this.#logger.info('skip: already deleted');
|
||||
this.logger.info('skip: already deleted');
|
||||
}
|
||||
|
||||
const job = await this.queueService.createDeleteAccountJob(actor);
|
||||
@ -473,8 +473,8 @@ export class ApInboxService {
|
||||
return `ok: queued ${job.name} ${job.id}`;
|
||||
}
|
||||
|
||||
async #deleteNote(actor: CacheableRemoteUser, uri: string): Promise<string> {
|
||||
this.#logger.info(`Deleting the Note: ${uri}`);
|
||||
private async deleteNote(actor: CacheableRemoteUser, uri: string): Promise<string> {
|
||||
this.logger.info(`Deleting the Note: ${uri}`);
|
||||
|
||||
const unlock = await this.appLockService.getApLock(uri);
|
||||
|
||||
@ -505,7 +505,7 @@ export class ApInboxService {
|
||||
}
|
||||
}
|
||||
|
||||
async #flag(actor: CacheableRemoteUser, activity: IFlag): Promise<string> {
|
||||
private async flag(actor: CacheableRemoteUser, activity: IFlag): Promise<string> {
|
||||
// objectは `(User|Note) | (User|Note)[]` だけど、全パターンDBスキーマと対応させられないので
|
||||
// 対象ユーザーは一番最初のユーザー として あとはコメントとして格納する
|
||||
const uris = getApIds(activity.object);
|
||||
@ -529,24 +529,24 @@ export class ApInboxService {
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
async #reject(actor: CacheableRemoteUser, activity: IReject): Promise<string> {
|
||||
private async reject(actor: CacheableRemoteUser, activity: IReject): Promise<string> {
|
||||
const uri = activity.id ?? activity;
|
||||
|
||||
this.#logger.info(`Reject: ${uri}`);
|
||||
this.logger.info(`Reject: ${uri}`);
|
||||
|
||||
const resolver = this.apResolverService.createResolver();
|
||||
|
||||
const object = await resolver.resolve(activity.object).catch(e => {
|
||||
this.#logger.error(`Resolution failed: ${e}`);
|
||||
this.logger.error(`Resolution failed: ${e}`);
|
||||
throw e;
|
||||
});
|
||||
|
||||
if (isFollow(object)) return await this.#rejectFollow(actor, object);
|
||||
if (isFollow(object)) return await this.rejectFollow(actor, object);
|
||||
|
||||
return `skip: Unknown Reject type: ${getApType(object)}`;
|
||||
}
|
||||
|
||||
async #rejectFollow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
||||
private async rejectFollow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
||||
// ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある
|
||||
|
||||
const follower = await this.apDbResolverService.getUserFromApId(activity.actor);
|
||||
@ -569,7 +569,7 @@ export class ApInboxService {
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
async #remove(actor: CacheableRemoteUser, activity: IRemove): Promise<void> {
|
||||
private async remove(actor: CacheableRemoteUser, activity: IRemove): Promise<void> {
|
||||
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||
throw new Error('invalid actor');
|
||||
}
|
||||
@ -588,32 +588,32 @@ export class ApInboxService {
|
||||
throw new Error(`unknown target: ${activity.target}`);
|
||||
}
|
||||
|
||||
async #undo(actor: CacheableRemoteUser, activity: IUndo): Promise<string> {
|
||||
private async undo(actor: CacheableRemoteUser, activity: IUndo): Promise<string> {
|
||||
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||
throw new Error('invalid actor');
|
||||
}
|
||||
|
||||
const uri = activity.id ?? activity;
|
||||
|
||||
this.#logger.info(`Undo: ${uri}`);
|
||||
this.logger.info(`Undo: ${uri}`);
|
||||
|
||||
const resolver = this.apResolverService.createResolver();
|
||||
|
||||
const object = await resolver.resolve(activity.object).catch(e => {
|
||||
this.#logger.error(`Resolution failed: ${e}`);
|
||||
this.logger.error(`Resolution failed: ${e}`);
|
||||
throw e;
|
||||
});
|
||||
|
||||
if (isFollow(object)) return await this.#undoFollow(actor, object);
|
||||
if (isBlock(object)) return await this.#undoBlock(actor, object);
|
||||
if (isLike(object)) return await this.#undoLike(actor, object);
|
||||
if (isAnnounce(object)) return await this.#undoAnnounce(actor, object);
|
||||
if (isAccept(object)) return await this.#undoAccept(actor, object);
|
||||
if (isFollow(object)) return await this.undoFollow(actor, object);
|
||||
if (isBlock(object)) return await this.undoBlock(actor, object);
|
||||
if (isLike(object)) return await this.undoLike(actor, object);
|
||||
if (isAnnounce(object)) return await this.undoAnnounce(actor, object);
|
||||
if (isAccept(object)) return await this.undoAccept(actor, object);
|
||||
|
||||
return `skip: unknown object type ${getApType(object)}`;
|
||||
}
|
||||
|
||||
async #undoAccept(actor: CacheableRemoteUser, activity: IAccept): Promise<string> {
|
||||
private async undoAccept(actor: CacheableRemoteUser, activity: IAccept): Promise<string> {
|
||||
const follower = await this.apDbResolverService.getUserFromApId(activity.object);
|
||||
if (follower == null) {
|
||||
return 'skip: follower not found';
|
||||
@ -632,7 +632,7 @@ export class ApInboxService {
|
||||
return 'skip: フォローされていない';
|
||||
}
|
||||
|
||||
async #undoAnnounce(actor: CacheableRemoteUser, activity: IAnnounce): Promise<string> {
|
||||
private async undoAnnounce(actor: CacheableRemoteUser, activity: IAnnounce): Promise<string> {
|
||||
const uri = getApId(activity);
|
||||
|
||||
const note = await this.notesRepository.findOneBy({
|
||||
@ -646,7 +646,7 @@ export class ApInboxService {
|
||||
return 'ok: deleted';
|
||||
}
|
||||
|
||||
async #undoBlock(actor: CacheableRemoteUser, activity: IBlock): Promise<string> {
|
||||
private async undoBlock(actor: CacheableRemoteUser, activity: IBlock): Promise<string> {
|
||||
const blockee = await this.apDbResolverService.getUserFromApId(activity.object);
|
||||
|
||||
if (blockee == null) {
|
||||
@ -661,7 +661,7 @@ export class ApInboxService {
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
async #undoFollow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
||||
private async undoFollow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
||||
const followee = await this.apDbResolverService.getUserFromApId(activity.object);
|
||||
if (followee == null) {
|
||||
return 'skip: followee not found';
|
||||
@ -694,7 +694,7 @@ export class ApInboxService {
|
||||
return 'skip: リクエストもフォローもされていない';
|
||||
}
|
||||
|
||||
async #undoLike(actor: CacheableRemoteUser, activity: ILike): Promise<string> {
|
||||
private async undoLike(actor: CacheableRemoteUser, activity: ILike): Promise<string> {
|
||||
const targetUri = getApId(activity.object);
|
||||
|
||||
const note = await this.apNoteService.fetchNote(targetUri);
|
||||
@ -708,17 +708,17 @@ export class ApInboxService {
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
async #update(actor: CacheableRemoteUser, activity: IUpdate): Promise<string> {
|
||||
private async update(actor: CacheableRemoteUser, activity: IUpdate): Promise<string> {
|
||||
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||
return 'skip: invalid actor';
|
||||
}
|
||||
|
||||
this.#logger.debug('Update');
|
||||
this.logger.debug('Update');
|
||||
|
||||
const resolver = this.apResolverService.createResolver();
|
||||
|
||||
const object = await resolver.resolve(activity.object).catch(e => {
|
||||
this.#logger.error(`Resolution failed: ${e}`);
|
||||
this.logger.error(`Resolution failed: ${e}`);
|
||||
throw e;
|
||||
});
|
||||
|
||||
|
@ -365,7 +365,7 @@ export class ApRendererService {
|
||||
text: apText,
|
||||
}));
|
||||
|
||||
const emojis = await this.#getEmojis(note.emojis);
|
||||
const emojis = await this.getEmojis(note.emojis);
|
||||
const apemojis = emojis.map(emoji => this.renderEmoji(emoji));
|
||||
|
||||
const tag = [
|
||||
@ -448,7 +448,7 @@ export class ApRendererService {
|
||||
}
|
||||
}
|
||||
|
||||
const emojis = await this.#getEmojis(user.emojis);
|
||||
const emojis = await this.getEmojis(user.emojis);
|
||||
const apemojis = emojis.map(emoji => this.renderEmoji(emoji));
|
||||
|
||||
const hashtagTags = (user.tags ?? []).map(tag => this.renderHashtag(tag));
|
||||
@ -687,7 +687,7 @@ export class ApRendererService {
|
||||
return page;
|
||||
}
|
||||
|
||||
async #getEmojis(names: string[]): Promise<Emoji[]> {
|
||||
private async getEmojis(names: string[]): Promise<Emoji[]> {
|
||||
if (names == null || names.length === 0) return [];
|
||||
|
||||
const emojis = await Promise.all(
|
||||
|
@ -36,14 +36,14 @@ export class ApRequestService {
|
||||
) {
|
||||
}
|
||||
|
||||
#createSignedPost(args: { key: PrivateKey, url: string, body: string, additionalHeaders: Record<string, string> }): Signed {
|
||||
private createSignedPost(args: { key: PrivateKey, url: string, body: string, additionalHeaders: Record<string, string> }): Signed {
|
||||
const u = new URL(args.url);
|
||||
const digestHeader = `SHA-256=${crypto.createHash('sha256').update(args.body).digest('base64')}`;
|
||||
|
||||
const request: Request = {
|
||||
url: u.href,
|
||||
method: 'POST',
|
||||
headers: this.#objectAssignWithLcKey({
|
||||
headers: this.objectAssignWithLcKey({
|
||||
'Date': new Date().toUTCString(),
|
||||
'Host': u.hostname,
|
||||
'Content-Type': 'application/activity+json',
|
||||
@ -51,7 +51,7 @@ export class ApRequestService {
|
||||
}, args.additionalHeaders),
|
||||
};
|
||||
|
||||
const result = this.#signToRequest(request, args.key, ['(request-target)', 'date', 'host', 'digest']);
|
||||
const result = this.signToRequest(request, args.key, ['(request-target)', 'date', 'host', 'digest']);
|
||||
|
||||
return {
|
||||
request,
|
||||
@ -61,20 +61,20 @@ export class ApRequestService {
|
||||
};
|
||||
}
|
||||
|
||||
#createSignedGet(args: { key: PrivateKey, url: string, additionalHeaders: Record<string, string> }): Signed {
|
||||
private createSignedGet(args: { key: PrivateKey, url: string, additionalHeaders: Record<string, string> }): Signed {
|
||||
const u = new URL(args.url);
|
||||
|
||||
const request: Request = {
|
||||
url: u.href,
|
||||
method: 'GET',
|
||||
headers: this.#objectAssignWithLcKey({
|
||||
headers: this.objectAssignWithLcKey({
|
||||
'Accept': 'application/activity+json, application/ld+json',
|
||||
'Date': new Date().toUTCString(),
|
||||
'Host': new URL(args.url).hostname,
|
||||
}, args.additionalHeaders),
|
||||
};
|
||||
|
||||
const result = this.#signToRequest(request, args.key, ['(request-target)', 'date', 'host', 'accept']);
|
||||
const result = this.signToRequest(request, args.key, ['(request-target)', 'date', 'host', 'accept']);
|
||||
|
||||
return {
|
||||
request,
|
||||
@ -84,12 +84,12 @@ export class ApRequestService {
|
||||
};
|
||||
}
|
||||
|
||||
#signToRequest(request: Request, key: PrivateKey, includeHeaders: string[]): Signed {
|
||||
const signingString = this.#genSigningString(request, includeHeaders);
|
||||
private signToRequest(request: Request, key: PrivateKey, includeHeaders: string[]): Signed {
|
||||
const signingString = this.genSigningString(request, includeHeaders);
|
||||
const signature = crypto.sign('sha256', Buffer.from(signingString), key.privateKeyPem).toString('base64');
|
||||
const signatureHeader = `keyId="${key.keyId}",algorithm="rsa-sha256",headers="${includeHeaders.join(' ')}",signature="${signature}"`;
|
||||
|
||||
request.headers = this.#objectAssignWithLcKey(request.headers, {
|
||||
request.headers = this.objectAssignWithLcKey(request.headers, {
|
||||
Signature: signatureHeader,
|
||||
});
|
||||
|
||||
@ -101,8 +101,8 @@ export class ApRequestService {
|
||||
};
|
||||
}
|
||||
|
||||
#genSigningString(request: Request, includeHeaders: string[]): string {
|
||||
request.headers = this.#lcObjectKey(request.headers);
|
||||
private genSigningString(request: Request, includeHeaders: string[]): string {
|
||||
request.headers = this.lcObjectKey(request.headers);
|
||||
|
||||
const results: string[] = [];
|
||||
|
||||
@ -117,14 +117,14 @@ export class ApRequestService {
|
||||
return results.join('\n');
|
||||
}
|
||||
|
||||
#lcObjectKey(src: Record<string, string>): Record<string, string> {
|
||||
private lcObjectKey(src: Record<string, string>): Record<string, string> {
|
||||
const dst: Record<string, string> = {};
|
||||
for (const key of Object.keys(src).filter(x => x !== '__proto__' && typeof src[x] === 'string')) dst[key.toLowerCase()] = src[key];
|
||||
return dst;
|
||||
}
|
||||
|
||||
#objectAssignWithLcKey(a: Record<string, string>, b: Record<string, string>): Record<string, string> {
|
||||
return Object.assign(this.#lcObjectKey(a), this.#lcObjectKey(b));
|
||||
private objectAssignWithLcKey(a: Record<string, string>, b: Record<string, string>): Record<string, string> {
|
||||
return Object.assign(this.lcObjectKey(a), this.lcObjectKey(b));
|
||||
}
|
||||
|
||||
public async signedPost(user: { id: User['id'] }, url: string, object: any) {
|
||||
@ -132,7 +132,7 @@ export class ApRequestService {
|
||||
|
||||
const keypair = await this.userKeypairStoreService.getUserKeypair(user.id);
|
||||
|
||||
const req = this.#createSignedPost({
|
||||
const req = this.createSignedPost({
|
||||
key: {
|
||||
privateKeyPem: keypair.privateKey,
|
||||
keyId: `${this.config.url}/users/${user.id}#main-key`,
|
||||
@ -160,7 +160,7 @@ export class ApRequestService {
|
||||
public async signedGet(url: string, user: { id: User['id'] }) {
|
||||
const keypair = await this.userKeypairStoreService.getUserKeypair(user.id);
|
||||
|
||||
const req = this.#createSignedGet({
|
||||
const req = this.createSignedGet({
|
||||
key: {
|
||||
privateKeyPem: keypair.privateKey,
|
||||
keyId: `${this.config.url}/users/${user.id}#main-key`,
|
||||
|
@ -14,7 +14,7 @@ import { ApLoggerService } from '../ApLoggerService.js';
|
||||
|
||||
@Injectable()
|
||||
export class ApImageService {
|
||||
#logger: Logger;
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
@ -28,7 +28,7 @@ export class ApImageService {
|
||||
private driveService: DriveService,
|
||||
private apLoggerService: ApLoggerService,
|
||||
) {
|
||||
this.#logger = this.apLoggerService.logger;
|
||||
this.logger = this.apLoggerService.logger;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -46,7 +46,7 @@ export class ApImageService {
|
||||
throw new Error('invalid image: url not privided');
|
||||
}
|
||||
|
||||
this.#logger.info(`Creating the Image: ${image.url}`);
|
||||
this.logger.info(`Creating the Image: ${image.url}`);
|
||||
|
||||
const instance = await this.metaService.fetch();
|
||||
|
||||
|
@ -35,7 +35,7 @@ import type { IObject, IPost } from '../type.js';
|
||||
|
||||
@Injectable()
|
||||
export class ApNoteService {
|
||||
#logger: Logger;
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
@ -71,7 +71,7 @@ export class ApNoteService {
|
||||
private apDbResolverService: ApDbResolverService,
|
||||
private apLoggerService: ApLoggerService,
|
||||
) {
|
||||
this.#logger = this.apLoggerService.logger;
|
||||
this.logger = this.apLoggerService.logger;
|
||||
}
|
||||
|
||||
public validateNote(object: any, uri: string) {
|
||||
@ -116,7 +116,7 @@ export class ApNoteService {
|
||||
const entryUri = getApId(value);
|
||||
const err = this.validateNote(object, entryUri);
|
||||
if (err) {
|
||||
this.#logger.error(`${err.message}`, {
|
||||
this.logger.error(`${err.message}`, {
|
||||
resolver: {
|
||||
history: resolver.getHistory(),
|
||||
},
|
||||
@ -128,9 +128,9 @@ export class ApNoteService {
|
||||
|
||||
const note: IPost = object;
|
||||
|
||||
this.#logger.debug(`Note fetched: ${JSON.stringify(note, null, 2)}`);
|
||||
this.logger.debug(`Note fetched: ${JSON.stringify(note, null, 2)}`);
|
||||
|
||||
this.#logger.info(`Creating the Note: ${note.id}`);
|
||||
this.logger.info(`Creating the Note: ${note.id}`);
|
||||
|
||||
// 投稿者をフェッチ
|
||||
const actor = await this.apPersonService.resolvePerson(getOneApId(note.attributedTo), resolver) as CacheableRemoteUser;
|
||||
@ -174,7 +174,7 @@ export class ApNoteService {
|
||||
const reply: Note | null = note.inReplyTo
|
||||
? await this.resolveNote(note.inReplyTo, resolver).then(x => {
|
||||
if (x == null) {
|
||||
this.#logger.warn('Specified inReplyTo, but nout found');
|
||||
this.logger.warn('Specified inReplyTo, but nout found');
|
||||
throw new Error('inReplyTo not found');
|
||||
} else {
|
||||
return x;
|
||||
@ -191,7 +191,7 @@ export class ApNoteService {
|
||||
}
|
||||
}
|
||||
|
||||
this.#logger.warn(`Error in inReplyTo ${note.inReplyTo} - ${err.statusCode ?? err}`);
|
||||
this.logger.warn(`Error in inReplyTo ${note.inReplyTo} - ${err.statusCode ?? err}`);
|
||||
throw err;
|
||||
})
|
||||
: null;
|
||||
@ -255,9 +255,9 @@ export class ApNoteService {
|
||||
|
||||
const tryCreateVote = async (name: string, index: number): Promise<null> => {
|
||||
if (poll.expiresAt && Date.now() > new Date(poll.expiresAt).getTime()) {
|
||||
this.#logger.warn(`vote to expired poll from AP: actor=${actor.username}@${actor.host}, note=${note.id}, choice=${name}`);
|
||||
this.logger.warn(`vote to expired poll from AP: actor=${actor.username}@${actor.host}, note=${note.id}, choice=${name}`);
|
||||
} else if (index >= 0) {
|
||||
this.#logger.info(`vote from AP: actor=${actor.username}@${actor.host}, note=${note.id}, choice=${name}`);
|
||||
this.logger.info(`vote from AP: actor=${actor.username}@${actor.host}, note=${note.id}, choice=${name}`);
|
||||
await this.pollService.vote(actor, reply, index);
|
||||
|
||||
// リモートフォロワーにUpdate配信
|
||||
@ -272,7 +272,7 @@ export class ApNoteService {
|
||||
}
|
||||
|
||||
const emojis = await this.extractEmojis(note.tag ?? [], actor.host).catch(e => {
|
||||
this.#logger.info(`extractEmojis: ${e}`);
|
||||
this.logger.info(`extractEmojis: ${e}`);
|
||||
return [] as Emoji[];
|
||||
});
|
||||
|
||||
@ -386,7 +386,7 @@ export class ApNoteService {
|
||||
return exists;
|
||||
}
|
||||
|
||||
this.#logger.info(`register emoji host=${host}, name=${name}`);
|
||||
this.logger.info(`register emoji host=${host}, name=${name}`);
|
||||
|
||||
return await this.emojisRepository.insert({
|
||||
id: this.idService.genId(),
|
||||
|
@ -91,7 +91,7 @@ export class ApPersonService implements OnModuleInit {
|
||||
private usersChart: UsersChart;
|
||||
private instanceChart: InstanceChart;
|
||||
private apLoggerService: ApLoggerService;
|
||||
#logger: Logger;
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
private moduleRef: ModuleRef,
|
||||
@ -153,7 +153,7 @@ export class ApPersonService implements OnModuleInit {
|
||||
this.usersChart = this.moduleRef.get('UsersChart');
|
||||
this.instanceChart = this.moduleRef.get('InstanceChart');
|
||||
this.apLoggerService = this.moduleRef.get('ApLoggerService');
|
||||
this.#logger = this.apLoggerService.logger;
|
||||
this.logger = this.apLoggerService.logger;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -161,7 +161,7 @@ export class ApPersonService implements OnModuleInit {
|
||||
* @param x Fetched object
|
||||
* @param uri Fetch target URI
|
||||
*/
|
||||
#validateActor(x: IObject, uri: string): IActor {
|
||||
private validateActor(x: IObject, uri: string): IActor {
|
||||
const expectHost = this.utilityService.toPuny(new URL(uri).hostname);
|
||||
|
||||
if (x == null) {
|
||||
@ -264,9 +264,9 @@ export class ApPersonService implements OnModuleInit {
|
||||
|
||||
const object = await resolver.resolve(uri) as any;
|
||||
|
||||
const person = this.#validateActor(object, uri);
|
||||
const person = this.validateActor(object, uri);
|
||||
|
||||
this.#logger.info(`Creating the Person: ${person.id}`);
|
||||
this.logger.info(`Creating the Person: ${person.id}`);
|
||||
|
||||
const host = this.utilityService.toPuny(new URL(object.id).hostname);
|
||||
|
||||
@ -338,7 +338,7 @@ export class ApPersonService implements OnModuleInit {
|
||||
throw new Error('already registered');
|
||||
}
|
||||
} else {
|
||||
this.#logger.error(e instanceof Error ? e : new Error(e as string));
|
||||
this.logger.error(e instanceof Error ? e : new Error(e as string));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@ -379,7 +379,7 @@ export class ApPersonService implements OnModuleInit {
|
||||
|
||||
//#region カスタム絵文字取得
|
||||
const emojis = await this.apNoteService.extractEmojis(person.tag ?? [], host).catch(err => {
|
||||
this.#logger.info(`extractEmojis: ${err}`);
|
||||
this.logger.info(`extractEmojis: ${err}`);
|
||||
return [] as Emoji[];
|
||||
});
|
||||
|
||||
@ -390,7 +390,7 @@ export class ApPersonService implements OnModuleInit {
|
||||
});
|
||||
//#endregion
|
||||
|
||||
await this.updateFeatured(user!.id).catch(err => this.#logger.error(err));
|
||||
await this.updateFeatured(user!.id).catch(err => this.logger.error(err));
|
||||
|
||||
return user!;
|
||||
}
|
||||
@ -422,9 +422,9 @@ export class ApPersonService implements OnModuleInit {
|
||||
|
||||
const object = hint ?? await resolver.resolve(uri);
|
||||
|
||||
const person = this.#validateActor(object, uri);
|
||||
const person = this.validateActor(object, uri);
|
||||
|
||||
this.#logger.info(`Updating the Person: ${person.id}`);
|
||||
this.logger.info(`Updating the Person: ${person.id}`);
|
||||
|
||||
// アバターとヘッダー画像をフェッチ
|
||||
const [avatar, banner] = await Promise.all([
|
||||
@ -438,7 +438,7 @@ export class ApPersonService implements OnModuleInit {
|
||||
|
||||
// カスタム絵文字取得
|
||||
const emojis = await this.apNoteService.extractEmojis(person.tag ?? [], exist.host).catch(e => {
|
||||
this.#logger.info(`extractEmojis: ${e}`);
|
||||
this.logger.info(`extractEmojis: ${e}`);
|
||||
return [] as Emoji[];
|
||||
});
|
||||
|
||||
@ -503,7 +503,7 @@ export class ApPersonService implements OnModuleInit {
|
||||
followerSharedInbox: person.sharedInbox ?? (person.endpoints ? person.endpoints.sharedInbox : undefined),
|
||||
});
|
||||
|
||||
await this.updateFeatured(exist.id).catch(err => this.#logger.error(err));
|
||||
await this.updateFeatured(exist.id).catch(err => this.logger.error(err));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -556,7 +556,7 @@ export class ApPersonService implements OnModuleInit {
|
||||
if (!this.userEntityService.isRemoteUser(user)) return;
|
||||
if (!user.featured) return;
|
||||
|
||||
this.#logger.info(`Updating the featured: ${user.uri}`);
|
||||
this.logger.info(`Updating the featured: ${user.uri}`);
|
||||
|
||||
const resolver = this.apResolverService.createResolver();
|
||||
|
||||
|
@ -12,7 +12,7 @@ import type { IObject, IQuestion } from '../type.js';
|
||||
|
||||
@Injectable()
|
||||
export class ApQuestionService {
|
||||
#logger: Logger;
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
@ -27,7 +27,7 @@ export class ApQuestionService {
|
||||
private apResolverService: ApResolverService,
|
||||
private apLoggerService: ApLoggerService,
|
||||
) {
|
||||
this.#logger = this.apLoggerService.logger;
|
||||
this.logger = this.apLoggerService.logger;
|
||||
}
|
||||
|
||||
public async extractPollFromQuestion(source: string | IObject, resolver?: Resolver): Promise<IPoll> {
|
||||
@ -82,7 +82,7 @@ export class ApQuestionService {
|
||||
// resolve new Question object
|
||||
const resolver = this.apResolverService.createResolver();
|
||||
const question = await resolver.resolve(value) as IQuestion;
|
||||
this.#logger.debug(`fetched question: ${JSON.stringify(question, null, 2)}`);
|
||||
this.logger.debug(`fetched question: ${JSON.stringify(question, null, 2)}`);
|
||||
|
||||
if (question.type !== 'Question') throw new Error('object is not a Question');
|
||||
|
||||
|
Reference in New Issue
Block a user