Merge remote-tracking branch 'origin/develop' into fetch-outbox

This commit is contained in:
Kagami Sascha Rosylight
2023-07-06 03:38:13 +02:00
18 changed files with 183 additions and 69 deletions

View File

@@ -8,7 +8,7 @@ import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import type { Antenna } from '@/server/api/endpoints/i/import-antennas.js';
import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, RelationshipQueue, SystemQueue, WebhookDeliverQueue } from './QueueModule.js';
import type { DbJobData, RelationshipJobData, ThinUser } from '../queue/types.js';
import type { DbJobData, DeliverJobData, RelationshipJobData, ThinUser } from '../queue/types.js';
import type httpSignature from '@peertube/http-signature';
import type * as Bull from 'bullmq';
@@ -69,7 +69,7 @@ export class QueueService {
if (content == null) return null;
if (to == null) return null;
const data = {
const data: DeliverJobData = {
user: {
id: user.id,
},
@@ -88,6 +88,38 @@ export class QueueService {
});
}
/**
* ApDeliverManager-DeliverManager.execute()からinboxesを突っ込んでaddBulkしたい
* @param user `{ id: string; }` この関数ではThinUserに変換しないので前もって変換してください
* @param content IActivity | null
* @param inboxes `Map<string, boolean>` / key: to (inbox url), value: isSharedInbox (whether it is sharedInbox)
* @returns void
*/
@bindThis
public async deliverMany(user: ThinUser, content: IActivity | null, inboxes: Map<string, boolean>) {
const opts = {
attempts: this.config.deliverJobMaxAttempts ?? 12,
backoff: {
type: 'custom',
},
removeOnComplete: true,
removeOnFail: true,
};
await this.deliverQueue.addBulk(Array.from(inboxes.entries()).map(d => ({
name: d[0],
data: {
user,
content,
to: d[0],
isSharedInbox: d[1],
} as DeliverJobData,
opts,
})));
return;
}
@bindThis
public inbox(activity: IActivity, signature: httpSignature.IParsedSignature) {
const data = {

View File

@@ -1,5 +1,4 @@
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
import escapeRegexp from 'escape-regexp';
import { DI } from '@/di-symbols.js';
import type { NotesRepository, UserPublickeysRepository, UsersRepository } from '@/models/index.js';
import type { Config } from '@/config.js';
@@ -56,25 +55,18 @@ export class ApDbResolverService implements OnApplicationShutdown {
@bindThis
public parseUri(value: string | IObject): UriParseResult {
const uri = getApId(value);
// the host part of a URL is case insensitive, so use the 'i' flag.
const localRegex = new RegExp('^' + escapeRegexp(this.config.url) + '/(\\w+)/(\\w+)(?:\/(.+))?', 'i');
const matchLocal = uri.match(localRegex);
if (matchLocal) {
return {
local: true,
type: matchLocal[1],
id: matchLocal[2],
rest: matchLocal[3],
};
} else {
return {
local: false,
uri,
};
}
const separator = '/';
const uri = new URL(getApId(value));
if (uri.origin !== this.config.url) return { local: false, uri: uri.href };
const [, type, id, ...rest] = uri.pathname.split(separator);
return {
local: true,
type,
id,
rest: rest.length === 0 ? undefined : rest.join(separator),
};
}
/**

View File

@@ -7,6 +7,8 @@ import type { LocalUser, RemoteUser, User } from '@/models/entities/User.js';
import { QueueService } from '@/core/QueueService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js';
import type { IActivity } from '@/core/activitypub/type.js';
import { ThinUser } from '@/queue/types.js';
interface IRecipe {
type: string;
@@ -21,10 +23,10 @@ interface IDirectRecipe extends IRecipe {
to: RemoteUser;
}
const isFollowers = (recipe: any): recipe is IFollowersRecipe =>
const isFollowers = (recipe: IRecipe): recipe is IFollowersRecipe =>
recipe.type === 'Followers';
const isDirect = (recipe: any): recipe is IDirectRecipe =>
const isDirect = (recipe: IRecipe): recipe is IDirectRecipe =>
recipe.type === 'Direct';
@Injectable()
@@ -46,11 +48,11 @@ export class ApDeliverManagerService {
/**
* Deliver activity to followers
* @param actor
* @param activity Activity
* @param from Followee
*/
@bindThis
public async deliverToFollowers(actor: { id: LocalUser['id']; host: null; }, activity: any) {
public async deliverToFollowers(actor: { id: LocalUser['id']; host: null; }, activity: IActivity) {
const manager = new DeliverManager(
this.userEntityService,
this.followingsRepository,
@@ -64,11 +66,12 @@ export class ApDeliverManagerService {
/**
* Deliver activity to user
* @param actor
* @param activity Activity
* @param to Target user
*/
@bindThis
public async deliverToUser(actor: { id: LocalUser['id']; host: null; }, activity: any, to: RemoteUser) {
public async deliverToUser(actor: { id: LocalUser['id']; host: null; }, activity: IActivity, to: RemoteUser) {
const manager = new DeliverManager(
this.userEntityService,
this.followingsRepository,
@@ -81,7 +84,7 @@ export class ApDeliverManagerService {
}
@bindThis
public createDeliverManager(actor: { id: User['id']; host: null; }, activity: any) {
public createDeliverManager(actor: { id: User['id']; host: null; }, activity: IActivity | null) {
return new DeliverManager(
this.userEntityService,
this.followingsRepository,
@@ -94,12 +97,15 @@ export class ApDeliverManagerService {
}
class DeliverManager {
private actor: { id: User['id']; host: null; };
private activity: any;
private actor: ThinUser;
private activity: IActivity | null;
private recipes: IRecipe[] = [];
/**
* Constructor
* @param userEntityService
* @param followingsRepository
* @param queueService
* @param actor Actor
* @param activity Activity to deliver
*/
@@ -109,9 +115,15 @@ class DeliverManager {
private queueService: QueueService,
actor: { id: User['id']; host: null; },
activity: any,
activity: IActivity | null,
) {
this.actor = actor;
// 型で弾いてはいるが一応ローカルユーザーかチェック
if (actor.host != null) throw new Error('actor.host must be null');
// パフォーマンス向上のためキューに突っ込むのはidのみに絞る
this.actor = {
id: actor.id,
};
this.activity = activity;
}
@@ -155,9 +167,8 @@ class DeliverManager {
*/
@bindThis
public async execute() {
if (!this.userEntityService.isLocalUser(this.actor)) return;
// The value flags whether it is shared or not.
// key: inbox URL, value: whether it is sharedInbox
const inboxes = new Map<string, boolean>();
/*
@@ -201,9 +212,6 @@ class DeliverManager {
.forEach(recipe => inboxes.set(recipe.to.inbox!, false));
// deliver
for (const inbox of inboxes) {
// inbox[0]: inbox, inbox[1]: whether it is sharedInbox
this.queueService.deliver(this.actor, this.activity, inbox[0], inbox[1]);
}
this.queueService.deliverMany(this.actor, this.activity, inboxes);
}
}

View File

@@ -47,4 +47,4 @@ html
header#banner(style=`background-image: url(${meta.bannerUrl})`)
div#title= meta.name || host
div#content
div#description= meta.description
div#description!= meta.description