2022-02-27 03:07:39 +01:00
|
|
|
|
import { Users, Followings } from '@/models/index.js';
|
|
|
|
|
import { ILocalUser, IRemoteUser, User } from '@/models/entities/user.js';
|
|
|
|
|
import { deliver } from '@/queue/index.js';
|
2022-03-26 09:43:08 +01:00
|
|
|
|
import { IsNull, Not } from 'typeorm';
|
2019-11-09 10:51:54 +01:00
|
|
|
|
|
|
|
|
|
//#region types
|
|
|
|
|
interface IRecipe {
|
|
|
|
|
type: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface IFollowersRecipe extends IRecipe {
|
|
|
|
|
type: 'Followers';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface IDirectRecipe extends IRecipe {
|
|
|
|
|
type: 'Direct';
|
|
|
|
|
to: IRemoteUser;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const isFollowers = (recipe: any): recipe is IFollowersRecipe =>
|
|
|
|
|
recipe.type === 'Followers';
|
|
|
|
|
|
|
|
|
|
const isDirect = (recipe: any): recipe is IDirectRecipe =>
|
|
|
|
|
recipe.type === 'Direct';
|
|
|
|
|
//#endregion
|
|
|
|
|
|
|
|
|
|
export default class DeliverManager {
|
2021-03-24 03:05:37 +01:00
|
|
|
|
private actor: { id: User['id']; host: null; };
|
2019-11-09 10:51:54 +01:00
|
|
|
|
private activity: any;
|
|
|
|
|
private recipes: IRecipe[] = [];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor
|
|
|
|
|
* @param actor Actor
|
|
|
|
|
* @param activity Activity to deliver
|
|
|
|
|
*/
|
2021-03-24 03:05:37 +01:00
|
|
|
|
constructor(actor: { id: User['id']; host: null; }, activity: any) {
|
2019-11-09 10:51:54 +01:00
|
|
|
|
this.actor = actor;
|
|
|
|
|
this.activity = activity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add recipe for followers deliver
|
|
|
|
|
*/
|
|
|
|
|
public addFollowersRecipe() {
|
|
|
|
|
const deliver = {
|
2021-12-09 15:58:30 +01:00
|
|
|
|
type: 'Followers',
|
2019-11-09 10:51:54 +01:00
|
|
|
|
} as IFollowersRecipe;
|
|
|
|
|
|
|
|
|
|
this.addRecipe(deliver);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add recipe for direct deliver
|
|
|
|
|
* @param to To
|
|
|
|
|
*/
|
|
|
|
|
public addDirectRecipe(to: IRemoteUser) {
|
|
|
|
|
const recipe = {
|
|
|
|
|
type: 'Direct',
|
2021-12-09 15:58:30 +01:00
|
|
|
|
to,
|
2019-11-09 10:51:54 +01:00
|
|
|
|
} as IDirectRecipe;
|
|
|
|
|
|
|
|
|
|
this.addRecipe(recipe);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add recipe
|
|
|
|
|
* @param recipe Recipe
|
|
|
|
|
*/
|
|
|
|
|
public addRecipe(recipe: IRecipe) {
|
|
|
|
|
this.recipes.push(recipe);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Execute delivers
|
|
|
|
|
*/
|
|
|
|
|
public async execute() {
|
|
|
|
|
if (!Users.isLocalUser(this.actor)) return;
|
|
|
|
|
|
2021-03-21 13:00:59 +01:00
|
|
|
|
const inboxes = new Set<string>();
|
2019-11-09 10:51:54 +01:00
|
|
|
|
|
|
|
|
|
// build inbox list
|
|
|
|
|
for (const recipe of this.recipes) {
|
|
|
|
|
if (isFollowers(recipe)) {
|
|
|
|
|
// followers deliver
|
2022-03-26 09:43:08 +01:00
|
|
|
|
// TODO: SELECT DISTINCT ON ("followerSharedInbox") "followerSharedInbox" みたいな問い合わせにすればよりパフォーマンス向上できそう
|
|
|
|
|
// ただ、sharedInboxがnullなリモートユーザーも稀におり、その対応ができなさそう?
|
|
|
|
|
const followers = await Followings.find({
|
|
|
|
|
where: {
|
|
|
|
|
followeeId: this.actor.id,
|
|
|
|
|
followerHost: Not(IsNull()),
|
|
|
|
|
},
|
|
|
|
|
select: {
|
|
|
|
|
followerSharedInbox: true,
|
|
|
|
|
followerInbox: true,
|
|
|
|
|
},
|
|
|
|
|
}) as {
|
|
|
|
|
followerSharedInbox: string | null;
|
|
|
|
|
followerInbox: string;
|
|
|
|
|
}[];
|
2019-11-09 10:51:54 +01:00
|
|
|
|
|
|
|
|
|
for (const following of followers) {
|
2022-03-26 09:43:08 +01:00
|
|
|
|
const inbox = following.followerSharedInbox || following.followerInbox;
|
|
|
|
|
inboxes.add(inbox);
|
2019-11-09 10:51:54 +01:00
|
|
|
|
}
|
|
|
|
|
} else if (isDirect(recipe)) {
|
|
|
|
|
// direct deliver
|
|
|
|
|
const inbox = recipe.to.inbox;
|
2021-03-21 13:00:59 +01:00
|
|
|
|
if (inbox) inboxes.add(inbox);
|
2019-11-09 10:51:54 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// deliver
|
|
|
|
|
for (const inbox of inboxes) {
|
|
|
|
|
deliver(this.actor, this.activity, inbox);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//#region Utilities
|
|
|
|
|
/**
|
|
|
|
|
* Deliver activity to followers
|
|
|
|
|
* @param activity Activity
|
|
|
|
|
* @param from Followee
|
|
|
|
|
*/
|
2022-03-25 08:27:41 +01:00
|
|
|
|
export async function deliverToFollowers(actor: { id: ILocalUser['id']; host: null; }, activity: any) {
|
2019-11-09 10:51:54 +01:00
|
|
|
|
const manager = new DeliverManager(actor, activity);
|
|
|
|
|
manager.addFollowersRecipe();
|
|
|
|
|
await manager.execute();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Deliver activity to user
|
|
|
|
|
* @param activity Activity
|
|
|
|
|
* @param to Target user
|
|
|
|
|
*/
|
2022-03-25 08:27:41 +01:00
|
|
|
|
export async function deliverToUser(actor: { id: ILocalUser['id']; host: null; }, activity: any, to: IRemoteUser) {
|
2019-11-09 10:51:54 +01:00
|
|
|
|
const manager = new DeliverManager(actor, activity);
|
|
|
|
|
manager.addDirectRecipe(to);
|
|
|
|
|
await manager.execute();
|
|
|
|
|
}
|
|
|
|
|
//#endregion
|