diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2019-02-08 16:58:57 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-02-08 16:58:57 +0900 |
| commit | 56275bcfcbd1366b0e96b79915e810baed0548bb (patch) | |
| tree | b35c8a6bd15ef8046c00119f0271808970f4f939 /src/services/chart/instance.ts | |
| parent | Supress logs during test (diff) | |
| download | sharkey-56275bcfcbd1366b0e96b79915e810baed0548bb.tar.gz sharkey-56275bcfcbd1366b0e96b79915e810baed0548bb.tar.bz2 sharkey-56275bcfcbd1366b0e96b79915e810baed0548bb.zip | |
Introduce per-instance chart (#4183)
* Introduce per-instance chart
* Implement chart view in client
* Handle note deleting
* More chart srcs
* Add drive stats
* Improve drive stats
* Fix bug
* Add icon
Diffstat (limited to 'src/services/chart/instance.ts')
| -rw-r--r-- | src/services/chart/instance.ts | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/src/services/chart/instance.ts b/src/services/chart/instance.ts new file mode 100644 index 0000000000..5af398b902 --- /dev/null +++ b/src/services/chart/instance.ts @@ -0,0 +1,302 @@ +import autobind from 'autobind-decorator'; +import Chart, { Obj } from '.'; +import User from '../../models/user'; +import Note from '../../models/note'; +import Following from '../../models/following'; +import DriveFile, { IDriveFile } from '../../models/drive-file'; + +/** + * インスタンスごとのチャート + */ +type InstanceLog = { + requests: { + /** + * 失敗したリクエスト数 + */ + failed: number; + + /** + * 成功したリクエスト数 + */ + succeeded: number; + + /** + * 受信したリクエスト数 + */ + received: number; + }; + + notes: { + /** + * 集計期間時点での、全投稿数 + */ + total: number; + + /** + * 増加した投稿数 + */ + inc: number; + + /** + * 減少した投稿数 + */ + dec: number; + }; + + users: { + /** + * 集計期間時点での、全ユーザー数 + */ + total: number; + + /** + * 増加したユーザー数 + */ + inc: number; + + /** + * 減少したユーザー数 + */ + dec: number; + }; + + following: { + /** + * 集計期間時点での、全フォロー数 + */ + total: number; + + /** + * 増加したフォロー数 + */ + inc: number; + + /** + * 減少したフォロー数 + */ + dec: number; + }; + + followers: { + /** + * 集計期間時点での、全フォロワー数 + */ + total: number; + + /** + * 増加したフォロワー数 + */ + inc: number; + + /** + * 減少したフォロワー数 + */ + dec: number; + }; + + drive: { + /** + * 集計期間時点での、全ドライブファイル数 + */ + totalFiles: number; + + /** + * 集計期間時点での、全ドライブファイルの合計サイズ + */ + totalUsage: number; + + /** + * 増加したドライブファイル数 + */ + incFiles: number; + + /** + * 増加したドライブ使用量 + */ + incUsage: number; + + /** + * 減少したドライブファイル数 + */ + decFiles: number; + + /** + * 減少したドライブ使用量 + */ + decUsage: number; + }; +}; + +class InstanceChart extends Chart<InstanceLog> { + constructor() { + super('instance', true); + } + + @autobind + protected async getTemplate(init: boolean, latest?: InstanceLog, group?: any): Promise<InstanceLog> { + const calcUsage = () => DriveFile + .aggregate([{ + $match: { + 'metadata._user.host': group, + 'metadata.deletedAt': { $exists: false } + } + }, { + $project: { + length: true + } + }, { + $group: { + _id: null, + usage: { $sum: '$length' } + } + }]) + .then(res => res.length > 0 ? res[0].usage : 0); + + const [ + notesCount, + usersCount, + followingCount, + followersCount, + driveFiles, + driveUsage, + ] = init ? await Promise.all([ + Note.count({ '_user.host': group }), + User.count({ host: group }), + Following.count({ '_follower.host': group }), + Following.count({ '_followee.host': group }), + DriveFile.count({ 'metadata._user.host': group }), + calcUsage(), + ]) : [ + latest ? latest.notes.total : 0, + latest ? latest.users.total : 0, + latest ? latest.following.total : 0, + latest ? latest.followers.total : 0, + latest ? latest.drive.totalFiles : 0, + latest ? latest.drive.totalUsage : 0, + ]; + + return { + requests: { + failed: 0, + succeeded: 0, + received: 0 + }, + notes: { + total: notesCount, + inc: 0, + dec: 0 + }, + users: { + total: usersCount, + inc: 0, + dec: 0 + }, + following: { + total: followingCount, + inc: 0, + dec: 0 + }, + followers: { + total: followersCount, + inc: 0, + dec: 0 + }, + drive: { + totalFiles: driveFiles, + totalUsage: driveUsage, + incFiles: 0, + incUsage: 0, + decFiles: 0, + decUsage: 0 + } + }; + } + + @autobind + public async requestReceived(host: string) { + await this.inc({ + requests: { + received: 1 + } + }, host); + } + + @autobind + public async requestSent(host: string, isSucceeded: boolean) { + const update: Obj = {}; + + if (isSucceeded) { + update.succeeded = 1; + } else { + update.failed = 1; + } + + await this.inc({ + requests: update + }, host); + } + + @autobind + public async newUser(host: string) { + await this.inc({ + users: { + total: 1, + inc: 1 + } + }, host); + } + + @autobind + public async updateNote(host: string, isAdditional: boolean) { + await this.inc({ + notes: { + total: isAdditional ? 1 : -1, + inc: isAdditional ? 1 : 0, + dec: isAdditional ? 0 : 1, + } + }, host); + } + + @autobind + public async updateFollowing(host: string, isAdditional: boolean) { + await this.inc({ + following: { + total: isAdditional ? 1 : -1, + inc: isAdditional ? 1 : 0, + dec: isAdditional ? 0 : 1, + } + }, host); + } + + @autobind + public async updateFollowers(host: string, isAdditional: boolean) { + await this.inc({ + followers: { + total: isAdditional ? 1 : -1, + inc: isAdditional ? 1 : 0, + dec: isAdditional ? 0 : 1, + } + }, host); + } + + @autobind + public async updateDrive(file: IDriveFile, isAdditional: boolean) { + const update: Obj = {}; + + update.totalFiles = isAdditional ? 1 : -1; + update.totalUsage = isAdditional ? file.length : -file.length; + if (isAdditional) { + update.incFiles = 1; + update.incUsage = file.length; + } else { + update.decFiles = 1; + update.decUsage = file.length; + } + + await this.inc({ + drive: update + }, file.metadata._user.host); + } +} + +export default new InstanceChart(); |