summaryrefslogtreecommitdiff
path: root/src/chart
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2019-02-08 04:31:33 +0900
committersyuilo <syuilotan@yahoo.co.jp>2019-02-08 04:31:33 +0900
commitaba85b977dfc868c1a65ce06ed58ea59d0371f7f (patch)
tree5e27a5397bb3ee93ae1790ed2f92c6264ae86956 /src/chart
parentImplement instance blocking (#4182) (diff)
downloadsharkey-aba85b977dfc868c1a65ce06ed58ea59d0371f7f.tar.gz
sharkey-aba85b977dfc868c1a65ce06ed58ea59d0371f7f.tar.bz2
sharkey-aba85b977dfc868c1a65ce06ed58ea59d0371f7f.zip
Refactoring: Move chart dir into services dir
Diffstat (limited to 'src/chart')
-rw-r--r--src/chart/active-users.ts48
-rw-r--r--src/chart/drive.ts122
-rw-r--r--src/chart/federation.ts66
-rw-r--r--src/chart/hashtag.ts56
-rw-r--r--src/chart/index.ts348
-rw-r--r--src/chart/network.ts64
-rw-r--r--src/chart/notes.ts114
-rw-r--r--src/chart/per-user-drive.ts101
-rw-r--r--src/chart/per-user-following.ts128
-rw-r--r--src/chart/per-user-notes.ts94
-rw-r--r--src/chart/per-user-reactions.ts45
-rw-r--r--src/chart/users.ts75
12 files changed, 0 insertions, 1261 deletions
diff --git a/src/chart/active-users.ts b/src/chart/active-users.ts
deleted file mode 100644
index 06d9b8aa90..0000000000
--- a/src/chart/active-users.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import autobind from 'autobind-decorator';
-import Chart, { Obj } from '.';
-import { IUser, isLocalUser } from '../models/user';
-
-/**
- * アクティブユーザーに関するチャート
- */
-type ActiveUsersLog = {
- local: {
- /**
- * アクティブユーザー数
- */
- count: number;
- };
-
- remote: ActiveUsersLog['local'];
-};
-
-class ActiveUsersChart extends Chart<ActiveUsersLog> {
- constructor() {
- super('activeUsers');
- }
-
- @autobind
- protected async getTemplate(init: boolean, latest?: ActiveUsersLog): Promise<ActiveUsersLog> {
- return {
- local: {
- count: 0
- },
- remote: {
- count: 0
- }
- };
- }
-
- @autobind
- public async update(user: IUser) {
- const update: Obj = {
- count: 1
- };
-
- await this.incIfUnique({
- [isLocalUser(user) ? 'local' : 'remote']: update
- }, 'users', user._id.toHexString());
- }
-}
-
-export default new ActiveUsersChart();
diff --git a/src/chart/drive.ts b/src/chart/drive.ts
deleted file mode 100644
index ff454c750a..0000000000
--- a/src/chart/drive.ts
+++ /dev/null
@@ -1,122 +0,0 @@
-import autobind from 'autobind-decorator';
-import Chart, { Obj } from './';
-import DriveFile, { IDriveFile } from '../models/drive-file';
-import { isLocalUser } from '../models/user';
-
-/**
- * ドライブに関するチャート
- */
-type DriveLog = {
- local: {
- /**
- * 集計期間時点での、全ドライブファイル数
- */
- totalCount: number;
-
- /**
- * 集計期間時点での、全ドライブファイルの合計サイズ
- */
- totalSize: number;
-
- /**
- * 増加したドライブファイル数
- */
- incCount: number;
-
- /**
- * 増加したドライブ使用量
- */
- incSize: number;
-
- /**
- * 減少したドライブファイル数
- */
- decCount: number;
-
- /**
- * 減少したドライブ使用量
- */
- decSize: number;
- };
-
- remote: DriveLog['local'];
-};
-
-class DriveChart extends Chart<DriveLog> {
- constructor() {
- super('drive');
- }
-
- @autobind
- protected async getTemplate(init: boolean, latest?: DriveLog): Promise<DriveLog> {
- const calcSize = (local: boolean) => DriveFile
- .aggregate([{
- $match: {
- 'metadata._user.host': local ? null : { $ne: null },
- 'metadata.deletedAt': { $exists: false }
- }
- }, {
- $project: {
- length: true
- }
- }, {
- $group: {
- _id: null,
- usage: { $sum: '$length' }
- }
- }])
- .then(res => res.length > 0 ? res[0].usage : 0);
-
- const [localCount, remoteCount, localSize, remoteSize] = init ? await Promise.all([
- DriveFile.count({ 'metadata._user.host': null }),
- DriveFile.count({ 'metadata._user.host': { $ne: null } }),
- calcSize(true),
- calcSize(false)
- ]) : [
- latest ? latest.local.totalCount : 0,
- latest ? latest.remote.totalCount : 0,
- latest ? latest.local.totalSize : 0,
- latest ? latest.remote.totalSize : 0
- ];
-
- return {
- local: {
- totalCount: localCount,
- totalSize: localSize,
- incCount: 0,
- incSize: 0,
- decCount: 0,
- decSize: 0
- },
- remote: {
- totalCount: remoteCount,
- totalSize: remoteSize,
- incCount: 0,
- incSize: 0,
- decCount: 0,
- decSize: 0
- }
- };
- }
-
- @autobind
- public async update(file: IDriveFile, isAdditional: boolean) {
- const update: Obj = {};
-
- update.totalCount = isAdditional ? 1 : -1;
- update.totalSize = isAdditional ? file.length : -file.length;
- if (isAdditional) {
- update.incCount = 1;
- update.incSize = file.length;
- } else {
- update.decCount = 1;
- update.decSize = file.length;
- }
-
- await this.inc({
- [isLocalUser(file.metadata._user) ? 'local' : 'remote']: update
- });
- }
-}
-
-export default new DriveChart();
diff --git a/src/chart/federation.ts b/src/chart/federation.ts
deleted file mode 100644
index 5bb41f00a2..0000000000
--- a/src/chart/federation.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import autobind from 'autobind-decorator';
-import Chart, { Obj } from '.';
-import Instance from '../models/instance';
-
-/**
- * フェデレーションに関するチャート
- */
-type FederationLog = {
- instance: {
- /**
- * インスタンス数の合計
- */
- total: number;
-
- /**
- * 増加インスタンス数
- */
- inc: number;
-
- /**
- * 減少インスタンス数
- */
- dec: number;
- };
-};
-
-class FederationChart extends Chart<FederationLog> {
- constructor() {
- super('federation');
- }
-
- @autobind
- protected async getTemplate(init: boolean, latest?: FederationLog): Promise<FederationLog> {
- 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/chart/hashtag.ts b/src/chart/hashtag.ts
deleted file mode 100644
index 5b03d8ba34..0000000000
--- a/src/chart/hashtag.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import autobind from 'autobind-decorator';
-import Chart, { Obj } from './';
-import { IUser, isLocalUser } from '../models/user';
-import db from '../db/mongodb';
-
-/**
- * ハッシュタグに関するチャート
- */
-type HashtagLog = {
- local: {
- /**
- * 投稿された数
- */
- count: number;
- };
-
- remote: HashtagLog['local'];
-};
-
-class HashtagChart extends Chart<HashtagLog> {
- constructor() {
- super('hashtag', true);
-
- // 後方互換性のため
- db.get('chart.hashtag').findOne().then(doc => {
- if (doc != null && doc.data.local == null) {
- db.get('chart.hashtag').drop();
- }
- });
- }
-
- @autobind
- protected async getTemplate(init: boolean, latest?: HashtagLog): Promise<HashtagLog> {
- return {
- local: {
- count: 0
- },
- remote: {
- count: 0
- }
- };
- }
-
- @autobind
- public async update(hashtag: string, user: IUser) {
- const update: Obj = {
- count: 1
- };
-
- await this.incIfUnique({
- [isLocalUser(user) ? 'local' : 'remote']: update
- }, 'users', user._id.toHexString(), hashtag);
- }
-}
-
-export default new HashtagChart();
diff --git a/src/chart/index.ts b/src/chart/index.ts
deleted file mode 100644
index cf61d90730..0000000000
--- a/src/chart/index.ts
+++ /dev/null
@@ -1,348 +0,0 @@
-/**
- * チャートエンジン
- */
-
-import * as moment from 'moment';
-import * as nestedProperty from 'nested-property';
-import autobind from 'autobind-decorator';
-import * as mongo from 'mongodb';
-import db from '../db/mongodb';
-import { ICollection } from 'monk';
-import Logger from '../misc/logger';
-
-const logger = new Logger('chart');
-
-const utc = moment.utc;
-
-export type Obj = { [key: string]: any };
-
-export type Partial<T> = {
- [P in keyof T]?: Partial<T[P]>;
-};
-
-type ArrayValue<T> = {
- [P in keyof T]: T[P] extends number ? T[P][] : ArrayValue<T[P]>;
-};
-
-type Span = 'day' | 'hour';
-
-type Log<T extends Obj> = {
- _id: mongo.ObjectID;
-
- /**
- * 集計のグループ
- */
- group?: any;
-
- /**
- * 集計日時
- */
- date: Date;
-
- /**
- * 集計期間
- */
- span: Span;
-
- /**
- * データ
- */
- data: T;
-
- /**
- * ユニークインクリメント用
- */
- unique?: Obj;
-};
-
-/**
- * 様々なチャートの管理を司るクラス
- */
-export default abstract class Chart<T extends Obj> {
- protected collection: ICollection<Log<T>>;
- protected abstract async getTemplate(init: boolean, latest?: T, group?: any): Promise<T>;
- private name: string;
-
- constructor(name: string, grouped = false) {
- this.name = name;
- this.collection = db.get<Log<T>>(`chart.${name}`);
-
- const keys = {
- span: -1,
- date: -1
- } as { [key: string]: 1 | -1; };
- if (grouped) keys.group = -1;
-
- this.collection.createIndex(keys, { unique: true });
- }
-
- @autobind
- private convertQuery(x: Obj, path: string): Obj {
- const query: Obj = {};
-
- const dive = (x: Obj, path: string) => {
- for (const [k, v] of Object.entries(x)) {
- const p = path ? `${path}.${k}` : k;
- if (typeof v === 'number') {
- query[p] = v;
- } else {
- dive(v, p);
- }
- }
- };
-
- dive(x, path);
-
- return query;
- }
-
- @autobind
- private getCurrentDate(): [number, number, number, number] {
- const now = moment().utc();
-
- const y = now.year();
- const m = now.month();
- const d = now.date();
- const h = now.hour();
-
- return [y, m, d, h];
- }
-
- @autobind
- private getLatestLog(span: Span, group?: any): Promise<Log<T>> {
- return this.collection.findOne({
- group: group,
- span: span
- }, {
- sort: {
- date: -1
- }
- });
- }
-
- @autobind
- private async getCurrentLog(span: Span, group?: any): Promise<Log<T>> {
- const [y, m, d, h] = this.getCurrentDate();
-
- const current =
- span == 'day' ? utc([y, m, d]) :
- span == 'hour' ? utc([y, m, d, h]) :
- null;
-
- // 現在(今日または今のHour)のログ
- const currentLog = await this.collection.findOne({
- group: group,
- span: span,
- date: current.toDate()
- });
-
- // ログがあればそれを返して終了
- if (currentLog != null) {
- return currentLog;
- }
-
- let log: Log<T>;
- let data: T;
-
- // 集計期間が変わってから、初めてのチャート更新なら
- // 最も最近のログを持ってくる
- // * 例えば集計期間が「日」である場合で考えると、
- // * 昨日何もチャートを更新するような出来事がなかった場合は、
- // * ログがそもそも作られずドキュメントが存在しないということがあり得るため、
- // * 「昨日の」と決め打ちせずに「もっとも最近の」とします
- const latest = await this.getLatestLog(span, group);
-
- if (latest != null) {
- // 空ログデータを作成
- data = await this.getTemplate(false, latest.data);
- } else {
- // ログが存在しなかったら
- // (Misskeyインスタンスを建てて初めてのチャート更新時など
- // または何らかの理由でチャートコレクションを抹消した場合)
-
- // 初期ログデータを作成
- data = await this.getTemplate(true, null, group);
-
- logger.info(`${this.name}: Initial commit created`);
- }
-
- try {
- // 新規ログ挿入
- log = await this.collection.insert({
- group: group,
- span: span,
- date: current.toDate(),
- data: data
- });
- } catch (e) {
- // 11000 is duplicate key error
- // 並列動作している他のチャートエンジンプロセスと処理が重なる場合がある
- // その場合は再度最も新しいログを持ってくる
- if (e.code === 11000) {
- log = await this.getLatestLog(span, group);
- } else {
- logger.error(e);
- throw e;
- }
- }
-
- return log;
- }
-
- @autobind
- protected commit(query: Obj, group?: any, uniqueKey?: string, uniqueValue?: string): void {
- const update = (log: Log<T>) => {
- // ユニークインクリメントの場合、指定のキーに指定の値が既に存在していたら弾く
- if (
- uniqueKey &&
- log.unique &&
- log.unique[uniqueKey] &&
- log.unique[uniqueKey].includes(uniqueValue)
- ) return;
-
- // ユニークインクリメントの指定のキーに値を追加
- if (uniqueKey) {
- query['$push'] = {
- [`unique.${uniqueKey}`]: uniqueValue
- };
- }
-
- // ログ更新
- this.collection.update({
- _id: log._id
- }, query);
- };
-
- this.getCurrentLog('day', group).then(log => update(log));
- this.getCurrentLog('hour', group).then(log => update(log));
- }
-
- @autobind
- protected inc(inc: Partial<T>, group?: any): void {
- this.commit({
- $inc: this.convertQuery(inc, 'data')
- }, group);
- }
-
- @autobind
- protected incIfUnique(inc: Partial<T>, key: string, value: string, group?: any): void {
- this.commit({
- $inc: this.convertQuery(inc, 'data')
- }, group, key, value);
- }
-
- @autobind
- public async getChart(span: Span, range: number, group?: any): Promise<ArrayValue<T>> {
- const promisedChart: Promise<T>[] = [];
-
- const [y, m, d, h] = this.getCurrentDate();
-
- const gt =
- span == 'day' ? utc([y, m, d]).subtract(range, 'days') :
- span == 'hour' ? utc([y, m, d, h]).subtract(range, 'hours') :
- null;
-
- // ログ取得
- let logs = await this.collection.find({
- group: group,
- span: span,
- date: {
- $gte: gt.toDate()
- }
- }, {
- sort: {
- date: -1
- },
- fields: {
- _id: 0
- }
- });
-
- // 要求された範囲にログがひとつもなかったら
- if (logs.length == 0) {
- // もっとも新しいログを持ってくる
- // (すくなくともひとつログが無いと隙間埋めできないため)
- const recentLog = await this.collection.findOne({
- group: group,
- span: span
- }, {
- sort: {
- date: -1
- },
- fields: {
- _id: 0
- }
- });
-
- if (recentLog) {
- logs = [recentLog];
- }
-
- // 要求された範囲の最も古い箇所に位置するログが存在しなかったら
- } else if (!utc(logs[logs.length - 1].date).isSame(gt)) {
- // 要求された範囲の最も古い箇所時点での最も新しいログを持ってきて末尾に追加する
- // (隙間埋めできないため)
- const outdatedLog = await this.collection.findOne({
- group: group,
- span: span,
- date: {
- $lt: gt.toDate()
- }
- }, {
- sort: {
- date: -1
- },
- fields: {
- _id: 0
- }
- });
-
- if (outdatedLog) {
- logs.push(outdatedLog);
- }
- }
-
- // 整形
- for (let i = (range - 1); i >= 0; i--) {
- const current =
- span == 'day' ? utc([y, m, d]).subtract(i, 'days') :
- span == 'hour' ? utc([y, m, d, h]).subtract(i, 'hours') :
- null;
-
- const log = logs.find(l => utc(l.date).isSame(current));
-
- if (log) {
- promisedChart.unshift(Promise.resolve(log.data));
- } else {
- // 隙間埋め
- const latest = logs.find(l => utc(l.date).isBefore(current));
- promisedChart.unshift(this.getTemplate(false, latest ? latest.data : null));
- }
- }
-
- const chart = await Promise.all(promisedChart);
-
- const res: ArrayValue<T> = {} as any;
-
- /**
- * [{ foo: 1, bar: 5 }, { foo: 2, bar: 6 }, { foo: 3, bar: 7 }]
- * を
- * { foo: [1, 2, 3], bar: [5, 6, 7] }
- * にする
- */
- const dive = (x: Obj, path?: string) => {
- for (const [k, v] of Object.entries(x)) {
- const p = path ? `${path}.${k}` : k;
- if (typeof v == 'object') {
- dive(v, p);
- } else {
- nestedProperty.set(res, p, chart.map(s => nestedProperty.get(s, p)));
- }
- }
- };
-
- dive(chart[0]);
-
- return res;
- }
-}
diff --git a/src/chart/network.ts b/src/chart/network.ts
deleted file mode 100644
index fce47099d1..0000000000
--- a/src/chart/network.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import autobind from 'autobind-decorator';
-import Chart, { Partial } from './';
-
-/**
- * ネットワークに関するチャート
- */
-type NetworkLog = {
- /**
- * 受信したリクエスト数
- */
- incomingRequests: number;
-
- /**
- * 送信したリクエスト数
- */
- outgoingRequests: number;
-
- /**
- * 応答時間の合計
- * TIP: (totalTime / incomingRequests) でひとつのリクエストに平均でどれくらいの時間がかかったか知れる
- */
- totalTime: number;
-
- /**
- * 合計受信データ量
- */
- incomingBytes: number;
-
- /**
- * 合計送信データ量
- */
- outgoingBytes: number;
-};
-
-class NetworkChart extends Chart<NetworkLog> {
- constructor() {
- super('network');
- }
-
- @autobind
- protected async getTemplate(init: boolean, latest?: NetworkLog): Promise<NetworkLog> {
- return {
- incomingRequests: 0,
- outgoingRequests: 0,
- totalTime: 0,
- incomingBytes: 0,
- outgoingBytes: 0
- };
- }
-
- @autobind
- public async update(incomingRequests: number, time: number, incomingBytes: number, outgoingBytes: number) {
- const inc: Partial<NetworkLog> = {
- incomingRequests: incomingRequests,
- totalTime: time,
- incomingBytes: incomingBytes,
- outgoingBytes: outgoingBytes
- };
-
- await this.inc(inc);
- }
-}
-
-export default new NetworkChart();
diff --git a/src/chart/notes.ts b/src/chart/notes.ts
deleted file mode 100644
index 738778e72a..0000000000
--- a/src/chart/notes.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-import autobind from 'autobind-decorator';
-import Chart, { Obj } from '.';
-import Note, { INote } from '../models/note';
-import { isLocalUser } from '../models/user';
-
-/**
- * 投稿に関するチャート
- */
-type NotesLog = {
- local: {
- /**
- * 集計期間時点での、全投稿数
- */
- total: number;
-
- /**
- * 増加した投稿数
- */
- inc: number;
-
- /**
- * 減少した投稿数
- */
- dec: number;
-
- diffs: {
- /**
- * 通常の投稿数の差分
- */
- normal: number;
-
- /**
- * リプライの投稿数の差分
- */
- reply: number;
-
- /**
- * Renoteの投稿数の差分
- */
- renote: number;
- };
- };
-
- remote: NotesLog['local'];
-};
-
-class NotesChart extends Chart<NotesLog> {
- constructor() {
- super('notes');
- }
-
- @autobind
- protected async getTemplate(init: boolean, latest?: NotesLog): Promise<NotesLog> {
- const [localCount, remoteCount] = init ? await Promise.all([
- Note.count({ '_user.host': null }),
- Note.count({ '_user.host': { $ne: null } })
- ]) : [
- latest ? latest.local.total : 0,
- latest ? latest.remote.total : 0
- ];
-
- return {
- local: {
- total: localCount,
- inc: 0,
- dec: 0,
- diffs: {
- normal: 0,
- reply: 0,
- renote: 0
- }
- },
- remote: {
- total: remoteCount,
- inc: 0,
- dec: 0,
- diffs: {
- normal: 0,
- reply: 0,
- renote: 0
- }
- }
- };
- }
-
- @autobind
- public async update(note: INote, isAdditional: boolean) {
- const update: Obj = {
- diffs: {}
- };
-
- update.total = isAdditional ? 1 : -1;
-
- if (isAdditional) {
- update.inc = 1;
- } else {
- update.dec = 1;
- }
-
- if (note.replyId != null) {
- update.diffs.reply = isAdditional ? 1 : -1;
- } else if (note.renoteId != null) {
- update.diffs.renote = isAdditional ? 1 : -1;
- } else {
- update.diffs.normal = isAdditional ? 1 : -1;
- }
-
- await this.inc({
- [isLocalUser(note._user) ? 'local' : 'remote']: update
- });
- }
-}
-
-export default new NotesChart();
diff --git a/src/chart/per-user-drive.ts b/src/chart/per-user-drive.ts
deleted file mode 100644
index 3decedeb3b..0000000000
--- a/src/chart/per-user-drive.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-import autobind from 'autobind-decorator';
-import Chart, { Obj } from './';
-import DriveFile, { IDriveFile } from '../models/drive-file';
-
-/**
- * ユーザーごとのドライブに関するチャート
- */
-type PerUserDriveLog = {
- /**
- * 集計期間時点での、全ドライブファイル数
- */
- totalCount: number;
-
- /**
- * 集計期間時点での、全ドライブファイルの合計サイズ
- */
- totalSize: number;
-
- /**
- * 増加したドライブファイル数
- */
- incCount: number;
-
- /**
- * 増加したドライブ使用量
- */
- incSize: number;
-
- /**
- * 減少したドライブファイル数
- */
- decCount: number;
-
- /**
- * 減少したドライブ使用量
- */
- decSize: number;
-};
-
-class PerUserDriveChart extends Chart<PerUserDriveLog> {
- constructor() {
- super('perUserDrive', true);
- }
-
- @autobind
- protected async getTemplate(init: boolean, latest?: PerUserDriveLog, group?: any): Promise<PerUserDriveLog> {
- const calcSize = () => DriveFile
- .aggregate([{
- $match: {
- 'metadata.userId': group,
- 'metadata.deletedAt': { $exists: false }
- }
- }, {
- $project: {
- length: true
- }
- }, {
- $group: {
- _id: null,
- usage: { $sum: '$length' }
- }
- }])
- .then(res => res.length > 0 ? res[0].usage : 0);
-
- const [count, size] = init ? await Promise.all([
- DriveFile.count({ 'metadata.userId': group }),
- calcSize()
- ]) : [
- latest ? latest.totalCount : 0,
- latest ? latest.totalSize : 0
- ];
-
- return {
- totalCount: count,
- totalSize: size,
- incCount: 0,
- incSize: 0,
- decCount: 0,
- decSize: 0
- };
- }
-
- @autobind
- public async update(file: IDriveFile, isAdditional: boolean) {
- const update: Obj = {};
-
- update.totalCount = isAdditional ? 1 : -1;
- update.totalSize = isAdditional ? file.length : -file.length;
- if (isAdditional) {
- update.incCount = 1;
- update.incSize = file.length;
- } else {
- update.decCount = 1;
- update.decSize = file.length;
- }
-
- await this.inc(update, file.metadata.userId);
- }
-}
-
-export default new PerUserDriveChart();
diff --git a/src/chart/per-user-following.ts b/src/chart/per-user-following.ts
deleted file mode 100644
index fac4a1619f..0000000000
--- a/src/chart/per-user-following.ts
+++ /dev/null
@@ -1,128 +0,0 @@
-import autobind from 'autobind-decorator';
-import Chart, { Obj } from './';
-import Following from '../models/following';
-import { IUser, isLocalUser } from '../models/user';
-
-/**
- * ユーザーごとのフォローに関するチャート
- */
-type PerUserFollowingLog = {
- local: {
- /**
- * フォローしている
- */
- followings: {
- /**
- * 合計
- */
- total: number;
-
- /**
- * フォローした数
- */
- inc: number;
-
- /**
- * フォロー解除した数
- */
- dec: number;
- };
-
- /**
- * フォローされている
- */
- followers: {
- /**
- * 合計
- */
- total: number;
-
- /**
- * フォローされた数
- */
- inc: number;
-
- /**
- * フォロー解除された数
- */
- dec: number;
- };
- };
-
- remote: PerUserFollowingLog['local'];
-};
-
-class PerUserFollowingChart extends Chart<PerUserFollowingLog> {
- constructor() {
- super('perUserFollowing', true);
- }
-
- @autobind
- protected async getTemplate(init: boolean, latest?: PerUserFollowingLog, group?: any): Promise<PerUserFollowingLog> {
- const [
- localFollowingsCount,
- localFollowersCount,
- remoteFollowingsCount,
- remoteFollowersCount
- ] = init ? await Promise.all([
- Following.count({ followerId: group, '_followee.host': null }),
- Following.count({ followeeId: group, '_follower.host': null }),
- Following.count({ followerId: group, '_followee.host': { $ne: null } }),
- Following.count({ followeeId: group, '_follower.host': { $ne: null } })
- ]) : [
- latest ? latest.local.followings.total : 0,
- latest ? latest.local.followers.total : 0,
- latest ? latest.remote.followings.total : 0,
- latest ? latest.remote.followers.total : 0
- ];
-
- return {
- local: {
- followings: {
- total: localFollowingsCount,
- inc: 0,
- dec: 0
- },
- followers: {
- total: localFollowersCount,
- inc: 0,
- dec: 0
- }
- },
- remote: {
- followings: {
- total: remoteFollowingsCount,
- inc: 0,
- dec: 0
- },
- followers: {
- total: remoteFollowersCount,
- inc: 0,
- dec: 0
- }
- }
- };
- }
-
- @autobind
- public async update(follower: IUser, followee: IUser, isFollow: boolean) {
- const update: Obj = {};
-
- update.total = isFollow ? 1 : -1;
-
- if (isFollow) {
- update.inc = 1;
- } else {
- update.dec = 1;
- }
-
- this.inc({
- [isLocalUser(follower) ? 'local' : 'remote']: { followings: update }
- }, follower._id);
- this.inc({
- [isLocalUser(followee) ? 'local' : 'remote']: { followers: update }
- }, followee._id);
- }
-}
-
-export default new PerUserFollowingChart();
diff --git a/src/chart/per-user-notes.ts b/src/chart/per-user-notes.ts
deleted file mode 100644
index 9558f5c839..0000000000
--- a/src/chart/per-user-notes.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-import autobind from 'autobind-decorator';
-import Chart, { Obj } from './';
-import Note, { INote } from '../models/note';
-import { IUser } from '../models/user';
-
-/**
- * ユーザーごとの投稿に関するチャート
- */
-type PerUserNotesLog = {
- /**
- * 集計期間時点での、全投稿数
- */
- total: number;
-
- /**
- * 増加した投稿数
- */
- inc: number;
-
- /**
- * 減少した投稿数
- */
- dec: number;
-
- diffs: {
- /**
- * 通常の投稿数の差分
- */
- normal: number;
-
- /**
- * リプライの投稿数の差分
- */
- reply: number;
-
- /**
- * Renoteの投稿数の差分
- */
- renote: number;
- };
-};
-
-class PerUserNotesChart extends Chart<PerUserNotesLog> {
- constructor() {
- super('perUserNotes', true);
- }
-
- @autobind
- protected async getTemplate(init: boolean, latest?: PerUserNotesLog, group?: any): Promise<PerUserNotesLog> {
- const [count] = init ? await Promise.all([
- Note.count({ userId: group, deletedAt: null }),
- ]) : [
- latest ? latest.total : 0
- ];
-
- return {
- total: count,
- inc: 0,
- dec: 0,
- diffs: {
- normal: 0,
- reply: 0,
- renote: 0
- }
- };
- }
-
- @autobind
- public async update(user: IUser, note: INote, isAdditional: boolean) {
- const update: Obj = {
- diffs: {}
- };
-
- update.total = isAdditional ? 1 : -1;
-
- if (isAdditional) {
- update.inc = 1;
- } else {
- update.dec = 1;
- }
-
- if (note.replyId != null) {
- update.diffs.reply = isAdditional ? 1 : -1;
- } else if (note.renoteId != null) {
- update.diffs.renote = isAdditional ? 1 : -1;
- } else {
- update.diffs.normal = isAdditional ? 1 : -1;
- }
-
- await this.inc(update, user._id);
- }
-}
-
-export default new PerUserNotesChart();
diff --git a/src/chart/per-user-reactions.ts b/src/chart/per-user-reactions.ts
deleted file mode 100644
index a31952ea22..0000000000
--- a/src/chart/per-user-reactions.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import autobind from 'autobind-decorator';
-import Chart from './';
-import { IUser, isLocalUser } from '../models/user';
-import { INote } from '../models/note';
-
-/**
- * ユーザーごとのリアクションに関するチャート
- */
-type PerUserReactionsLog = {
- local: {
- /**
- * リアクションされた数
- */
- count: number;
- };
-
- remote: PerUserReactionsLog['local'];
-};
-
-class PerUserReactionsChart extends Chart<PerUserReactionsLog> {
- constructor() {
- super('perUserReaction', true);
- }
-
- @autobind
- protected async getTemplate(init: boolean, latest?: PerUserReactionsLog, group?: any): Promise<PerUserReactionsLog> {
- return {
- local: {
- count: 0
- },
- remote: {
- count: 0
- }
- };
- }
-
- @autobind
- public async update(user: IUser, note: INote) {
- this.inc({
- [isLocalUser(user) ? 'local' : 'remote']: { count: 1 }
- }, note.userId);
- }
-}
-
-export default new PerUserReactionsChart();
diff --git a/src/chart/users.ts b/src/chart/users.ts
deleted file mode 100644
index 547e595b01..0000000000
--- a/src/chart/users.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import autobind from 'autobind-decorator';
-import Chart, { Obj } from './';
-import User, { IUser, isLocalUser } from '../models/user';
-
-/**
- * ユーザーに関するチャート
- */
-type UsersLog = {
- local: {
- /**
- * 集計期間時点での、全ユーザー数
- */
- total: number;
-
- /**
- * 増加したユーザー数
- */
- inc: number;
-
- /**
- * 減少したユーザー数
- */
- dec: number;
- };
-
- remote: UsersLog['local'];
-};
-
-class UsersChart extends Chart<UsersLog> {
- constructor() {
- super('users');
- }
-
- @autobind
- protected async getTemplate(init: boolean, latest?: UsersLog): Promise<UsersLog> {
- const [localCount, remoteCount] = init ? await Promise.all([
- User.count({ host: null }),
- User.count({ host: { $ne: null } })
- ]) : [
- latest ? latest.local.total : 0,
- latest ? latest.remote.total : 0
- ];
-
- return {
- local: {
- total: localCount,
- inc: 0,
- dec: 0
- },
- remote: {
- total: remoteCount,
- inc: 0,
- dec: 0
- }
- };
- }
-
- @autobind
- public async update(user: IUser, isAdditional: boolean) {
- const update: Obj = {};
-
- update.total = isAdditional ? 1 : -1;
- if (isAdditional) {
- update.inc = 1;
- } else {
- update.dec = 1;
- }
-
- await this.inc({
- [isLocalUser(user) ? 'local' : 'remote']: update
- });
- }
-}
-
-export default new UsersChart();