This commit is contained in:
syuilo 2018-10-21 15:08:07 +09:00
parent a617b8dbed
commit 6b0d48423d
No known key found for this signature in database
GPG key ID: BDC4C49D06AB9D69
12 changed files with 79 additions and 79 deletions

View file

@ -10,7 +10,7 @@ import { isCollectionOrOrderedCollection, isCollection, IPerson } from '../type'
import { IDriveFile } from '../../../models/drive-file'; import { IDriveFile } from '../../../models/drive-file';
import Meta from '../../../models/meta'; import Meta from '../../../models/meta';
import htmlToMFM from '../../../mfm/html-to-mfm'; import htmlToMFM from '../../../mfm/html-to-mfm';
import { usersChart } from '../../../services/stats'; import { usersStats } from '../../../services/stats';
import { URL } from 'url'; import { URL } from 'url';
import { resolveNote } from './note'; import { resolveNote } from './note';
@ -180,7 +180,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<IU
} }
}, { upsert: true }); }, { upsert: true });
usersChart.update(user, true); usersStats.update(user, true);
//#endregion //#endregion
//#region アイコンとヘッダー画像をフェッチ //#region アイコンとヘッダー画像をフェッチ

View file

@ -1,6 +1,6 @@
import $ from 'cafy'; import $ from 'cafy';
import getParams from '../../get-params'; import getParams from '../../get-params';
import { driveChart } from '../../../../services/stats'; import { driveStats } from '../../../../services/stats';
export const meta = { export const meta = {
desc: { desc: {
@ -27,7 +27,7 @@ export default (params: any) => new Promise(async (res, rej) => {
const [ps, psErr] = getParams(meta, params); const [ps, psErr] = getParams(meta, params);
if (psErr) throw psErr; if (psErr) throw psErr;
const stats = await driveChart.getStats(ps.span as any, ps.limit); const stats = await driveStats.getChart(ps.span as any, ps.limit);
res(stats); res(stats);
}); });

View file

@ -1,6 +1,6 @@
import $ from 'cafy'; import $ from 'cafy';
import getParams from '../../get-params'; import getParams from '../../get-params';
import { networkChart } from '../../../../services/stats'; import { networkStats } from '../../../../services/stats';
export const meta = { export const meta = {
desc: { desc: {
@ -27,7 +27,7 @@ export default (params: any) => new Promise(async (res, rej) => {
const [ps, psErr] = getParams(meta, params); const [ps, psErr] = getParams(meta, params);
if (psErr) throw psErr; if (psErr) throw psErr;
const stats = await networkChart.getStats(ps.span as any, ps.limit); const stats = await networkStats.getChart(ps.span as any, ps.limit);
res(stats); res(stats);
}); });

View file

@ -1,6 +1,6 @@
import $ from 'cafy'; import $ from 'cafy';
import getParams from '../../get-params'; import getParams from '../../get-params';
import { notesChart } from '../../../../services/stats'; import { notesStats } from '../../../../services/stats';
export const meta = { export const meta = {
desc: { desc: {
@ -27,7 +27,7 @@ export default (params: any) => new Promise(async (res, rej) => {
const [ps, psErr] = getParams(meta, params); const [ps, psErr] = getParams(meta, params);
if (psErr) throw psErr; if (psErr) throw psErr;
const stats = await notesChart.getStats(ps.span as any, ps.limit); const stats = await notesStats.getChart(ps.span as any, ps.limit);
res(stats); res(stats);
}); });

View file

@ -1,6 +1,6 @@
import $ from 'cafy'; import $ from 'cafy';
import getParams from '../../get-params'; import getParams from '../../get-params';
import { usersChart } from '../../../../services/stats'; import { usersStats } from '../../../../services/stats';
export const meta = { export const meta = {
desc: { desc: {
@ -27,7 +27,7 @@ export default (params: any) => new Promise(async (res, rej) => {
const [ps, psErr] = getParams(meta, params); const [ps, psErr] = getParams(meta, params);
if (psErr) throw psErr; if (psErr) throw psErr;
const stats = await usersChart.getStats(ps.span as any, ps.limit); const stats = await usersStats.getChart(ps.span as any, ps.limit);
res(stats); res(stats);
}); });

View file

@ -7,7 +7,7 @@ import generateUserToken from '../common/generate-native-user-token';
import config from '../../../config'; import config from '../../../config';
import Meta from '../../../models/meta'; import Meta from '../../../models/meta';
import RegistrationTicket from '../../../models/registration-tickets'; import RegistrationTicket from '../../../models/registration-tickets';
import { usersChart } from '../../../services/stats'; import { usersStats } from '../../../services/stats';
if (config.recaptcha) { if (config.recaptcha) {
recaptcha.init({ recaptcha.init({
@ -130,7 +130,7 @@ export default async (ctx: Koa.Context) => {
}, { upsert: true }); }, { upsert: true });
//#endregion //#endregion
usersChart.update(account, true); usersStats.update(account, true);
const res = await pack(account, account, { const res = await pack(account, account, {
detail: true, detail: true,

View file

@ -17,7 +17,7 @@ const requestStats = require('request-stats');
import activityPub from './activitypub'; import activityPub from './activitypub';
import webFinger from './webfinger'; import webFinger from './webfinger';
import config from '../config'; import config from '../config';
import { networkChart } from '../services/stats'; import { networkStats } from '../services/stats';
import apiServer from './api'; import apiServer from './api';
// Init app // Init app
@ -104,7 +104,7 @@ export default () => new Promise(resolve => {
const outgoingBytes = queue.reduce((a, b) => a + b.res.bytes, 0); const outgoingBytes = queue.reduce((a, b) => a + b.res.bytes, 0);
queue = []; queue = [];
networkChart.update(requests, time, incomingBytes, outgoingBytes); networkStats.update(requests, time, incomingBytes, outgoingBytes);
}, 5000); }, 5000);
//#endregion //#endregion
}); });

View file

@ -17,7 +17,7 @@ import { isLocalUser, IUser, IRemoteUser } from '../../models/user';
import delFile from './delete-file'; import delFile from './delete-file';
import config from '../../config'; import config from '../../config';
import { getDriveFileThumbnailBucket } from '../../models/drive-file-thumbnail'; import { getDriveFileThumbnailBucket } from '../../models/drive-file-thumbnail';
import { driveChart } from '../stats'; import { driveStats } from '../stats';
const log = debug('misskey:drive:add-file'); const log = debug('misskey:drive:add-file');
@ -389,7 +389,7 @@ export default async function(
}); });
// 統計を更新 // 統計を更新
driveChart.update(driveFile, true); driveStats.update(driveFile, true);
return driveFile; return driveFile;
} }

View file

@ -2,7 +2,7 @@ import * as Minio from 'minio';
import DriveFile, { DriveFileChunk, IDriveFile } from '../../models/drive-file'; import DriveFile, { DriveFileChunk, IDriveFile } from '../../models/drive-file';
import DriveFileThumbnail, { DriveFileThumbnailChunk } from '../../models/drive-file-thumbnail'; import DriveFileThumbnail, { DriveFileThumbnailChunk } from '../../models/drive-file-thumbnail';
import config from '../../config'; import config from '../../config';
import { driveChart } from '../stats'; import { driveStats } from '../stats';
export default async function(file: IDriveFile, isExpired = false) { export default async function(file: IDriveFile, isExpired = false) {
if (file.metadata.storage == 'minio') { if (file.metadata.storage == 'minio') {
@ -48,5 +48,5 @@ export default async function(file: IDriveFile, isExpired = false) {
//#endregion //#endregion
// 統計を更新 // 統計を更新
driveChart.update(file, false); driveStats.update(file, false);
} }

View file

@ -23,7 +23,7 @@ import registerHashtag from '../register-hashtag';
import isQuote from '../../misc/is-quote'; import isQuote from '../../misc/is-quote';
import { TextElementMention } from '../../mfm/parse/elements/mention'; import { TextElementMention } from '../../mfm/parse/elements/mention';
import { TextElementHashtag } from '../../mfm/parse/elements/hashtag'; import { TextElementHashtag } from '../../mfm/parse/elements/hashtag';
import { notesChart } from '../stats'; import { notesStats } from '../stats';
import { erase, unique } from '../../prelude/array'; import { erase, unique } from '../../prelude/array';
import insertNoteUnread from './unread'; import insertNoteUnread from './unread';
@ -165,7 +165,7 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
} }
// 統計を更新 // 統計を更新
notesChart.update(note, true); notesStats.update(note, true);
// ハッシュタグ登録 // ハッシュタグ登録
tags.map(tag => registerHashtag(user, tag)); tags.map(tag => registerHashtag(user, tag));

View file

@ -6,7 +6,7 @@ import pack from '../../remote/activitypub/renderer';
import { deliver } from '../../queue'; import { deliver } from '../../queue';
import Following from '../../models/following'; import Following from '../../models/following';
import renderTombstone from '../../remote/activitypub/renderer/tombstone'; import renderTombstone from '../../remote/activitypub/renderer/tombstone';
import { notesChart } from '../stats'; import { notesStats } from '../stats';
import config from '../../config'; import config from '../../config';
import NoteUnread from '../../models/note-unread'; import NoteUnread from '../../models/note-unread';
import read from './read'; import read from './read';
@ -63,5 +63,5 @@ export default async function(user: IUser, note: INote) {
//#endregion //#endregion
// 統計を更新 // 統計を更新
notesChart.update(note, false); notesStats.update(note, false);
} }

View file

@ -24,7 +24,7 @@ type ArrayValue<T> = {
type Span = 'day' | 'hour'; type Span = 'day' | 'hour';
//#region Chart Core //#region Chart Core
type ChartDocument<T extends Obj> = { type Log<T extends Obj> = {
_id: mongo.ObjectID; _id: mongo.ObjectID;
/** /**
@ -56,12 +56,12 @@ type ChartDocument<T extends Obj> = {
/** /**
* *
*/ */
abstract class Chart<T> { abstract class Stats<T> {
protected collection: ICollection<ChartDocument<T>>; protected collection: ICollection<Log<T>>;
protected abstract async generateTemplate(initial: boolean, latestStats?: T): Promise<T>; protected abstract async generateTemplate(init: boolean, latestLog?: T): Promise<T>;
constructor(name: string) { constructor(name: string) {
this.collection = db.get<ChartDocument<T>>(`stats.${name}`); this.collection = db.get<Log<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');
} }
@ -87,7 +87,7 @@ abstract class Chart<T> {
} }
@autobind @autobind
private async getCurrentStats(span: Span, group?: Obj): Promise<ChartDocument<T>> { private async getCurrentLog(span: Span, group?: Obj): Promise<Log<T>> {
const now = new Date(); const now = new Date();
const y = now.getFullYear(); const y = now.getFullYear();
const m = now.getMonth(); const m = now.getMonth();
@ -100,14 +100,14 @@ abstract class Chart<T> {
null; null;
// 現在(今日または今のHour)の統計 // 現在(今日または今のHour)の統計
const currentStats = await this.collection.findOne({ const currentLog = await this.collection.findOne({
group: group, group: group,
span: span, span: span,
date: current date: current
}); });
if (currentStats) { if (currentLog) {
return currentStats; return currentLog;
} }
// 集計期間が変わってから、初めてのチャート更新なら // 集計期間が変わってから、初めてのチャート更新なら
@ -116,7 +116,7 @@ abstract class Chart<T> {
// * 昨日何もチャートを更新するような出来事がなかった場合は、 // * 昨日何もチャートを更新するような出来事がなかった場合は、
// * 統計がそもそも作られずドキュメントが存在しないということがあり得るため、 // * 統計がそもそも作られずドキュメントが存在しないということがあり得るため、
// * 「昨日の」と決め打ちせずに「もっとも最近の」とします // * 「昨日の」と決め打ちせずに「もっとも最近の」とします
const latestStats = await this.collection.findOne({ const latestLog = await this.collection.findOne({
group: group, group: group,
span: span span: span
}, { }, {
@ -125,18 +125,18 @@ abstract class Chart<T> {
} }
}); });
if (latestStats) { if (latestLog) {
// 現在の統計を初期挿入 // 現在の統計を初期挿入
const data = await this.generateTemplate(false, latestStats.data); const data = await this.generateTemplate(false, latestLog.data);
const stats = await this.collection.insert({ const log = await this.collection.insert({
group: group, group: group,
span: span, span: span,
date: current, date: current,
data: data data: data
}); });
return stats; return log;
} else { } else {
// 統計が存在しなかったら // 統計が存在しなかったら
// * Misskeyインスタンスを建てて初めてのチャート更新時など // * Misskeyインスタンスを建てて初めてのチャート更新時など
@ -144,26 +144,26 @@ abstract class Chart<T> {
// 空の統計を作成 // 空の統計を作成
const data = await this.generateTemplate(true); const data = await this.generateTemplate(true);
const stats = await this.collection.insert({ const log = await this.collection.insert({
group: group, group: group,
span: span, span: span,
date: current, date: current,
data: data data: data
}); });
return stats; return log;
} }
} }
@autobind @autobind
protected commit(query: Obj, group?: Obj, uniqueKey?: string, uniqueValue?: string): void { protected commit(query: Obj, group?: Obj, uniqueKey?: string, uniqueValue?: string): void {
const update = (stats: ChartDocument<T>) => { const update = (log: Log<T>) => {
// ユニークインクリメントの場合、指定のキーに指定の値が既に存在していたら弾く // ユニークインクリメントの場合、指定のキーに指定の値が既に存在していたら弾く
if ( if (
uniqueKey && uniqueKey &&
stats.unique && log.unique &&
stats.unique[uniqueKey] && log.unique[uniqueKey] &&
stats.unique[uniqueKey].includes(uniqueValue) log.unique[uniqueKey].includes(uniqueValue)
) return; ) return;
// ユニークインクリメントの指定のキーに値を追加 // ユニークインクリメントの指定のキーに値を追加
@ -174,12 +174,12 @@ abstract class Chart<T> {
} }
this.collection.update({ this.collection.update({
_id: stats._id _id: log._id
}, query); }, query);
}; };
this.getCurrentStats('day', group).then(stats => update(stats)); this.getCurrentLog('day', group).then(log => update(log));
this.getCurrentStats('hour', group).then(stats => update(stats)); this.getCurrentLog('hour', group).then(log => update(log));
} }
@autobind @autobind
@ -197,7 +197,7 @@ abstract class Chart<T> {
} }
@autobind @autobind
public async getStats(span: Span, range: number, group?: Obj): Promise<ArrayValue<T>> { public async getChart(span: Span, range: number, group?: Obj): Promise<ArrayValue<T>> {
const promisedChart: Promise<T>[] = []; const promisedChart: Promise<T>[] = [];
const now = new Date(); const now = new Date();
@ -210,7 +210,7 @@ abstract class Chart<T> {
span == 'day' ? new Date(y, m, d - range) : span == 'day' ? new Date(y, m, d - range) :
span == 'hour' ? new Date(y, m, d, h - range) : null; span == 'hour' ? new Date(y, m, d, h - range) : null;
const stats = await this.collection.find({ const logs = await this.collection.find({
group: group, group: group,
span: span, span: span,
date: { date: {
@ -231,12 +231,12 @@ abstract class Chart<T> {
span == 'hour' ? new Date(y, m, d, h - i) : span == 'hour' ? new Date(y, m, d, h - i) :
null; null;
const stat = stats.find(s => s.date.getTime() == current.getTime()); const log = logs.find(l => l.date.getTime() == current.getTime());
if (stat) { if (log) {
promisedChart.unshift(Promise.resolve(stat.data)); promisedChart.unshift(Promise.resolve(log.data));
} else { // 隙間埋め } else { // 隙間埋め
const latest = stats.find(s => s.date.getTime() < current.getTime()); const latest = logs.find(l => l.date.getTime() < current.getTime());
promisedChart.unshift(this.generateTemplate(false, latest ? latest.data : null)); promisedChart.unshift(this.generateTemplate(false, latest ? latest.data : null));
} }
} }
@ -288,7 +288,7 @@ abstract class Chart<T> {
/** /**
* *
*/ */
type UsersStats = { type UsersLog = {
local: { local: {
/** /**
* () * ()
@ -324,19 +324,19 @@ type UsersStats = {
}; };
}; };
class UsersChart extends Chart<UsersStats> { class UsersStats extends Stats<UsersLog> {
constructor() { constructor() {
super('users'); super('users');
} }
@autobind @autobind
protected async generateTemplate(initial: boolean, latestStats?: UsersStats): Promise<UsersStats> { protected async generateTemplate(init: boolean, latestLog?: UsersLog): Promise<UsersLog> {
const [localCount, remoteCount] = initial ? await Promise.all([ const [localCount, remoteCount] = init ? await Promise.all([
User.count({ host: null }), User.count({ host: null }),
User.count({ host: { $ne: null } }) User.count({ host: { $ne: null } })
]) : [ ]) : [
latestStats ? latestStats.local.total : 0, latestLog ? latestLog.local.total : 0,
latestStats ? latestStats.remote.total : 0 latestLog ? latestLog.remote.total : 0
]; ];
return { return {
@ -370,14 +370,14 @@ class UsersChart extends Chart<UsersStats> {
} }
} }
export const usersChart = new UsersChart(); export const usersStats = new UsersStats();
//#endregion //#endregion
//#region Notes stats //#region Notes stats
/** /**
* 稿 * 稿
*/ */
type NotesStats = { type NotesLog = {
local: { local: {
/** /**
* 稿 () * 稿 ()
@ -447,19 +447,19 @@ type NotesStats = {
}; };
}; };
class NotesChart extends Chart<NotesStats> { class NotesStats extends Stats<NotesLog> {
constructor() { constructor() {
super('notes'); super('notes');
} }
@autobind @autobind
protected async generateTemplate(initial: boolean, latestStats?: NotesStats): Promise<NotesStats> { protected async generateTemplate(init: boolean, latestLog?: NotesLog): Promise<NotesLog> {
const [localCount, remoteCount] = initial ? await Promise.all([ const [localCount, remoteCount] = init ? await Promise.all([
Note.count({ '_user.host': null }), Note.count({ '_user.host': null }),
Note.count({ '_user.host': { $ne: null } }) Note.count({ '_user.host': { $ne: null } })
]) : [ ]) : [
latestStats ? latestStats.local.total : 0, latestLog ? latestLog.local.total : 0,
latestStats ? latestStats.remote.total : 0 latestLog ? latestLog.remote.total : 0
]; ];
return { return {
@ -514,14 +514,14 @@ class NotesChart extends Chart<NotesStats> {
} }
} }
export const notesChart = new NotesChart(); export const notesStats = new NotesStats();
//#endregion //#endregion
//#region Drive stats //#region Drive stats
/** /**
* *
*/ */
type DriveStats = { type DriveLog = {
local: { local: {
/** /**
* () * ()
@ -587,13 +587,13 @@ type DriveStats = {
}; };
}; };
class DriveChart extends Chart<DriveStats> { class DriveStats extends Stats<DriveLog> {
constructor() { constructor() {
super('drive'); super('drive');
} }
@autobind @autobind
protected async generateTemplate(initial: boolean, latestStats?: DriveStats): Promise<DriveStats> { protected async generateTemplate(init: boolean, latestLog?: DriveLog): Promise<DriveLog> {
const calcSize = (local: boolean) => DriveFile const calcSize = (local: boolean) => DriveFile
.aggregate([{ .aggregate([{
$match: { $match: {
@ -612,16 +612,16 @@ class DriveChart extends Chart<DriveStats> {
}]) }])
.then(res => res.length > 0 ? res[0].usage : 0); .then(res => res.length > 0 ? res[0].usage : 0);
const [localCount, remoteCount, localSize, remoteSize] = initial ? await Promise.all([ const [localCount, remoteCount, localSize, remoteSize] = init ? await Promise.all([
DriveFile.count({ 'metadata._user.host': null }), DriveFile.count({ 'metadata._user.host': null }),
DriveFile.count({ 'metadata._user.host': { $ne: null } }), DriveFile.count({ 'metadata._user.host': { $ne: null } }),
calcSize(true), calcSize(true),
calcSize(false) calcSize(false)
]) : [ ]) : [
latestStats ? latestStats.local.totalCount : 0, latestLog ? latestLog.local.totalCount : 0,
latestStats ? latestStats.remote.totalCount : 0, latestLog ? latestLog.remote.totalCount : 0,
latestStats ? latestStats.local.totalSize : 0, latestLog ? latestLog.local.totalSize : 0,
latestStats ? latestStats.remote.totalSize : 0 latestLog ? latestLog.remote.totalSize : 0
]; ];
return { return {
@ -664,14 +664,14 @@ class DriveChart extends Chart<DriveStats> {
} }
} }
export const driveChart = new DriveChart(); export const driveStats = new DriveStats();
//#endregion //#endregion
//#region Network stats //#region Network stats
/** /**
* *
*/ */
type NetworkStats = { type NetworkLog = {
/** /**
* *
*/ */
@ -699,13 +699,13 @@ type NetworkStats = {
outgoingBytes: number; outgoingBytes: number;
}; };
class NetworkChart extends Chart<NetworkStats> { class NetworkStats extends Stats<NetworkLog> {
constructor() { constructor() {
super('network'); super('network');
} }
@autobind @autobind
protected async generateTemplate(initial: boolean, latestStats?: NetworkStats): Promise<NetworkStats> { protected async generateTemplate(init: boolean, latestLog?: NetworkLog): Promise<NetworkLog> {
return { return {
incomingRequests: 0, incomingRequests: 0,
outgoingRequests: 0, outgoingRequests: 0,
@ -717,7 +717,7 @@ class NetworkChart extends Chart<NetworkStats> {
@autobind @autobind
public async update(incomingRequests: number, time: number, incomingBytes: number, outgoingBytes: number) { public async update(incomingRequests: number, time: number, incomingBytes: number, outgoingBytes: number) {
const inc: Partial<NetworkStats> = { const inc: Partial<NetworkLog> = {
incomingRequests: incomingRequests, incomingRequests: incomingRequests,
totalTime: time, totalTime: time,
incomingBytes: incomingBytes, incomingBytes: incomingBytes,
@ -728,5 +728,5 @@ class NetworkChart extends Chart<NetworkStats> {
} }
} }
export const networkChart = new NetworkChart(); export const networkStats = new NetworkStats();
//#endregion //#endregion