Refactoring & Better stats aggregation
This commit is contained in:
parent
6cccd9d288
commit
f13faf2243
1 changed files with 75 additions and 107 deletions
|
@ -6,9 +6,9 @@ const nestedProperty = require('nested-property');
|
||||||
import autobind from 'autobind-decorator';
|
import autobind from 'autobind-decorator';
|
||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
import db from '../db/mongodb';
|
import db from '../db/mongodb';
|
||||||
import { INote } from '../models/note';
|
import Note, { INote } from '../models/note';
|
||||||
import { isLocalUser, IUser } from '../models/user';
|
import User, { isLocalUser, IUser } from '../models/user';
|
||||||
import { IDriveFile } from '../models/drive-file';
|
import DriveFile, { IDriveFile } from '../models/drive-file';
|
||||||
import { ICollection } from 'monk';
|
import { ICollection } from 'monk';
|
||||||
|
|
||||||
type Obj = { [key: string]: any };
|
type Obj = { [key: string]: any };
|
||||||
|
@ -58,11 +58,10 @@ type ChartDocument<T extends Obj> = {
|
||||||
*/
|
*/
|
||||||
abstract class Chart<T> {
|
abstract class Chart<T> {
|
||||||
protected collection: ICollection<ChartDocument<T>>;
|
protected collection: ICollection<ChartDocument<T>>;
|
||||||
protected abstract generateInitialStats(): T;
|
protected abstract async generateTemplate(initial: boolean, mostRecentStats?: T): Promise<T>;
|
||||||
protected abstract generateEmptyStats(mostRecentStats: T): T;
|
|
||||||
|
|
||||||
constructor(dbCollectionName: string) {
|
constructor(name: string) {
|
||||||
this.collection = db.get<ChartDocument<T>>(dbCollectionName);
|
this.collection = db.get<ChartDocument<T>>(`stats.${name}`);
|
||||||
this.collection.createIndex({ span: -1, date: -1 }, { unique: true });
|
this.collection.createIndex({ span: -1, date: -1 }, { unique: true });
|
||||||
this.collection.createIndex('group');
|
this.collection.createIndex('group');
|
||||||
}
|
}
|
||||||
|
@ -127,7 +126,7 @@ abstract class Chart<T> {
|
||||||
|
|
||||||
if (mostRecentStats) {
|
if (mostRecentStats) {
|
||||||
// 現在の統計を初期挿入
|
// 現在の統計を初期挿入
|
||||||
const data = this.generateEmptyStats(mostRecentStats.data);
|
const data = await this.generateTemplate(false, mostRecentStats.data);
|
||||||
|
|
||||||
const stats = await this.collection.insert({
|
const stats = await this.collection.insert({
|
||||||
group: group,
|
group: group,
|
||||||
|
@ -142,7 +141,7 @@ abstract class Chart<T> {
|
||||||
// * Misskeyインスタンスを建てて初めてのチャート更新時など
|
// * Misskeyインスタンスを建てて初めてのチャート更新時など
|
||||||
|
|
||||||
// 空の統計を作成
|
// 空の統計を作成
|
||||||
const data = this.generateInitialStats();
|
const data = await this.generateTemplate(true);
|
||||||
|
|
||||||
const stats = await this.collection.insert({
|
const stats = await this.collection.insert({
|
||||||
group: group,
|
group: group,
|
||||||
|
@ -193,7 +192,7 @@ abstract class Chart<T> {
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
public async getStats(span: Span, range: number, group?: Obj): Promise<ArrayValue<T>> {
|
public async getStats(span: Span, range: number, group?: Obj): Promise<ArrayValue<T>> {
|
||||||
const chart: T[] = [];
|
const promisedChart: Promise<T>[] = [];
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const y = now.getFullYear();
|
const y = now.getFullYear();
|
||||||
|
@ -229,17 +228,15 @@ abstract class Chart<T> {
|
||||||
const stat = stats.find(s => s.date.getTime() == current.getTime());
|
const stat = stats.find(s => s.date.getTime() == current.getTime());
|
||||||
|
|
||||||
if (stat) {
|
if (stat) {
|
||||||
chart.unshift(stat.data);
|
promisedChart.unshift(Promise.resolve(stat.data));
|
||||||
} else { // 隙間埋め
|
} else { // 隙間埋め
|
||||||
const mostRecent = stats.find(s => s.date.getTime() < current.getTime());
|
const mostRecent = stats.find(s => s.date.getTime() < current.getTime());
|
||||||
if (mostRecent) {
|
promisedChart.unshift(this.generateTemplate(false, mostRecent ? mostRecent.data : null));
|
||||||
chart.unshift(this.generateEmptyStats(mostRecent.data));
|
|
||||||
} else {
|
|
||||||
chart.unshift(this.generateInitialStats());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const chart = await Promise.all(promisedChart);
|
||||||
|
|
||||||
const res: ArrayValue<T> = {} as any;
|
const res: ArrayValue<T> = {} as any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -323,35 +320,27 @@ type UsersStats = {
|
||||||
|
|
||||||
class UsersChart extends Chart<UsersStats> {
|
class UsersChart extends Chart<UsersStats> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super('usersStats');
|
super('users');
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
protected generateInitialStats(): UsersStats {
|
protected async generateTemplate(initial: boolean, mostRecentStats?: UsersStats): Promise<UsersStats> {
|
||||||
|
const [localCount, remoteCount] = initial ? await Promise.all([
|
||||||
|
User.count({ host: null }),
|
||||||
|
User.count({ host: { $ne: null } })
|
||||||
|
]) : [
|
||||||
|
mostRecentStats ? mostRecentStats.local.total : 0,
|
||||||
|
mostRecentStats ? mostRecentStats.remote.total : 0
|
||||||
|
];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
local: {
|
local: {
|
||||||
total: 0,
|
total: localCount,
|
||||||
inc: 0,
|
inc: 0,
|
||||||
dec: 0
|
dec: 0
|
||||||
},
|
},
|
||||||
remote: {
|
remote: {
|
||||||
total: 0,
|
total: remoteCount,
|
||||||
inc: 0,
|
|
||||||
dec: 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@autobind
|
|
||||||
protected generateEmptyStats(mostRecentStats: UsersStats): UsersStats {
|
|
||||||
return {
|
|
||||||
local: {
|
|
||||||
total: mostRecentStats.local.total,
|
|
||||||
inc: 0,
|
|
||||||
dec: 0
|
|
||||||
},
|
|
||||||
remote: {
|
|
||||||
total: mostRecentStats.remote.total,
|
|
||||||
inc: 0,
|
inc: 0,
|
||||||
dec: 0
|
dec: 0
|
||||||
}
|
}
|
||||||
|
@ -454,14 +443,22 @@ type NotesStats = {
|
||||||
|
|
||||||
class NotesChart extends Chart<NotesStats> {
|
class NotesChart extends Chart<NotesStats> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super('notesStats');
|
super('notes');
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
protected generateInitialStats(): NotesStats {
|
protected async generateTemplate(initial: boolean, mostRecentStats?: NotesStats): Promise<NotesStats> {
|
||||||
|
const [localCount, remoteCount] = initial ? await Promise.all([
|
||||||
|
Note.count({ '_user.host': null }),
|
||||||
|
Note.count({ '_user.host': { $ne: null } })
|
||||||
|
]) : [
|
||||||
|
mostRecentStats ? mostRecentStats.local.total : 0,
|
||||||
|
mostRecentStats ? mostRecentStats.remote.total : 0
|
||||||
|
];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
local: {
|
local: {
|
||||||
total: 0,
|
total: localCount,
|
||||||
inc: 0,
|
inc: 0,
|
||||||
dec: 0,
|
dec: 0,
|
||||||
diffs: {
|
diffs: {
|
||||||
|
@ -471,33 +468,7 @@ class NotesChart extends Chart<NotesStats> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
remote: {
|
remote: {
|
||||||
total: 0,
|
total: remoteCount,
|
||||||
inc: 0,
|
|
||||||
dec: 0,
|
|
||||||
diffs: {
|
|
||||||
normal: 0,
|
|
||||||
reply: 0,
|
|
||||||
renote: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@autobind
|
|
||||||
protected generateEmptyStats(mostRecentStats: NotesStats): NotesStats {
|
|
||||||
return {
|
|
||||||
local: {
|
|
||||||
total: mostRecentStats.local.total,
|
|
||||||
inc: 0,
|
|
||||||
dec: 0,
|
|
||||||
diffs: {
|
|
||||||
normal: 0,
|
|
||||||
reply: 0,
|
|
||||||
renote: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
remote: {
|
|
||||||
total: mostRecentStats.remote.total,
|
|
||||||
inc: 0,
|
inc: 0,
|
||||||
dec: 0,
|
dec: 0,
|
||||||
diffs: {
|
diffs: {
|
||||||
|
@ -612,45 +583,53 @@ type DriveStats = {
|
||||||
|
|
||||||
class DriveChart extends Chart<DriveStats> {
|
class DriveChart extends Chart<DriveStats> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super('driveStats');
|
super('drive');
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
protected generateInitialStats(): DriveStats {
|
protected async generateTemplate(initial: boolean, mostRecentStats?: DriveStats): Promise<DriveStats> {
|
||||||
|
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] = initial ? await Promise.all([
|
||||||
|
DriveFile.count({ 'metadata._user.host': null }),
|
||||||
|
DriveFile.count({ 'metadata._user.host': { $ne: null } }),
|
||||||
|
calcSize(true),
|
||||||
|
calcSize(false)
|
||||||
|
]) : [
|
||||||
|
mostRecentStats ? mostRecentStats.local.totalCount : 0,
|
||||||
|
mostRecentStats ? mostRecentStats.remote.totalCount : 0,
|
||||||
|
mostRecentStats ? mostRecentStats.local.totalSize : 0,
|
||||||
|
mostRecentStats ? mostRecentStats.remote.totalSize : 0
|
||||||
|
];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
local: {
|
local: {
|
||||||
totalCount: 0,
|
totalCount: localCount,
|
||||||
totalSize: 0,
|
totalSize: localSize,
|
||||||
incCount: 0,
|
incCount: 0,
|
||||||
incSize: 0,
|
incSize: 0,
|
||||||
decCount: 0,
|
decCount: 0,
|
||||||
decSize: 0
|
decSize: 0
|
||||||
},
|
},
|
||||||
remote: {
|
remote: {
|
||||||
totalCount: 0,
|
totalCount: remoteCount,
|
||||||
totalSize: 0,
|
totalSize: remoteSize,
|
||||||
incCount: 0,
|
|
||||||
incSize: 0,
|
|
||||||
decCount: 0,
|
|
||||||
decSize: 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@autobind
|
|
||||||
protected generateEmptyStats(mostRecentStats: DriveStats): DriveStats {
|
|
||||||
return {
|
|
||||||
local: {
|
|
||||||
totalCount: mostRecentStats.local.totalCount,
|
|
||||||
totalSize: mostRecentStats.local.totalSize,
|
|
||||||
incCount: 0,
|
|
||||||
incSize: 0,
|
|
||||||
decCount: 0,
|
|
||||||
decSize: 0
|
|
||||||
},
|
|
||||||
remote: {
|
|
||||||
totalCount: mostRecentStats.remote.totalCount,
|
|
||||||
totalSize: mostRecentStats.remote.totalSize,
|
|
||||||
incCount: 0,
|
incCount: 0,
|
||||||
incSize: 0,
|
incSize: 0,
|
||||||
decCount: 0,
|
decCount: 0,
|
||||||
|
@ -716,22 +695,11 @@ type NetworkStats = {
|
||||||
|
|
||||||
class NetworkChart extends Chart<NetworkStats> {
|
class NetworkChart extends Chart<NetworkStats> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super('networkStats');
|
super('network');
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
protected generateInitialStats(): NetworkStats {
|
protected async generateTemplate(initial: boolean, mostRecentStats?: NetworkStats): Promise<NetworkStats> {
|
||||||
return {
|
|
||||||
incomingRequests: 0,
|
|
||||||
outgoingRequests: 0,
|
|
||||||
totalTime: 0,
|
|
||||||
incomingBytes: 0,
|
|
||||||
outgoingBytes: 0
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@autobind
|
|
||||||
protected generateEmptyStats(mostRecentStats: NetworkStats): NetworkStats {
|
|
||||||
return {
|
return {
|
||||||
incomingRequests: 0,
|
incomingRequests: 0,
|
||||||
outgoingRequests: 0,
|
outgoingRequests: 0,
|
||||||
|
|
Loading…
Reference in a new issue