Merge branch 'develop' into feature/misskey-2024.07

fixing conflicts in `package.json`
This commit is contained in:
dakkar 2024-08-06 10:35:14 +01:00
commit 34c1e9ea2b
12 changed files with 49 additions and 21 deletions

View File

@ -22,7 +22,7 @@
"build": "pnpm build-pre && pnpm -r build && pnpm build-assets", "build": "pnpm build-pre && pnpm -r build && pnpm build-assets",
"build-storybook": "pnpm --filter frontend build-storybook", "build-storybook": "pnpm --filter frontend build-storybook",
"build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api", "build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
"start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js", "start": "pnpm check:connect && cd packages/backend && MK_WARNED_ABOUT_CONFIG=true node ./built/boot/entry.js",
"start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js", "start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js",
"init": "pnpm migrate", "init": "pnpm migrate",
"migrate": "cd packages/backend && pnpm migrate", "migrate": "cd packages/backend && pnpm migrate",

View File

@ -112,6 +112,11 @@ export async function masterMain() {
await server(); await server();
} }
if (config.clusterLimit === 0) {
bootLogger.error("Configuration error: we can't create workers, `config.clusterLimit` is 0 (if you don't want to use clustering, set the environment variable `MK_DISABLE_CLUSTERING` to a non-empty value instead)", null, true);
process.exit(1);
}
await spawnWorkers(config.clusterLimit); await spawnWorkers(config.clusterLimit);
} }
@ -180,7 +185,10 @@ async function connectDb(): Promise<void> {
*/ */
async function spawnWorkers(limit = 1) { async function spawnWorkers(limit = 1) {
const workers = Math.min(limit, os.cpus().length); const cpuCount = os.cpus().length;
// in some weird environments, node can't count the CPUs; we trust the config in those cases
const workers = cpuCount === 0 ? limit : Math.min(limit, cpuCount);
bootLogger.info(`Starting ${workers} worker${workers === 1 ? '' : 's'}...`); bootLogger.info(`Starting ${workers} worker${workers === 1 ? '' : 's'}...`);
await Promise.all([...Array(workers)].map(spawnWorker)); await Promise.all([...Array(workers)].map(spawnWorker));
bootLogger.succ('All workers started'); bootLogger.succ('All workers started');

View File

@ -12,9 +12,10 @@ import * as Sentry from '@sentry/node';
import type { RedisOptions } from 'ioredis'; import type { RedisOptions } from 'ioredis';
type RedisOptionsSource = Partial<RedisOptions> & { type RedisOptionsSource = Partial<RedisOptions> & {
host: string; host?: string;
port: number; port?: number;
family?: number; family?: number;
path?: string,
pass: string; pass: string;
db?: number; db?: number;
prefix?: string; prefix?: string;
@ -221,8 +222,15 @@ export function loadConfig(): Config {
JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_vite_/manifest.json`, 'utf-8')) JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_vite_/manifest.json`, 'utf-8'))
: { 'src/_boot_.ts': { file: 'src/_boot_.ts' } }; : { 'src/_boot_.ts': { file: 'src/_boot_.ts' } };
const config = globSync(path).sort() const configFiles = globSync(path).sort();
.map(path => fs.readFileSync(path, 'utf-8'))
if (configFiles.length === 0
&& !process.env['MK_WARNED_ABOUT_CONFIG']) {
console.log('No config files loaded, check if this is intentional');
process.env['MK_WARNED_ABOUT_CONFIG'] = true;
}
const config = configFiles.map(path => fs.readFileSync(path, 'utf-8'))
.map(contents => yaml.load(contents) as Source) .map(contents => yaml.load(contents) as Source)
.reduce( .reduce(
(acc: Source, cur: Source) => Object.assign(acc, cur), (acc: Source, cur: Source) => Object.assign(acc, cur),
@ -252,7 +260,7 @@ export function loadConfig(): Config {
version, version,
publishTarballInsteadOfProvideRepositoryUrl: !!config.publishTarballInsteadOfProvideRepositoryUrl, publishTarballInsteadOfProvideRepositoryUrl: !!config.publishTarballInsteadOfProvideRepositoryUrl,
url: url.origin, url: url.origin,
port: config.port ?? parseInt(process.env.PORT ?? '', 10), port: config.port ?? parseInt(process.env.PORT ?? '3000', 10),
socket: config.socket, socket: config.socket,
chmodSocket: config.chmodSocket, chmodSocket: config.chmodSocket,
disableHsts: config.disableHsts, disableHsts: config.disableHsts,
@ -440,8 +448,8 @@ function applyEnvOverrides(config: Source) {
// these are all the settings that can be overridden // these are all the settings that can be overridden
_apply_top([['url', 'port', 'socket', 'chmodSocket', 'disableHsts']]); _apply_top([['url', 'port', 'socket', 'chmodSocket', 'disableHsts', 'id', 'dbReplications']]);
_apply_top(['db', ['host', 'port', 'db', 'user', 'pass']]); _apply_top(['db', ['host', 'port', 'db', 'user', 'pass', 'disableCache']]);
_apply_top(['dbSlaves', Array.from((config.dbSlaves ?? []).keys()), ['host', 'port', 'db', 'user', 'pass']]); _apply_top(['dbSlaves', Array.from((config.dbSlaves ?? []).keys()), ['host', 'port', 'db', 'user', 'pass']]);
_apply_top([ _apply_top([
['redis', 'redisForPubsub', 'redisForJobQueue', 'redisForTimelines'], ['redis', 'redisForPubsub', 'redisForJobQueue', 'redisForTimelines'],
@ -451,7 +459,8 @@ function applyEnvOverrides(config: Source) {
_apply_top([['sentryForFrontend', 'sentryForBackend'], 'options', ['dsn', 'profileSampleRate', 'serverName', 'includeLocalVariables', 'proxy', 'keepAlive', 'caCerts']]); _apply_top([['sentryForFrontend', 'sentryForBackend'], 'options', ['dsn', 'profileSampleRate', 'serverName', 'includeLocalVariables', 'proxy', 'keepAlive', 'caCerts']]);
_apply_top(['sentryForBackend', 'enableNodeProfiling']); _apply_top(['sentryForBackend', 'enableNodeProfiling']);
_apply_top([['clusterLimit', 'deliverJobConcurrency', 'inboxJobConcurrency', 'relashionshipJobConcurrency', 'deliverJobPerSec', 'inboxJobPerSec', 'relashionshipJobPerSec', 'deliverJobMaxAttempts', 'inboxJobMaxAttempts']]); _apply_top([['clusterLimit', 'deliverJobConcurrency', 'inboxJobConcurrency', 'relashionshipJobConcurrency', 'deliverJobPerSec', 'inboxJobPerSec', 'relashionshipJobPerSec', 'deliverJobMaxAttempts', 'inboxJobMaxAttempts']]);
_apply_top([['outgoingAddress', 'outgoingAddressFamily', 'proxy', 'proxySmtp', 'mediaProxy', 'videoThumbnailGenerator']]); _apply_top([['outgoingAddress', 'outgoingAddressFamily', 'proxy', 'proxySmtp', 'mediaProxy', 'proxyRemoteFiles','videoThumbnailGenerator']]);
_apply_top([['maxFileSize', 'maxNoteLength', 'pidFile']]); _apply_top([['maxFileSize', 'maxNoteLength', 'pidFile']]);
_apply_top(['import', ['downloadTimeout', 'maxFileSize']]); _apply_top(['import', ['downloadTimeout', 'maxFileSize']]);
_apply_top([['signToActivityPubGet', 'checkActivityPubGetSignature']]);
} }

View File

@ -136,6 +136,7 @@ export interface NoteEventTypes {
}; };
replied: { replied: {
id: MiNote['id']; id: MiNote['id'];
userId: MiUser['id'];
}; };
} }
type NoteStreamEventTypes = { type NoteStreamEventTypes = {

View File

@ -833,6 +833,7 @@ export class NoteCreateService implements OnApplicationShutdown {
if (data.reply) { if (data.reply) {
this.globalEventService.publishNoteStream(data.reply.id, 'replied', { this.globalEventService.publishNoteStream(data.reply.id, 'replied', {
id: note.id, id: note.id,
userId: user.id,
}); });
// 通知 // 通知
if (data.reply.userHost === null) { if (data.reply.userHost === null) {

View File

@ -82,7 +82,7 @@ export class ApImageService {
url: image.url, url: image.url,
user: actor, user: actor,
uri: image.url, uri: image.url,
sensitive: image.sensitive, sensitive: !!(image.sensitive),
isLink: !shouldBeCached, isLink: !shouldBeCached,
comment: truncate(image.name ?? undefined, DB_MAX_IMAGE_COMMENT_LENGTH), comment: truncate(image.name ?? undefined, DB_MAX_IMAGE_COMMENT_LENGTH),
}); });

View File

@ -64,8 +64,9 @@ export class InstanceEntityService {
@bindThis @bindThis
public packMany( public packMany(
instances: MiInstance[], instances: MiInstance[],
me?: { id: MiUser['id']; } | null | undefined,
) { ) {
return Promise.all(instances.map(x => this.pack(x))); return Promise.all(instances.map(x => this.pack(x, me)));
} }
} }

View File

@ -240,12 +240,8 @@ export function createPostgresDataSource(config: Config) {
cache: !config.db.disableCache && process.env.NODE_ENV !== 'test' ? { // dbをcloseしても何故かredisのコネクションが内部的に残り続けるようで、テストの際に支障が出るため無効にする(キャッシュも含めてテストしたいため本当は有効にしたいが...) cache: !config.db.disableCache && process.env.NODE_ENV !== 'test' ? { // dbをcloseしても何故かredisのコネクションが内部的に残り続けるようで、テストの際に支障が出るため無効にする(キャッシュも含めてテストしたいため本当は有効にしたいが...)
type: 'ioredis', type: 'ioredis',
options: { options: {
host: config.redis.host, ...config.redis,
port: config.redis.port,
family: config.redis.family ?? 0,
password: config.redis.pass,
keyPrefix: `${config.redis.prefix}:query:`, keyPrefix: `${config.redis.prefix}:query:`,
db: config.redis.db ?? 0,
}, },
} : false, } : false,
logging: log, logging: log,

View File

@ -203,7 +203,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const instances = await query.limit(ps.limit).offset(ps.offset).getMany(); const instances = await query.limit(ps.limit).offset(ps.offset).getMany();
return await this.instanceEntityService.packMany(instances); return await this.instanceEntityService.packMany(instances, me);
}); });
} }
} }

View File

@ -107,9 +107,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const gotPubCount = topPubInstances.map(x => x.followingCount).reduce((a, b) => a + b, 0); const gotPubCount = topPubInstances.map(x => x.followingCount).reduce((a, b) => a + b, 0);
return await awaitAll({ return await awaitAll({
topSubInstances: this.instanceEntityService.packMany(topSubInstances), topSubInstances: this.instanceEntityService.packMany(topSubInstances, me),
otherFollowersCount: Math.max(0, allSubCount - gotSubCount), otherFollowersCount: Math.max(0, allSubCount - gotSubCount),
topPubInstances: this.instanceEntityService.packMany(topPubInstances), topPubInstances: this.instanceEntityService.packMany(topPubInstances, me),
otherFollowingCount: Math.max(0, allPubCount - gotPubCount), otherFollowingCount: Math.max(0, allPubCount - gotPubCount),
}); });
}); });

View File

@ -205,6 +205,18 @@ export default class Connection {
@bindThis @bindThis
private async onNoteStreamMessage(data: GlobalEvents['note']['payload']) { private async onNoteStreamMessage(data: GlobalEvents['note']['payload']) {
// we must not send to the frontend information about notes from
// users who blocked the logged-in user, even when they're replies
// to notes the logged-in user can see
if (data.type === 'replied') {
const noteUserId = data.body.body.userId;
if (noteUserId !== null) {
if (this.userIdsWhoBlockingMe.has(noteUserId)) {
return;
}
}
}
this.sendMessageToWs('noteUpdated', { this.sendMessageToWs('noteUpdated', {
id: data.body.id, id: data.body.id,
type: data.type, type: data.type,

View File

@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
> >
<div v-if="appearNote.reply && inReplyToCollapsed" :class="$style.collapsedInReplyTo"> <div v-if="appearNote.reply && inReplyToCollapsed" :class="$style.collapsedInReplyTo">
<MkAvatar :class="$style.collapsedInReplyToAvatar" :user="appearNote.reply.user" link preview/> <MkAvatar :class="$style.collapsedInReplyToAvatar" :user="appearNote.reply.user" link preview/>
<MkA v-user-preview="note.user.id" :class="$style.name" :to="userPage(note.user)"> <MkA v-user-preview="appearNote.reply.userId" :class="$style.name" :to="userPage(appearNote.reply.user)">
<MkAcct :user="appearNote.reply.user"/> <MkAcct :user="appearNote.reply.user"/>
</MkA>: </MkA>:
<Mfm :text="getNoteSummary(appearNote.reply)" :plain="true" :nowrap="true" :author="appearNote.reply.user" :nyaize="'respect'" :class="$style.collapsedInReplyToText" @click="inReplyToCollapsed = false"/> <Mfm :text="getNoteSummary(appearNote.reply)" :plain="true" :nowrap="true" :author="appearNote.reply.user" :nyaize="'respect'" :class="$style.collapsedInReplyToText" @click="inReplyToCollapsed = false"/>