diff --git a/src/chart/federation.ts b/src/chart/federation.ts new file mode 100644 index 000000000..9d5830a53 --- /dev/null +++ b/src/chart/federation.ts @@ -0,0 +1,65 @@ +import autobind from 'autobind-decorator'; +import Chart, { Obj } from '.'; + +/** + * フェデレーションに関するチャート + */ +type FederationLog = { + instance: { + /** + * インスタンス数の合計 + */ + total: number; + + /** + * 増加インスタンス数 + */ + inc: number; + + /** + * 減少インスタンス数 + */ + dec: number; + }; +}; + +class FederationChart extends Chart { + constructor() { + super('federation'); + } + + @autobind + protected async getTemplate(init: boolean, latest?: FederationLog): Promise { + const [total] = init ? await Promise.all([ + Instance.count({}) + ]) : [ + latest ? latest.instance.total : 0 + ]; + + return { + instance: { + total: total, + inc: 0, + dec: 0 + } + }; + } + + @autobind + public async update(isAdditional: boolean) { + const update: Obj = {}; + + update.total = isAdditional ? 1 : -1; + if (isAdditional) { + update.inc = 1; + } else { + update.dec = 1; + } + + await this.inc({ + instance: update + }); + } +} + +export default new FederationChart(); diff --git a/src/models/instance.ts b/src/models/instance.ts new file mode 100644 index 000000000..d3906df42 --- /dev/null +++ b/src/models/instance.ts @@ -0,0 +1,35 @@ +import * as mongo from 'mongodb'; +import db from '../db/mongodb'; + +const Instance = db.get('instances'); +Instance.createIndex('host', { unique: true }); +export default Instance; + +export interface IInstance { + _id: mongo.ObjectID; + + /** + * ホスト + */ + host: string; + + /** + * このインスタンスを捕捉した日時 + */ + caughtAt: Date; + + /** + * このインスタンスのシステム (MastodonとかMisskeyとかPleromaとか) + */ + system: string; + + /** + * このインスタンスのユーザー数 + */ + usersCount: number; + + /** + * このインスタンスから受け取った投稿数 + */ + notesCount: number; +} diff --git a/src/remote/activitypub/models/person.ts b/src/remote/activitypub/models/person.ts index a39c8d33c..f115dee87 100644 --- a/src/remote/activitypub/models/person.ts +++ b/src/remote/activitypub/models/person.ts @@ -13,6 +13,8 @@ import htmlToMFM from '../../../mfm/html-to-mfm'; import usersChart from '../../../chart/users'; import { URL } from 'url'; import { resolveNote } from './note'; +import registerInstance from '../../../services/register-instance'; +import Instance from '../../../models/instance'; const log = debug('misskey:activitypub'); @@ -173,6 +175,18 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise { + Instance.update({ _id: i._id }, { + $inc: { + usersCount: 1 + } + }); + + // TODO + //perInstanceChart.newUser(); + }); + //#region Increment users count Meta.update({}, { $inc: { @@ -214,6 +228,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise console.log(err)); + return user; } diff --git a/src/services/note/create.ts b/src/services/note/create.ts index 401543b48..96ffe9687 100644 --- a/src/services/note/create.ts +++ b/src/services/note/create.ts @@ -28,6 +28,8 @@ import perUserNotesChart from '../../chart/per-user-notes'; import { erase, unique } from '../../prelude/array'; import insertNoteUnread from './unread'; +import registerInstance from '../register-instance'; +import Instance from '../../models/instance'; type NotificationType = 'reply' | 'renote' | 'quote' | 'mention'; @@ -170,6 +172,20 @@ export default async (user: IUser, data: Option, silent = false) => new Promise< notesChart.update(note, true); perUserNotesChart.update(user, note, true); + // Register host + if (isRemoteUser(user)) { + registerInstance(user.host).then(i => { + Instance.update({ _id: i._id }, { + $inc: { + notesCount: 1 + } + }); + + // TODO + //perInstanceChart.newNote(); + }); + } + // ハッシュタグ登録 tags.map(tag => registerHashtag(user, tag)); diff --git a/src/services/register-instance.ts b/src/services/register-instance.ts new file mode 100644 index 000000000..6576a9ed0 --- /dev/null +++ b/src/services/register-instance.ts @@ -0,0 +1,22 @@ +import Instance, { IInstance } from '../models/instance'; +import federationChart from '../chart/federation'; + +export default async function(host: string): Promise { + if (host == null) return null; + + const index = await Instance.findOne({ host }); + + if (index == null) { + const i = await Instance.insert({ + host, + caughtAt: new Date(), + system: null // TODO + }); + + federationChart.update(true); + + return i; + } else { + return index; + } +}