From c78945436e39121f46e083eac7a6572ca2efe2d2 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 9 Jun 2018 04:14:26 +0900 Subject: [PATCH] #1686 --- locales/ja.yml | 5 + package.json | 2 +- .../streaming/{server.ts => notes-stats.ts} | 10 +- .../common/scripts/streaming/server-stats.ts | 30 +++ src/client/app/common/views/widgets/index.ts | 2 + .../common/views/widgets/posts-monitor.vue | 182 ++++++++++++++++++ .../app/common/views/widgets/server.vue | 6 +- .../app/desktop/views/components/home.vue | 1 + .../views/pages/deck/deck.widgets-column.vue | 1 + src/client/app/mios.ts | 12 +- src/client/app/mobile/views/pages/widgets.vue | 1 + src/db/mongodb.ts | 5 +- src/index.ts | 2 + src/models/note.ts | 3 + src/notes-stats-child.ts | 20 ++ src/notes-stats.ts | 20 ++ src/server-stats.ts | 2 +- src/server/api/stream/notes-stats.ts | 35 ++++ .../api/stream/{server.ts => server-stats.ts} | 0 src/server/api/streaming.ts | 12 +- 20 files changed, 333 insertions(+), 18 deletions(-) rename src/client/app/common/scripts/streaming/{server.ts => notes-stats.ts} (57%) create mode 100644 src/client/app/common/scripts/streaming/server-stats.ts create mode 100644 src/client/app/common/views/widgets/posts-monitor.vue create mode 100644 src/notes-stats-child.ts create mode 100644 src/notes-stats.ts create mode 100644 src/server/api/stream/notes-stats.ts rename src/server/api/stream/{server.ts => server-stats.ts} (100%) diff --git a/locales/ja.yml b/locales/ja.yml index 120ccc7998..212ba90b69 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -63,6 +63,7 @@ common: memo: "メモ" trends: "トレンド" photo-stream: "フォトストリーム" + posts-monitor: "投稿チャート" slideshow: "スライドショー" version: "バージョン" broadcast: "ブロードキャスト" @@ -249,6 +250,10 @@ common/views/widgets/photo-stream.vue: title: "フォトストリーム" no-photos: "写真はありません" +common/views/widgets/posts-monitor.vue: + title: "投稿チャート" + toggle: "表示を切り替え" + common/views/widgets/server.vue: title: "サーバー情報" toggle: "表示を切り替え" diff --git a/package.json b/package.json index b0ad03aa6e..a18f37e0a2 100644 --- a/package.json +++ b/package.json @@ -152,7 +152,7 @@ "mkdirp": "0.5.1", "mocha": "5.2.0", "moji": "0.5.1", - "mongodb": "3.0.8", + "mongodb": "3.0.10", "monk": "6.0.6", "ms": "2.1.1", "nan": "2.10.0", diff --git a/src/client/app/common/scripts/streaming/server.ts b/src/client/app/common/scripts/streaming/notes-stats.ts similarity index 57% rename from src/client/app/common/scripts/streaming/server.ts rename to src/client/app/common/scripts/streaming/notes-stats.ts index 2ea4239288..9e3e78a709 100644 --- a/src/client/app/common/scripts/streaming/server.ts +++ b/src/client/app/common/scripts/streaming/notes-stats.ts @@ -3,15 +3,15 @@ import StreamManager from './stream-manager'; import MiOS from '../../../mios'; /** - * Server stream connection + * Notes stats stream connection */ -export class ServerStream extends Stream { +export class NotesStatsStream extends Stream { constructor(os: MiOS) { - super(os, 'server'); + super(os, 'notes-stats'); } } -export class ServerStreamManager extends StreamManager { +export class NotesStatsStreamManager extends StreamManager { private os: MiOS; constructor(os: MiOS) { @@ -22,7 +22,7 @@ export class ServerStreamManager extends StreamManager { public getConnection() { if (this.connection == null) { - this.connection = new ServerStream(this.os); + this.connection = new NotesStatsStream(this.os); } return this.connection; diff --git a/src/client/app/common/scripts/streaming/server-stats.ts b/src/client/app/common/scripts/streaming/server-stats.ts new file mode 100644 index 0000000000..9983dfcaf0 --- /dev/null +++ b/src/client/app/common/scripts/streaming/server-stats.ts @@ -0,0 +1,30 @@ +import Stream from './stream'; +import StreamManager from './stream-manager'; +import MiOS from '../../../mios'; + +/** + * Server stats stream connection + */ +export class ServerStatsStream extends Stream { + constructor(os: MiOS) { + super(os, 'server-stats'); + } +} + +export class ServerStatsStreamManager extends StreamManager { + private os: MiOS; + + constructor(os: MiOS) { + super(); + + this.os = os; + } + + public getConnection() { + if (this.connection == null) { + this.connection = new ServerStatsStream(this.os); + } + + return this.connection; + } +} diff --git a/src/client/app/common/views/widgets/index.ts b/src/client/app/common/views/widgets/index.ts index a4cabc43ba..0190393ba7 100644 --- a/src/client/app/common/views/widgets/index.ts +++ b/src/client/app/common/views/widgets/index.ts @@ -4,6 +4,7 @@ import wAnalogClock from './analog-clock.vue'; import wVersion from './version.vue'; import wRss from './rss.vue'; import wServer from './server.vue'; +import wPostsMonitor from './posts-monitor.vue'; import wMemo from './memo.vue'; import wBroadcast from './broadcast.vue'; import wCalendar from './calendar.vue'; @@ -22,6 +23,7 @@ Vue.component('mkw-tips', wTips); Vue.component('mkw-donation', wDonation); Vue.component('mkw-broadcast', wBroadcast); Vue.component('mkw-server', wServer); +Vue.component('mkw-posts-monitor', wPostsMonitor); Vue.component('mkw-memo', wMemo); Vue.component('mkw-rss', wRss); Vue.component('mkw-version', wVersion); diff --git a/src/client/app/common/views/widgets/posts-monitor.vue b/src/client/app/common/views/widgets/posts-monitor.vue new file mode 100644 index 0000000000..bdf811bad0 --- /dev/null +++ b/src/client/app/common/views/widgets/posts-monitor.vue @@ -0,0 +1,182 @@ + + + + + diff --git a/src/client/app/common/views/widgets/server.vue b/src/client/app/common/views/widgets/server.vue index 2fdd60499b..d796a3ae05 100644 --- a/src/client/app/common/views/widgets/server.vue +++ b/src/client/app/common/views/widgets/server.vue @@ -55,11 +55,11 @@ export default define({ this.fetching = false; }); - this.connection = (this as any).os.streams.serverStream.getConnection(); - this.connectionId = (this as any).os.streams.serverStream.use(); + this.connection = (this as any).os.streams.serverStatsStream.getConnection(); + this.connectionId = (this as any).os.streams.serverStatsStream.use(); }, beforeDestroy() { - (this as any).os.streams.serverStream.dispose(this.connectionId); + (this as any).os.streams.serverStatsStream.dispose(this.connectionId); }, methods: { toggle() { diff --git a/src/client/app/desktop/views/components/home.vue b/src/client/app/desktop/views/components/home.vue index 826753c169..cac1fd935b 100644 --- a/src/client/app/desktop/views/components/home.vue +++ b/src/client/app/desktop/views/components/home.vue @@ -23,6 +23,7 @@ + diff --git a/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue b/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue index 098a580405..2a3a2472dc 100644 --- a/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue +++ b/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue @@ -23,6 +23,7 @@ + diff --git a/src/client/app/mios.ts b/src/client/app/mios.ts index c644e22087..ba3f967a23 100644 --- a/src/client/app/mios.ts +++ b/src/client/app/mios.ts @@ -8,7 +8,8 @@ import Progress from './common/scripts/loading'; import Connection from './common/scripts/streaming/stream'; import { HomeStreamManager } from './common/scripts/streaming/home'; import { DriveStreamManager } from './common/scripts/streaming/drive'; -import { ServerStreamManager } from './common/scripts/streaming/server'; +import { ServerStatsStreamManager } from './common/scripts/streaming/server-stats'; +import { NotesStatsStreamManager } from './common/scripts/streaming/notes-stats'; import { MessagingIndexStreamManager } from './common/scripts/streaming/messaging-index'; import { OthelloStreamManager } from './common/scripts/streaming/othello'; @@ -104,14 +105,16 @@ export default class MiOS extends EventEmitter { localTimelineStream: LocalTimelineStreamManager; globalTimelineStream: GlobalTimelineStreamManager; driveStream: DriveStreamManager; - serverStream: ServerStreamManager; + serverStatsStream: ServerStatsStreamManager; + notesStatsStream: NotesStatsStreamManager; messagingIndexStream: MessagingIndexStreamManager; othelloStream: OthelloStreamManager; } = { localTimelineStream: null, globalTimelineStream: null, driveStream: null, - serverStream: null, + serverStatsStream: null, + notesStatsStream: null, messagingIndexStream: null, othelloStream: null }; @@ -218,7 +221,8 @@ export default class MiOS extends EventEmitter { this.store = initStore(this); //#region Init stream managers - this.streams.serverStream = new ServerStreamManager(this); + this.streams.serverStatsStream = new ServerStatsStreamManager(this); + this.streams.notesStatsStream = new NotesStatsStreamManager(this); this.once('signedin', () => { // Init home stream manager diff --git a/src/client/app/mobile/views/pages/widgets.vue b/src/client/app/mobile/views/pages/widgets.vue index eab0ca6a38..ea8580b4d0 100644 --- a/src/client/app/mobile/views/pages/widgets.vue +++ b/src/client/app/mobile/views/pages/widgets.vue @@ -15,6 +15,7 @@ + diff --git a/src/db/mongodb.ts b/src/db/mongodb.ts index 05bb72bfde..0f6d27ca15 100644 --- a/src/db/mongodb.ts +++ b/src/db/mongodb.ts @@ -12,7 +12,10 @@ const uri = u && p */ import mongo from 'monk'; -const db = mongo(uri); +const db = mongo(uri, { + poolSize: 16, + keepAlive: 1 +}); export default db; diff --git a/src/index.ts b/src/index.ts index 42a4f484e6..4a98b7564c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -18,6 +18,7 @@ import EnvironmentInfo from './utils/environmentInfo'; import MachineInfo from './utils/machineInfo'; import DependencyInfo from './utils/dependencyInfo'; import serverStats from './server-stats'; +import notesStats from './notes-stats'; import loadConfig from './config/load'; import { Config } from './config/types'; @@ -50,6 +51,7 @@ function main() { ev.mount(); serverStats(); + notesStats(); } else { workerMain(opt); } diff --git a/src/models/note.ts b/src/models/note.ts index ad8c1565f0..d4681b7b70 100644 --- a/src/models/note.ts +++ b/src/models/note.ts @@ -16,6 +16,9 @@ import Following from './following'; const Note = db.get('notes'); Note.createIndex('uri', { sparse: true, unique: true }); Note.createIndex('userId'); +Note.createIndex({ + createdAt: -1 +}); export default Note; export function isValidText(text: string): boolean { diff --git a/src/notes-stats-child.ts b/src/notes-stats-child.ts new file mode 100644 index 0000000000..0e0f14eaf1 --- /dev/null +++ b/src/notes-stats-child.ts @@ -0,0 +1,20 @@ +import Note from './models/note'; + +setInterval(async () => { + const [all, local] = await Promise.all([Note.count({ + createdAt: { + $gte: new Date(Date.now() - 3000) + } + }), Note.count({ + createdAt: { + $gte: new Date(Date.now() - 3000) + }, + '_user.host': null + })]); + + const stats = { + all, local + }; + + process.send(stats); +}, 3000); diff --git a/src/notes-stats.ts b/src/notes-stats.ts new file mode 100644 index 0000000000..3094c34af0 --- /dev/null +++ b/src/notes-stats.ts @@ -0,0 +1,20 @@ +import * as childProcess from 'child_process'; +import Xev from 'xev'; + +const ev = new Xev(); + +export default function() { + const log = []; + + const p = childProcess.fork(__dirname + '/notes-stats-child.js'); + + p.on('message', stats => { + ev.emit('notesStats', stats); + log.push(stats); + if (log.length > 100) log.shift(); + }); + + ev.on('requestNotesStatsLog', id => { + ev.emit('notesStatsLog:' + id, log); + }); +} diff --git a/src/server-stats.ts b/src/server-stats.ts index 85aa85b682..7b0d4a8576 100644 --- a/src/server-stats.ts +++ b/src/server-stats.ts @@ -6,7 +6,7 @@ import Xev from 'xev'; const ev = new Xev(); /** - * Report stats regularly + * Report server stats regularly */ export default function() { const log = []; diff --git a/src/server/api/stream/notes-stats.ts b/src/server/api/stream/notes-stats.ts new file mode 100644 index 0000000000..739b325848 --- /dev/null +++ b/src/server/api/stream/notes-stats.ts @@ -0,0 +1,35 @@ +import * as websocket from 'websocket'; +import Xev from 'xev'; + +const ev = new Xev(); + +export default function(request: websocket.request, connection: websocket.connection): void { + const onStats = stats => { + connection.send(JSON.stringify({ + type: 'stats', + body: stats + })); + }; + + connection.on('message', async data => { + const msg = JSON.parse(data.utf8Data); + + switch (msg.type) { + case 'requestLog': + ev.once('notesStatsLog:' + msg.id, statsLog => { + connection.send(JSON.stringify({ + type: 'statsLog', + body: statsLog + })); + }); + ev.emit('requestNotesStatsLog', msg.id); + break; + } + }); + + ev.addListener('notesStats', onStats); + + connection.on('close', () => { + ev.removeListener('notesStats', onStats); + }); +} diff --git a/src/server/api/stream/server.ts b/src/server/api/stream/server-stats.ts similarity index 100% rename from src/server/api/stream/server.ts rename to src/server/api/stream/server-stats.ts diff --git a/src/server/api/streaming.ts b/src/server/api/streaming.ts index 6825b6336a..2d4cfc108f 100644 --- a/src/server/api/streaming.ts +++ b/src/server/api/streaming.ts @@ -12,7 +12,8 @@ import messagingStream from './stream/messaging'; import messagingIndexStream from './stream/messaging-index'; import othelloGameStream from './stream/othello-game'; import othelloStream from './stream/othello'; -import serverStream from './stream/server'; +import serverStatsStream from './stream/server-stats'; +import notesStatsStream from './stream/notes-stats'; import requestsStream from './stream/requests'; import { ParsedUrlQuery } from 'querystring'; import authenticate from './authenticate'; @@ -28,8 +29,13 @@ module.exports = (server: http.Server) => { ws.on('request', async (request) => { const connection = request.accept(); - if (request.resourceURL.pathname === '/server') { - serverStream(request, connection); + if (request.resourceURL.pathname === '/server-stats') { + serverStatsStream(request, connection); + return; + } + + if (request.resourceURL.pathname === '/notes-stats') { + notesStatsStream(request, connection); return; }