perf(server): refactor and performance improvements
This commit is contained in:
@ -3,26 +3,26 @@ import Resolver from './resolver.js';
|
||||
import { resolvePerson } from './models/person.js';
|
||||
import { unique, concat } from '@/prelude/array.js';
|
||||
import promiseLimit from 'promise-limit';
|
||||
import { User, IRemoteUser } from '@/models/entities/user.js';
|
||||
import { User, CacheableRemoteUser, CacheableUser } from '@/models/entities/user.js';
|
||||
|
||||
type Visibility = 'public' | 'home' | 'followers' | 'specified';
|
||||
|
||||
type AudienceInfo = {
|
||||
visibility: Visibility,
|
||||
mentionedUsers: User[],
|
||||
visibleUsers: User[],
|
||||
mentionedUsers: CacheableUser[],
|
||||
visibleUsers: CacheableUser[],
|
||||
};
|
||||
|
||||
export async function parseAudience(actor: IRemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver): Promise<AudienceInfo> {
|
||||
export async function parseAudience(actor: CacheableRemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver): Promise<AudienceInfo> {
|
||||
const toGroups = groupingAudience(getApIds(to), actor);
|
||||
const ccGroups = groupingAudience(getApIds(cc), actor);
|
||||
|
||||
const others = unique(concat([toGroups.other, ccGroups.other]));
|
||||
|
||||
const limit = promiseLimit<User | null>(2);
|
||||
const limit = promiseLimit<CacheableUser | null>(2);
|
||||
const mentionedUsers = (await Promise.all(
|
||||
others.map(id => limit(() => resolvePerson(id, resolver).catch(() => null)))
|
||||
)).filter((x): x is User => x != null);
|
||||
)).filter((x): x is CacheableUser => x != null);
|
||||
|
||||
if (toGroups.public.length > 0) {
|
||||
return {
|
||||
@ -55,7 +55,7 @@ export async function parseAudience(actor: IRemoteUser, to?: ApObject, cc?: ApOb
|
||||
};
|
||||
}
|
||||
|
||||
function groupingAudience(ids: string[], actor: IRemoteUser) {
|
||||
function groupingAudience(ids: string[], actor: CacheableRemoteUser) {
|
||||
const groups = {
|
||||
public: [] as string[],
|
||||
followers: [] as string[],
|
||||
@ -85,7 +85,7 @@ function isPublic(id: string) {
|
||||
].includes(id);
|
||||
}
|
||||
|
||||
function isFollowers(id: string, actor: IRemoteUser) {
|
||||
function isFollowers(id: string, actor: CacheableRemoteUser) {
|
||||
return (
|
||||
id === (actor.followersUri || `${actor.uri}/followers`)
|
||||
);
|
||||
|
@ -1,12 +1,17 @@
|
||||
import escapeRegexp from 'escape-regexp';
|
||||
import config from '@/config/index.js';
|
||||
import { Note } from '@/models/entities/note.js';
|
||||
import { User, IRemoteUser } from '@/models/entities/user.js';
|
||||
import { User, IRemoteUser, CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { UserPublickey } from '@/models/entities/user-publickey.js';
|
||||
import { MessagingMessage } from '@/models/entities/messaging-message.js';
|
||||
import { Notes, Users, UserPublickeys, MessagingMessages } from '@/models/index.js';
|
||||
import { IObject, getApId } from './type.js';
|
||||
import { resolvePerson } from './models/person.js';
|
||||
import escapeRegexp from 'escape-regexp';
|
||||
import { Cache } from '@/misc/cache.js';
|
||||
import { userByIdCache } from '@/services/user-cache.js';
|
||||
|
||||
const publicKeyCache = new Cache<UserPublickey | null>(Infinity);
|
||||
const publicKeyByUserIdCache = new Cache<UserPublickey | null>(Infinity);
|
||||
|
||||
export default class DbResolver {
|
||||
constructor() {
|
||||
@ -75,17 +80,24 @@ export default class DbResolver {
|
||||
/**
|
||||
* AP KeyId => Misskey User and Key
|
||||
*/
|
||||
public async getAuthUserFromKeyId(keyId: string): Promise<AuthUser | null> {
|
||||
const key = await UserPublickeys.findOne({
|
||||
keyId,
|
||||
}, {
|
||||
relations: ['user'],
|
||||
});
|
||||
public async getAuthUserFromKeyId(keyId: string): Promise<{
|
||||
user: CacheableRemoteUser;
|
||||
key: UserPublickey;
|
||||
} | null> {
|
||||
const key = await publicKeyCache.fetch(keyId, async () => {
|
||||
const key = await UserPublickeys.findOne({
|
||||
keyId,
|
||||
});
|
||||
|
||||
if (key == null) return null;
|
||||
|
||||
return key;
|
||||
}, key => key != null);
|
||||
|
||||
if (key == null) return null;
|
||||
|
||||
return {
|
||||
user: key.user as IRemoteUser,
|
||||
user: await userByIdCache.fetch(key.userId, () => Users.findOneOrFail(key.userId)) as CacheableRemoteUser,
|
||||
key,
|
||||
};
|
||||
}
|
||||
@ -93,12 +105,15 @@ export default class DbResolver {
|
||||
/**
|
||||
* AP Actor id => Misskey User and Key
|
||||
*/
|
||||
public async getAuthUserFromApId(uri: string): Promise<AuthUser | null> {
|
||||
const user = await resolvePerson(uri) as IRemoteUser;
|
||||
public async getAuthUserFromApId(uri: string): Promise<{
|
||||
user: CacheableRemoteUser;
|
||||
key: UserPublickey | null;
|
||||
} | null> {
|
||||
const user = await resolvePerson(uri) as CacheableRemoteUser;
|
||||
|
||||
if (user == null) return null;
|
||||
|
||||
const key = await UserPublickeys.findOne(user.id);
|
||||
const key = await publicKeyByUserIdCache.fetch(user.id, () => UserPublickeys.findOne(user.id).then(x => x || null), v => v != null); // TODO: typeorm 3.0 にしたら.then(x => x || null)は消せる
|
||||
|
||||
return {
|
||||
user,
|
||||
@ -125,11 +140,6 @@ export default class DbResolver {
|
||||
}
|
||||
}
|
||||
|
||||
export type AuthUser = {
|
||||
user: IRemoteUser;
|
||||
key?: UserPublickey;
|
||||
};
|
||||
|
||||
type UriParseResult = {
|
||||
/** id in DB (local object only) */
|
||||
id?: string;
|
||||
|
@ -112,7 +112,7 @@ export default class DeliverManager {
|
||||
* @param activity Activity
|
||||
* @param from Followee
|
||||
*/
|
||||
export async function deliverToFollowers(actor: ILocalUser, activity: any) {
|
||||
export async function deliverToFollowers(actor: { id: ILocalUser['id']; host: null; }, activity: any) {
|
||||
const manager = new DeliverManager(actor, activity);
|
||||
manager.addFollowersRecipe();
|
||||
await manager.execute();
|
||||
@ -123,7 +123,7 @@ export async function deliverToFollowers(actor: ILocalUser, activity: any) {
|
||||
* @param activity Activity
|
||||
* @param to Target user
|
||||
*/
|
||||
export async function deliverToUser(actor: ILocalUser, activity: any, to: IRemoteUser) {
|
||||
export async function deliverToUser(actor: { id: ILocalUser['id']; host: null; }, activity: any, to: IRemoteUser) {
|
||||
const manager = new DeliverManager(actor, activity);
|
||||
manager.addDirectRecipe(to);
|
||||
await manager.execute();
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import accept from '@/services/following/requests/accept.js';
|
||||
import { IFollow } from '../../type.js';
|
||||
import DbResolver from '../../db-resolver.js';
|
||||
import { relayAccepted } from '@/services/relay.js';
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IFollow): Promise<string> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IFollow): Promise<string> => {
|
||||
// ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある
|
||||
|
||||
const dbResolver = new DbResolver();
|
||||
|
@ -1,12 +1,12 @@
|
||||
import Resolver from '../../resolver.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import acceptFollow from './follow.js';
|
||||
import { IAccept, isFollow, getApType } from '../../type.js';
|
||||
import { apLogger } from '../../logger.js';
|
||||
|
||||
const logger = apLogger;
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IAccept): Promise<string> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IAccept): Promise<string> => {
|
||||
const uri = activity.id || activity;
|
||||
|
||||
logger.info(`Accept: ${uri}`);
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { IAdd } from '../../type.js';
|
||||
import { resolveNote } from '../../models/note.js';
|
||||
import { addPinned } from '@/services/i/pin.js';
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IAdd): Promise<void> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IAdd): Promise<void> => {
|
||||
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||
throw new Error('invalid actor');
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
import Resolver from '../../resolver.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import announceNote from './note.js';
|
||||
import { IAnnounce, getApId } from '../../type.js';
|
||||
import { apLogger } from '../../logger.js';
|
||||
|
||||
const logger = apLogger;
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IAnnounce): Promise<void> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IAnnounce): Promise<void> => {
|
||||
const uri = getApId(activity);
|
||||
|
||||
logger.info(`Announce: ${uri}`);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import Resolver from '../../resolver.js';
|
||||
import post from '@/services/note/create.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { IAnnounce, getApId } from '../../type.js';
|
||||
import { fetchNote, resolveNote } from '../../models/note.js';
|
||||
import { apLogger } from '../../logger.js';
|
||||
@ -15,10 +15,9 @@ const logger = apLogger;
|
||||
/**
|
||||
* アナウンスアクティビティを捌きます
|
||||
*/
|
||||
export default async function(resolver: Resolver, actor: IRemoteUser, activity: IAnnounce, targetUri: string): Promise<void> {
|
||||
export default async function(resolver: Resolver, actor: CacheableRemoteUser, activity: IAnnounce, targetUri: string): Promise<void> {
|
||||
const uri = getApId(activity);
|
||||
|
||||
// アナウンサーが凍結されていたらスキップ
|
||||
if (actor.isSuspended) {
|
||||
return;
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { IBlock } from '../../type.js';
|
||||
import block from '@/services/blocking/create.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import DbResolver from '../../db-resolver.js';
|
||||
import { Users } from '@/models/index.js';
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IBlock): Promise<string> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IBlock): Promise<string> => {
|
||||
// ※ activity.objectにブロック対象があり、それは存在するローカルユーザーのはず
|
||||
|
||||
const dbResolver = new DbResolver();
|
||||
@ -17,6 +18,6 @@ export default async (actor: IRemoteUser, activity: IBlock): Promise<string> =>
|
||||
return `skip: ブロックしようとしているユーザーはローカルユーザーではありません`;
|
||||
}
|
||||
|
||||
await block(actor, blockee);
|
||||
await block(await Users.findOneOrFail(actor.id), blockee);
|
||||
return `ok`;
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import Resolver from '../../resolver.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import createNote from './note.js';
|
||||
import { ICreate, getApId, isPost, getApType } from '../../type.js';
|
||||
import { apLogger } from '../../logger.js';
|
||||
@ -7,7 +7,7 @@ import { toArray, concat, unique } from '@/prelude/array.js';
|
||||
|
||||
const logger = apLogger;
|
||||
|
||||
export default async (actor: IRemoteUser, activity: ICreate): Promise<void> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: ICreate): Promise<void> => {
|
||||
const uri = getApId(activity);
|
||||
|
||||
logger.info(`Create: ${uri}`);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import Resolver from '../../resolver.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { createNote, fetchNote } from '../../models/note.js';
|
||||
import { getApId, IObject, ICreate } from '../../type.js';
|
||||
import { getApLock } from '@/misc/app-lock.js';
|
||||
@ -9,7 +9,7 @@ import { StatusError } from '@/misc/fetch.js';
|
||||
/**
|
||||
* 投稿作成アクティビティを捌きます
|
||||
*/
|
||||
export default async function(resolver: Resolver, actor: IRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise<string> {
|
||||
export default async function(resolver: Resolver, actor: CacheableRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise<string> {
|
||||
const uri = getApId(note);
|
||||
|
||||
if (typeof note === 'object') {
|
||||
|
@ -1,18 +1,19 @@
|
||||
import { apLogger } from '../../logger.js';
|
||||
import { createDeleteAccountJob } from '@/queue/index.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { Users } from '@/models/index.js';
|
||||
|
||||
const logger = apLogger;
|
||||
|
||||
export async function deleteActor(actor: IRemoteUser, uri: string): Promise<string> {
|
||||
export async function deleteActor(actor: CacheableRemoteUser, uri: string): Promise<string> {
|
||||
logger.info(`Deleting the Actor: ${uri}`);
|
||||
|
||||
if (actor.uri !== uri) {
|
||||
return `skip: delete actor ${actor.uri} !== ${uri}`;
|
||||
}
|
||||
|
||||
if (actor.isDeleted) {
|
||||
const user = await Users.findOneOrFail(actor.id);
|
||||
if (user.isDeleted) {
|
||||
logger.info(`skip: already deleted`);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import deleteNote from './note.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { IDelete, getApId, isTombstone, IObject, validPost, validActor } from '../../type.js';
|
||||
import { toSingle } from '@/prelude/array.js';
|
||||
import { deleteActor } from './actor.js';
|
||||
@ -7,7 +7,7 @@ import { deleteActor } from './actor.js';
|
||||
/**
|
||||
* 削除アクティビティを捌きます
|
||||
*/
|
||||
export default async (actor: IRemoteUser, activity: IDelete): Promise<string> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IDelete): Promise<string> => {
|
||||
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||
throw new Error('invalid actor');
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import deleteNode from '@/services/note/delete.js';
|
||||
import { apLogger } from '../../logger.js';
|
||||
import DbResolver from '../../db-resolver.js';
|
||||
@ -7,7 +7,7 @@ import { deleteMessage } from '@/services/messages/delete.js';
|
||||
|
||||
const logger = apLogger;
|
||||
|
||||
export default async function(actor: IRemoteUser, uri: string): Promise<string> {
|
||||
export default async function(actor: CacheableRemoteUser, uri: string): Promise<string> {
|
||||
logger.info(`Deleting the Note: ${uri}`);
|
||||
|
||||
const unlock = await getApLock(uri);
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import config from '@/config/index.js';
|
||||
import { IFlag, getApIds } from '../../type.js';
|
||||
import { AbuseUserReports, Users } from '@/models/index.js';
|
||||
import { In } from 'typeorm';
|
||||
import { genId } from '@/misc/gen-id.js';
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IFlag): Promise<string> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IFlag): Promise<string> => {
|
||||
// objectは `(User|Note) | (User|Note)[]` だけど、全パターンDBスキーマと対応させられないので
|
||||
// 対象ユーザーは一番最初のユーザー として あとはコメントとして格納する
|
||||
const uris = getApIds(activity.object);
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import follow from '@/services/following/create.js';
|
||||
import { IFollow } from '../type.js';
|
||||
import DbResolver from '../db-resolver.js';
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IFollow): Promise<string> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IFollow): Promise<string> => {
|
||||
const dbResolver = new DbResolver();
|
||||
const followee = await dbResolver.getUserFromApId(activity.object);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { IObject, isCreate, isDelete, isUpdate, isRead, isFollow, isAccept, isReject, isAdd, isRemove, isAnnounce, isLike, isUndo, isBlock, isCollectionOrOrderedCollection, isCollection, isFlag } from '../type.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import create from './create/index.js';
|
||||
import performDeleteActivity from './delete/index.js';
|
||||
import performUpdateActivity from './update/index.js';
|
||||
@ -17,8 +17,9 @@ import flag from './flag/index.js';
|
||||
import { apLogger } from '../logger.js';
|
||||
import Resolver from '../resolver.js';
|
||||
import { toArray } from '@/prelude/array.js';
|
||||
import { Users } from '@/models/index.js';
|
||||
|
||||
export async function performActivity(actor: IRemoteUser, activity: IObject) {
|
||||
export async function performActivity(actor: CacheableRemoteUser, activity: IObject) {
|
||||
if (isCollectionOrOrderedCollection(activity)) {
|
||||
const resolver = new Resolver();
|
||||
for (const item of toArray(isCollection(activity) ? activity.items : activity.orderedItems)) {
|
||||
@ -36,7 +37,7 @@ export async function performActivity(actor: IRemoteUser, activity: IObject) {
|
||||
}
|
||||
}
|
||||
|
||||
async function performOneActivity(actor: IRemoteUser, activity: IObject): Promise<void> {
|
||||
async function performOneActivity(actor: CacheableRemoteUser, activity: IObject): Promise<void> {
|
||||
if (actor.isSuspended) return;
|
||||
|
||||
if (isCreate(activity)) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { ILike, getApId } from '../type.js';
|
||||
import create from '@/services/note/reaction/create.js';
|
||||
import { fetchNote, extractEmojis } from '../models/note.js';
|
||||
|
||||
export default async (actor: IRemoteUser, activity: ILike) => {
|
||||
export default async (actor: CacheableRemoteUser, activity: ILike) => {
|
||||
const targetUri = getApId(activity.object);
|
||||
|
||||
const note = await fetchNote(targetUri);
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { IRead, getApId } from '../type.js';
|
||||
import { isSelfHost, extractDbHost } from '@/misc/convert-host.js';
|
||||
import { MessagingMessages } from '@/models/index.js';
|
||||
import { readUserMessagingMessage } from '../../../server/api/common/read-messaging-message.js';
|
||||
|
||||
export const performReadActivity = async (actor: IRemoteUser, activity: IRead): Promise<string> => {
|
||||
export const performReadActivity = async (actor: CacheableRemoteUser, activity: IRead): Promise<string> => {
|
||||
const id = await getApId(activity.object);
|
||||
|
||||
if (!isSelfHost(extractDbHost(id))) {
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { remoteReject } from '@/services/following/reject.js';
|
||||
import { IFollow } from '../../type.js';
|
||||
import DbResolver from '../../db-resolver.js';
|
||||
import { relayRejected } from '@/services/relay.js';
|
||||
import { Users } from '@/models/index.js';
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IFollow): Promise<string> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IFollow): Promise<string> => {
|
||||
// ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある
|
||||
|
||||
const dbResolver = new DbResolver();
|
||||
|
@ -1,12 +1,12 @@
|
||||
import Resolver from '../../resolver.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import rejectFollow from './follow.js';
|
||||
import { IReject, isFollow, getApType } from '../../type.js';
|
||||
import { apLogger } from '../../logger.js';
|
||||
|
||||
const logger = apLogger;
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IReject): Promise<string> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IReject): Promise<string> => {
|
||||
const uri = activity.id || activity;
|
||||
|
||||
logger.info(`Reject: ${uri}`);
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { IRemove } from '../../type.js';
|
||||
import { resolveNote } from '../../models/note.js';
|
||||
import { removePinned } from '@/services/i/pin.js';
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IRemove): Promise<void> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IRemove): Promise<void> => {
|
||||
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||
throw new Error('invalid actor');
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import unfollow from '@/services/following/delete.js';
|
||||
import cancelRequest from '@/services/following/requests/cancel.js';
|
||||
import {IAccept} from '../../type.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { Followings } from '@/models/index.js';
|
||||
import DbResolver from '../../db-resolver.js';
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IAccept): Promise<string> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IAccept): Promise<string> => {
|
||||
const dbResolver = new DbResolver();
|
||||
|
||||
const follower = await dbResolver.getUserFromApId(activity.object);
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Notes } from '@/models/index.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { IAnnounce, getApId } from '../../type.js';
|
||||
import deleteNote from '@/services/note/delete.js';
|
||||
|
||||
export const undoAnnounce = async (actor: IRemoteUser, activity: IAnnounce): Promise<string> => {
|
||||
export const undoAnnounce = async (actor: CacheableRemoteUser, activity: IAnnounce): Promise<string> => {
|
||||
const uri = getApId(activity);
|
||||
|
||||
const note = await Notes.findOne({
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { IBlock } from '../../type.js';
|
||||
import unblock from '@/services/blocking/delete.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import DbResolver from '../../db-resolver.js';
|
||||
import { Users } from '@/models/index.js';
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IBlock): Promise<string> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IBlock): Promise<string> => {
|
||||
const dbResolver = new DbResolver();
|
||||
const blockee = await dbResolver.getUserFromApId(activity.object);
|
||||
|
||||
@ -15,6 +16,6 @@ export default async (actor: IRemoteUser, activity: IBlock): Promise<string> =>
|
||||
return `skip: ブロック解除しようとしているユーザーはローカルユーザーではありません`;
|
||||
}
|
||||
|
||||
await unblock(actor, blockee);
|
||||
await unblock(await Users.findOneOrFail(actor.id), blockee);
|
||||
return `ok`;
|
||||
};
|
||||
|
@ -1,11 +1,11 @@
|
||||
import unfollow from '@/services/following/delete.js';
|
||||
import cancelRequest from '@/services/following/requests/cancel.js';
|
||||
import { IFollow } from '../../type.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { FollowRequests, Followings } from '@/models/index.js';
|
||||
import DbResolver from '../../db-resolver.js';
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IFollow): Promise<string> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IFollow): Promise<string> => {
|
||||
const dbResolver = new DbResolver();
|
||||
|
||||
const followee = await dbResolver.getUserFromApId(activity.object);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import {IUndo, isFollow, isBlock, isLike, isAnnounce, getApType, isAccept} from '../../type.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { IUndo, isFollow, isBlock, isLike, isAnnounce, getApType, isAccept } from '../../type.js';
|
||||
import unfollow from './follow.js';
|
||||
import unblock from './block.js';
|
||||
import undoLike from './like.js';
|
||||
@ -10,7 +10,7 @@ import { apLogger } from '../../logger.js';
|
||||
|
||||
const logger = apLogger;
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IUndo): Promise<string> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IUndo): Promise<string> => {
|
||||
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||
throw new Error('invalid actor');
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { ILike, getApId } from '../../type.js';
|
||||
import deleteReaction from '@/services/note/reaction/delete.js';
|
||||
import { fetchNote } from '../../models/note.js';
|
||||
@ -6,7 +6,7 @@ import { fetchNote } from '../../models/note.js';
|
||||
/**
|
||||
* Process Undo.Like activity
|
||||
*/
|
||||
export default async (actor: IRemoteUser, activity: ILike) => {
|
||||
export default async (actor: CacheableRemoteUser, activity: ILike) => {
|
||||
const targetUri = getApId(activity.object);
|
||||
|
||||
const note = await fetchNote(targetUri);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { getApType, IUpdate, isActor } from '../../type.js';
|
||||
import { apLogger } from '../../logger.js';
|
||||
import { updateQuestion } from '../../models/question.js';
|
||||
@ -8,7 +8,7 @@ import { updatePerson } from '../../models/person.js';
|
||||
/**
|
||||
* Updateアクティビティを捌きます
|
||||
*/
|
||||
export default async (actor: IRemoteUser, activity: IUpdate): Promise<string> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IUpdate): Promise<string> => {
|
||||
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||
return `skip: invalid actor`;
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { uploadFromUrl } from '@/services/drive/upload-from-url.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser, IRemoteUser } from '@/models/entities/user.js';
|
||||
import Resolver from '../resolver.js';
|
||||
import { fetchMeta } from '@/misc/fetch-meta.js';
|
||||
import { apLogger } from '../logger.js';
|
||||
import { DriveFile } from '@/models/entities/drive-file.js';
|
||||
import { DriveFiles } from '@/models/index.js';
|
||||
import { DriveFiles, Users } from '@/models/index.js';
|
||||
import { truncate } from '@/misc/truncate.js';
|
||||
import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits.js';
|
||||
|
||||
@ -13,7 +13,7 @@ const logger = apLogger;
|
||||
/**
|
||||
* Imageを作成します。
|
||||
*/
|
||||
export async function createImage(actor: IRemoteUser, value: any): Promise<DriveFile> {
|
||||
export async function createImage(actor: CacheableRemoteUser, value: any): Promise<DriveFile> {
|
||||
// 投稿者が凍結されていたらスキップ
|
||||
if (actor.isSuspended) {
|
||||
throw new Error('actor has been suspended');
|
||||
@ -60,7 +60,7 @@ export async function createImage(actor: IRemoteUser, value: any): Promise<Drive
|
||||
* Misskeyに対象のImageが登録されていればそれを返し、そうでなければ
|
||||
* リモートサーバーからフェッチしてMisskeyに登録しそれを返します。
|
||||
*/
|
||||
export async function resolveImage(actor: IRemoteUser, value: any): Promise<DriveFile> {
|
||||
export async function resolveImage(actor: CacheableRemoteUser, value: any): Promise<DriveFile> {
|
||||
// TODO
|
||||
|
||||
// リモートサーバーからフェッチしてきて登録
|
||||
|
@ -3,17 +3,17 @@ import { IObject, isMention, IApMention } from '../type.js';
|
||||
import { resolvePerson } from './person.js';
|
||||
import promiseLimit from 'promise-limit';
|
||||
import Resolver from '../resolver.js';
|
||||
import { User } from '@/models/entities/user.js';
|
||||
import { CacheableUser, User } from '@/models/entities/user.js';
|
||||
|
||||
export async function extractApMentions(tags: IObject | IObject[] | null | undefined) {
|
||||
const hrefs = unique(extractApMentionObjects(tags).map(x => x.href as string));
|
||||
|
||||
const resolver = new Resolver();
|
||||
|
||||
const limit = promiseLimit<User | null>(2);
|
||||
const limit = promiseLimit<CacheableUser | null>(2);
|
||||
const mentionedUsers = (await Promise.all(
|
||||
hrefs.map(x => limit(() => resolvePerson(x, resolver).catch(() => null)))
|
||||
)).filter((x): x is User => x != null);
|
||||
)).filter((x): x is CacheableUser => x != null);
|
||||
|
||||
return mentionedUsers;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import Resolver from '../resolver.js';
|
||||
import post from '@/services/note/create.js';
|
||||
import { resolvePerson, updatePerson } from './person.js';
|
||||
import { resolveImage } from './image.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser, IRemoteUser } from '@/models/entities/user.js';
|
||||
import { htmlToMfm } from '../misc/html-to-mfm.js';
|
||||
import { extractApHashtags } from './tag.js';
|
||||
import { unique, toArray, toSingle } from '@/prelude/array.js';
|
||||
@ -15,7 +15,7 @@ import { apLogger } from '../logger.js';
|
||||
import { DriveFile } from '@/models/entities/drive-file.js';
|
||||
import { deliverQuestionUpdate } from '@/services/note/polls/update.js';
|
||||
import { extractDbHost, toPuny } from '@/misc/convert-host.js';
|
||||
import { Emojis, Polls, MessagingMessages } from '@/models/index.js';
|
||||
import { Emojis, Polls, MessagingMessages, Users } from '@/models/index.js';
|
||||
import { Note } from '@/models/entities/note.js';
|
||||
import { IObject, getOneApId, getApId, getOneApHrefNullable, validPost, IPost, isEmoji, getApType } from '../type.js';
|
||||
import { Emoji } from '@/models/entities/emoji.js';
|
||||
@ -90,7 +90,7 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s
|
||||
logger.info(`Creating the Note: ${note.id}`);
|
||||
|
||||
// 投稿者をフェッチ
|
||||
const actor = await resolvePerson(getOneApId(note.attributedTo), resolver) as IRemoteUser;
|
||||
const actor = await resolvePerson(getOneApId(note.attributedTo), resolver) as CacheableRemoteUser;
|
||||
|
||||
// 投稿者が凍結されていたらスキップ
|
||||
if (actor.isSuspended) {
|
||||
@ -230,11 +230,6 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s
|
||||
|
||||
const poll = await extractPollFromQuestion(note, resolver).catch(() => undefined);
|
||||
|
||||
// ユーザーの情報が古かったらついでに更新しておく
|
||||
if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
|
||||
if (actor.uri) updatePerson(actor.uri);
|
||||
}
|
||||
|
||||
if (isTalk) {
|
||||
for (const recipient of visibleUsers) {
|
||||
await createMessage(actor, recipient, undefined, text || undefined, (files && files.length > 0) ? files[0] : null, object.id);
|
||||
|
@ -15,7 +15,7 @@ import { apLogger } from '../logger.js';
|
||||
import { Note } from '@/models/entities/note.js';
|
||||
import { updateUsertags } from '@/services/update-hashtag.js';
|
||||
import { Users, Instances, DriveFiles, Followings, UserProfiles, UserPublickeys } from '@/models/index.js';
|
||||
import { User, IRemoteUser } from '@/models/entities/user.js';
|
||||
import { User, IRemoteUser, CacheableUser } from '@/models/entities/user.js';
|
||||
import { Emoji } from '@/models/entities/emoji.js';
|
||||
import { UserNotePining } from '@/models/entities/user-note-pining.js';
|
||||
import { genId } from '@/misc/gen-id.js';
|
||||
@ -30,6 +30,8 @@ import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata.js';
|
||||
import { normalizeForSearch } from '@/misc/normalize-for-search.js';
|
||||
import { truncate } from '@/misc/truncate.js';
|
||||
import { StatusError } from '@/misc/fetch.js';
|
||||
import { uriPersonCache } from '@/services/user-cache.js';
|
||||
import { publishInternalEvent } from '@/services/stream.js';
|
||||
|
||||
const logger = apLogger;
|
||||
|
||||
@ -91,19 +93,25 @@ function validateActor(x: IObject, uri: string): IActor {
|
||||
*
|
||||
* Misskeyに対象のPersonが登録されていればそれを返します。
|
||||
*/
|
||||
export async function fetchPerson(uri: string, resolver?: Resolver): Promise<User | null> {
|
||||
export async function fetchPerson(uri: string, resolver?: Resolver): Promise<CacheableUser | null> {
|
||||
if (typeof uri !== 'string') throw new Error('uri is not string');
|
||||
|
||||
const cached = uriPersonCache.get(uri);
|
||||
if (cached) return cached;
|
||||
|
||||
// URIがこのサーバーを指しているならデータベースからフェッチ
|
||||
if (uri.startsWith(config.url + '/')) {
|
||||
const id = uri.split('/').pop();
|
||||
return await Users.findOne(id).then(x => x || null);
|
||||
const u = await Users.findOne(id).then(x => x || null); // TODO: typeorm 3.0 にしたら .then(x => x || null) を消す
|
||||
if (u) uriPersonCache.set(uri, u);
|
||||
return u;
|
||||
}
|
||||
|
||||
//#region このサーバーに既に登録されていたらそれを返す
|
||||
const exist = await Users.findOne({ uri });
|
||||
|
||||
if (exist) {
|
||||
uriPersonCache.set(uri, exist);
|
||||
return exist;
|
||||
}
|
||||
//#endregion
|
||||
@ -352,6 +360,8 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint
|
||||
location: person['vcard:Address'] || null,
|
||||
});
|
||||
|
||||
publishInternalEvent('remoteUserUpdated', { id: exist.id });
|
||||
|
||||
// ハッシュタグ更新
|
||||
updateUsertags(exist, tags);
|
||||
|
||||
@ -371,7 +381,7 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint
|
||||
* Misskeyに対象のPersonが登録されていればそれを返し、そうでなければ
|
||||
* リモートサーバーからフェッチしてMisskeyに登録しそれを返します。
|
||||
*/
|
||||
export async function resolvePerson(uri: string, resolver?: Resolver): Promise<User> {
|
||||
export async function resolvePerson(uri: string, resolver?: Resolver): Promise<CacheableUser> {
|
||||
if (typeof uri !== 'string') throw new Error('uri is not string');
|
||||
|
||||
//#region このサーバーに既に登録されていたらそれを返す
|
||||
|
@ -1,7 +1,17 @@
|
||||
import { IObject } from './type.js';
|
||||
import { IRemoteUser } from '@/models/entities/user.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { performActivity } from './kernel/index.js';
|
||||
import { updatePerson } from './models/person.js';
|
||||
|
||||
export default async (actor: IRemoteUser, activity: IObject): Promise<void> => {
|
||||
export default async (actor: CacheableRemoteUser, activity: IObject): Promise<void> => {
|
||||
await performActivity(actor, activity);
|
||||
|
||||
// ついでにリモートユーザーの情報が古かったら更新しておく
|
||||
if (actor.uri) {
|
||||
if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
|
||||
setImmediate(() => {
|
||||
updatePerson(actor.uri!);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user