From 4e5545af384f610a56b3d19ea73c3b801b0be6c6 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Fri, 9 Jun 2017 01:03:54 +0900 Subject: [PATCH] nanka iroiro --- locales/en.yml | 4 + locales/ja.yml | 4 + package.json | 299 +++++++++--------- src/api/stream/server.ts | 20 ++ src/api/streaming.ts | 6 + src/index.ts | 6 + src/utils/stats.ts | 25 ++ src/web/app/common/scripts/home-stream.js | 18 ++ .../app/common/scripts/messaging-stream.js | 52 +-- src/web/app/common/scripts/server-stream.js | 14 + src/web/app/common/scripts/stream.js | 15 +- src/web/app/common/tags/messaging/room.tag | 16 +- .../desktop/tags/home-widgets/activity.tag | 15 +- .../app/desktop/tags/home-widgets/server.tag | 177 +++++++++++ src/web/app/desktop/tags/home.tag | 1 + src/web/app/desktop/tags/index.js | 1 + src/web/app/init.js | 4 +- 17 files changed, 472 insertions(+), 205 deletions(-) create mode 100644 src/api/stream/server.ts create mode 100644 src/utils/stats.ts create mode 100644 src/web/app/common/scripts/home-stream.js create mode 100644 src/web/app/common/scripts/server-stream.js create mode 100644 src/web/app/desktop/tags/home-widgets/server.tag diff --git a/locales/en.yml b/locales/en.yml index 6104cbdc9d..e15a7c9ae4 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -243,6 +243,10 @@ desktop: title: "Notifications" settings: "Notification settings" + mk-server-home-widget: + title: "Server info" + toggle: "Toggle views" + mk-activity-home-widget: title: "Activity" toggle: "Toggle views" diff --git a/locales/ja.yml b/locales/ja.yml index e83c0eb724..5ed1d4f1ee 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -243,6 +243,10 @@ desktop: title: "通知" settings: "通知の設定" + mk-server-home-widget: + title: "サーバー情報" + toggle: "表示を切り替え" + mk-activity-home-widget: title: "アクティビティ" toggle: "表示を切り替え" diff --git a/package.json b/package.json index fd10ea50cb..93f87561fa 100644 --- a/package.json +++ b/package.json @@ -1,150 +1,153 @@ { - "name": "misskey", - "author": "syuilo <i@syuilo.com>", - "version": "0.0.2038", - "license": "MIT", - "description": "A miniblog-based SNS", - "bugs": "https://github.com/syuilo/misskey/issues", - "repository": "https://github.com/syuilo/misskey.git", - "main": "./built/index.js", - "private": true, - "scripts": { - "config": "node ./tools/init.js", - "start": "node ./built", - "debug": "DEBUG=misskey:* node ./built", - "swagger": "node ./swagger.js", - "build": "gulp build", - "rebuild": "gulp rebuild", - "clean": "gulp clean", - "cleanall": "gulp cleanall", - "lint": "gulp lint", - "test": "gulp test" - }, - "devDependencies": { - "@types/bcryptjs": "2.4.0", - "@types/body-parser": "1.16.3", - "@types/chai": "4.0.0", - "@types/chai-http": "0.0.30", - "@types/chalk": "0.4.31", - "@types/compression": "0.0.33", - "@types/cors": "2.8.1", - "@types/debug": "0.0.29", - "@types/deep-equal": "1.0.0", - "@types/elasticsearch": "5.0.13", - "@types/event-stream": "3.3.31", - "@types/express": "4.0.35", - "@types/gm": "1.17.31", - "@types/gulp": "4.0.3", - "@types/gulp-mocha": "0.0.30", - "@types/gulp-rename": "0.0.32", - "@types/gulp-replace": "0.0.30", - "@types/gulp-tslint": "3.6.31", - "@types/gulp-typescript": "2.13.0", - "@types/gulp-uglify": "0.0.30", - "@types/gulp-util": "3.0.31", - "@types/inquirer": "0.0.34", - "@types/is-root": "1.0.0", - "@types/is-url": "1.2.28", - "@types/js-yaml": "3.5.30", - "@types/mocha": "2.2.41", - "@types/mongodb": "2.2.3", - "@types/monk": "1.0.5", - "@types/morgan": "1.7.32", - "@types/ms": "0.7.29", - "@types/multer": "0.0.34", - "@types/node": "7.0.29", - "@types/ratelimiter": "2.1.28", - "@types/redis": "2.6.0", - "@types/request": "0.0.43", - "@types/rimraf": "0.0.28", - "@types/riot": "2.6.2", - "@types/serve-favicon": "2.2.28", - "@types/uuid": "3.0.0", - "@types/webpack": "2.2.15", - "@types/webpack-stream": "3.2.7", - "@types/websocket": "0.0.33", - "chai": "4.0.2", - "chai-http": "3.0.0", - "css-loader": "0.28.4", - "event-stream": "3.3.4", - "gulp": "3.9.1", - "gulp-cssnano": "2.1.2", - "gulp-imagemin": "3.3.0", - "gulp-mocha": "4.3.1", - "gulp-pug": "3.3.0", - "gulp-rename": "1.2.2", - "gulp-replace": "0.5.4", - "gulp-tslint": "8.1.1", - "gulp-typescript": "3.1.7", - "gulp-uglify": "3.0.0", - "gulp-util": "3.0.8", - "mocha": "3.4.2", - "riot-tag-loader": "1.0.0", - "string-replace-webpack-plugin": "0.1.3", - "style-loader": "0.18.2", - "stylus": "0.54.5", - "stylus-loader": "3.0.1", - "swagger-jsdoc": "1.9.4", - "tslint": "5.4.3", - "uglify-es": "3.0.15", - "uglify-es-webpack-plugin": "0.0.2", - "uglify-js": "git+https://github.com/mishoo/UglifyJS2.git#harmony", - "webpack": "2.6.1" - }, - "dependencies": { - "accesses": "2.5.0", - "animejs": "2.0.2", - "autwh": "0.0.1", - "bcryptjs": "2.4.3", - "body-parser": "1.17.2", - "cafy": "2.4.0", - "chalk": "1.1.3", - "compression": "1.6.2", - "cors": "2.8.3", - "cropperjs": "1.0.0-rc.2", - "crypto": "0.0.3", - "debug": "2.6.8", - "deep-equal": "1.0.1", - "deepcopy": "0.6.3", - "download": "6.2.2", - "elasticsearch": "13.0.1", - "escape-regexp": "0.0.1", - "express": "4.15.3", - "file-type": "5.0.0", - "fuckadblock": "3.2.1", - "gm": "1.23.0", - "inquirer": "3.1.0", - "is-root": "1.0.0", - "is-url": "1.2.2", - "js-yaml": "3.8.4", - "mongodb": "2.2.28", - "monk": "6.0.0", - "morgan": "1.8.2", - "ms": "2.0.0", - "multer": "1.3.0", - "nprogress": "0.2.0", - "page": "1.7.1", - "pictograph": "2.0.4", - "prominence": "0.2.0", - "pug": "2.0.0-rc.2", - "ratelimiter": "3.0.3", - "recaptcha-promise": "0.1.2", - "reconnecting-websocket": "3.0.5", - "redis": "2.7.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "riot": "3.6.0", - "rndstr": "1.0.0", - "s-age": "1.1.0", - "serve-favicon": "2.4.3", - "summaly": "2.0.3", - "syuilo-password-strength": "0.0.1", - "tcp-port-used": "0.1.2", - "textarea-caret": "3.0.2", - "ts-node": "3.0.6", - "typescript": "2.3.4", - "uuid": "3.0.1", - "vhost": "3.0.2", - "websocket": "1.0.24" - } + "name": "misskey", + "author": "syuilo <i@syuilo.com>", + "version": "0.0.2038", + "license": "MIT", + "description": "A miniblog-based SNS", + "bugs": "https://github.com/syuilo/misskey/issues", + "repository": "https://github.com/syuilo/misskey.git", + "main": "./built/index.js", + "private": true, + "scripts": { + "config": "node ./tools/init.js", + "start": "node ./built", + "debug": "DEBUG=misskey:* node ./built", + "swagger": "node ./swagger.js", + "build": "gulp build", + "rebuild": "gulp rebuild", + "clean": "gulp clean", + "cleanall": "gulp cleanall", + "lint": "gulp lint", + "test": "gulp test" + }, + "devDependencies": { + "@types/bcryptjs": "2.4.0", + "@types/body-parser": "1.16.3", + "@types/chai": "4.0.0", + "@types/chai-http": "0.0.30", + "@types/chalk": "0.4.31", + "@types/compression": "0.0.33", + "@types/cors": "2.8.1", + "@types/debug": "0.0.29", + "@types/deep-equal": "1.0.0", + "@types/elasticsearch": "5.0.13", + "@types/event-stream": "3.3.31", + "@types/express": "4.0.35", + "@types/gm": "1.17.31", + "@types/gulp": "4.0.3", + "@types/gulp-mocha": "0.0.30", + "@types/gulp-rename": "0.0.32", + "@types/gulp-replace": "0.0.30", + "@types/gulp-tslint": "3.6.31", + "@types/gulp-typescript": "2.13.0", + "@types/gulp-uglify": "0.0.30", + "@types/gulp-util": "3.0.31", + "@types/inquirer": "0.0.34", + "@types/is-root": "1.0.0", + "@types/is-url": "1.2.28", + "@types/js-yaml": "3.5.30", + "@types/mocha": "2.2.41", + "@types/mongodb": "2.2.3", + "@types/monk": "1.0.5", + "@types/morgan": "1.7.32", + "@types/ms": "0.7.29", + "@types/multer": "0.0.34", + "@types/node": "7.0.29", + "@types/ratelimiter": "2.1.28", + "@types/redis": "2.6.0", + "@types/request": "0.0.43", + "@types/rimraf": "0.0.28", + "@types/riot": "2.6.2", + "@types/serve-favicon": "2.2.28", + "@types/uuid": "3.0.0", + "@types/webpack": "2.2.15", + "@types/webpack-stream": "3.2.7", + "@types/websocket": "0.0.33", + "chai": "4.0.2", + "chai-http": "3.0.0", + "css-loader": "0.28.4", + "event-stream": "3.3.4", + "gulp": "3.9.1", + "gulp-cssnano": "2.1.2", + "gulp-imagemin": "3.3.0", + "gulp-mocha": "4.3.1", + "gulp-pug": "3.3.0", + "gulp-rename": "1.2.2", + "gulp-replace": "0.5.4", + "gulp-tslint": "8.1.1", + "gulp-typescript": "3.1.7", + "gulp-uglify": "3.0.0", + "gulp-util": "3.0.8", + "mocha": "3.4.2", + "riot-tag-loader": "1.0.0", + "string-replace-webpack-plugin": "0.1.3", + "style-loader": "0.18.2", + "stylus": "0.54.5", + "stylus-loader": "3.0.1", + "swagger-jsdoc": "1.9.4", + "tslint": "5.4.3", + "uglify-es": "3.0.15", + "uglify-es-webpack-plugin": "0.0.2", + "uglify-js": "git+https://github.com/mishoo/UglifyJS2.git#harmony", + "webpack": "2.6.1" + }, + "dependencies": { + "accesses": "2.5.0", + "animejs": "2.0.2", + "autwh": "0.0.1", + "bcryptjs": "2.4.3", + "body-parser": "1.17.2", + "cafy": "2.4.0", + "chalk": "1.1.3", + "compression": "1.6.2", + "cors": "2.8.3", + "cropperjs": "1.0.0-rc.2", + "crypto": "0.0.3", + "debug": "2.6.8", + "deep-equal": "1.0.1", + "deepcopy": "0.6.3", + "diskusage": "^0.2.2", + "download": "6.2.2", + "elasticsearch": "13.0.1", + "escape-regexp": "0.0.1", + "express": "4.15.3", + "file-type": "5.0.0", + "fuckadblock": "3.2.1", + "gm": "1.23.0", + "inquirer": "3.1.0", + "is-root": "1.0.0", + "is-url": "1.2.2", + "js-yaml": "3.8.4", + "mongodb": "2.2.28", + "monk": "6.0.0", + "morgan": "1.8.2", + "ms": "2.0.0", + "multer": "1.3.0", + "nprogress": "0.2.0", + "os-utils": "0.0.14", + "page": "1.7.1", + "pictograph": "2.0.4", + "prominence": "0.2.0", + "pug": "2.0.0-rc.2", + "ratelimiter": "3.0.3", + "recaptcha-promise": "0.1.2", + "reconnecting-websocket": "3.0.5", + "redis": "2.7.1", + "request": "2.81.0", + "rimraf": "2.6.1", + "riot": "3.6.0", + "rndstr": "1.0.0", + "s-age": "1.1.0", + "serve-favicon": "2.4.3", + "summaly": "2.0.3", + "syuilo-password-strength": "0.0.1", + "tcp-port-used": "0.1.2", + "textarea-caret": "3.0.2", + "ts-node": "3.0.6", + "typescript": "2.3.4", + "uuid": "3.0.1", + "vhost": "3.0.2", + "websocket": "1.0.24", + "xev": "^2.0.0" + } } diff --git a/src/api/stream/server.ts b/src/api/stream/server.ts new file mode 100644 index 0000000000..6de5337499 --- /dev/null +++ b/src/api/stream/server.ts @@ -0,0 +1,20 @@ +import * as websocket from 'websocket'; +import Xev from 'xev'; + +const ev = new Xev(); + +export default function homeStream(request: websocket.request, connection: websocket.connection): void { + const onStats = stats => { + connection.send(JSON.stringify({ + type: 'stats', + body: stats + })); + }; + + ev.addListener('stats', onStats); + + connection.on('close', () => { + console.log('yooo'); + ev.removeListener('stats', onStats); + }); +} diff --git a/src/api/streaming.ts b/src/api/streaming.ts index e1d79481d3..c71132100c 100644 --- a/src/api/streaming.ts +++ b/src/api/streaming.ts @@ -8,6 +8,7 @@ import isNativeToken from './common/is-native-token'; import homeStream from './stream/home'; import messagingStream from './stream/messaging'; +import serverStream from './stream/server'; module.exports = (server: http.Server) => { /** @@ -20,6 +21,11 @@ module.exports = (server: http.Server) => { ws.on('request', async (request) => { const connection = request.accept(); + if (request.resourceURL.pathname === '/server') { + serverStream(request, connection); + return; + } + const user = await authenticate(connection, request.resourceURL.query.i); if (user == null) { diff --git a/src/index.ts b/src/index.ts index 0b568b5d44..da83dde108 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,17 +12,20 @@ import * as chalk from 'chalk'; // import portUsed = require('tcp-port-used'); import isRoot = require('is-root'); import { master } from 'accesses'; +import Xev from 'xev'; import Logger from './utils/logger'; import ProgressBar from './utils/cli/progressbar'; import EnvironmentInfo from './utils/environmentInfo'; import MachineInfo from './utils/machineInfo'; import DependencyInfo from './utils/dependencyInfo'; +import stats from './utils/stats'; import { Config, path as configPath } from './config'; import loadConfig from './config'; const clusterLog = debug('misskey:cluster'); +const ev = new Xev(); process.title = 'Misskey'; @@ -35,6 +38,9 @@ main(); function main() { if (cluster.isMaster) { masterMain(); + + ev.mount(); + stats(); } else { workerMain(); } diff --git a/src/utils/stats.ts b/src/utils/stats.ts new file mode 100644 index 0000000000..1615268310 --- /dev/null +++ b/src/utils/stats.ts @@ -0,0 +1,25 @@ +import * as os from 'os'; +const osUtils = require('os-utils'); +import * as diskusage from 'diskusage'; +import Xev from 'xev'; + +const ev = new Xev(); + +/** + * Report stats regularly + */ +export default function() { + setInterval(() => { + osUtils.cpuUsage(cpuUsage => { + const disk = diskusage.checkSync(os.platform() == 'win32' ? 'c:' : '/'); + ev.emit('stats', { + cpu_usage: cpuUsage, + mem: { + total: os.totalmem(), + free: os.freemem() + }, + disk + }); + }); + }, 1000); +} diff --git a/src/web/app/common/scripts/home-stream.js b/src/web/app/common/scripts/home-stream.js new file mode 100644 index 0000000000..24f13cd291 --- /dev/null +++ b/src/web/app/common/scripts/home-stream.js @@ -0,0 +1,18 @@ +'use strict'; + +import Stream from './stream'; + +/** + * Home stream connection + */ +class Connection extends Stream { + constructor(me) { + super('', { + i: me.token + }); + + this.on('i_updated', me.update); + } +} + +export default Connection; diff --git a/src/web/app/common/scripts/messaging-stream.js b/src/web/app/common/scripts/messaging-stream.js index 50d41c2be9..261525d5f6 100644 --- a/src/web/app/common/scripts/messaging-stream.js +++ b/src/web/app/common/scripts/messaging-stream.js @@ -1,42 +1,22 @@ -const ReconnectingWebSocket = require('reconnecting-websocket'); -import * as riot from 'riot'; -import CONFIG from './config'; +'use strict'; -class Connection { +import Stream from './stream'; + +/** + * Messaging stream connection + */ +class Connection extends Stream { constructor(me, otherparty) { - // BIND ----------------------------------- - this.onOpen = this.onOpen.bind(this); - this.onMessage = this.onMessage.bind(this); - this.close = this.close.bind(this); - // ---------------------------------------- + super('messaging', { + i: me.token, + otherparty + }); - this.event = riot.observable(); - this.me = me; - - const host = CONFIG.apiUrl.replace('http', 'ws'); - this.socket = new ReconnectingWebSocket(`${host}/messaging?i=${me.token}&otherparty=${otherparty}`); - this.socket.addEventListener('open', this.onOpen); - this.socket.addEventListener('message', this.onMessage); - } - - onOpen() { - this.socket.send(JSON.stringify({ - i: this.me.token - })); - } - - onMessage(message) { - try { - const msg = JSON.parse(message.data); - if (msg.type) this.event.trigger(msg.type, msg.body); - } catch(e) { - // noop - } - } - - close() { - this.socket.removeEventListener('open', this.onOpen); - this.socket.removeEventListener('message', this.onMessage); + this.on('_connected_', () => { + this.send({ + i: me.token + }); + }); } } diff --git a/src/web/app/common/scripts/server-stream.js b/src/web/app/common/scripts/server-stream.js new file mode 100644 index 0000000000..a1c466b35d --- /dev/null +++ b/src/web/app/common/scripts/server-stream.js @@ -0,0 +1,14 @@ +'use strict'; + +import Stream from './stream'; + +/** + * Server stream connection + */ +class Connection extends Stream { + constructor() { + super('server'); + } +} + +export default Connection; diff --git a/src/web/app/common/scripts/stream.js b/src/web/app/common/scripts/stream.js index ac3dd67153..981118b5de 100644 --- a/src/web/app/common/scripts/stream.js +++ b/src/web/app/common/scripts/stream.js @@ -5,10 +5,10 @@ import * as riot from 'riot'; import CONFIG from './config'; /** - * Home stream connection + * Misskey stream connection */ class Connection { - constructor(me) { + constructor(endpoint, params) { // BIND ----------------------------------- this.onOpen = this.onOpen.bind(this); this.onClose = this.onClose.bind(this); @@ -20,16 +20,19 @@ class Connection { riot.observable(this); this.state = 'initializing'; - this.me = me; this.buffer = []; const host = CONFIG.apiUrl.replace('http', 'ws'); - this.socket = new ReconnectingWebSocket(`${host}?i=${me.token}`); + const query = params + ? Object.keys(params) + .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) + .join('&') + : null; + + this.socket = new ReconnectingWebSocket(`${host}/${endpoint}${query ? '?' + query : ''}`); this.socket.addEventListener('open', this.onOpen); this.socket.addEventListener('close', this.onClose); this.socket.addEventListener('message', this.onMessage); - - this.on('i_updated', me.update); } /** diff --git a/src/web/app/common/tags/messaging/room.tag b/src/web/app/common/tags/messaging/room.tag index bd49a4d782..93f07f2cee 100644 --- a/src/web/app/common/tags/messaging/room.tag +++ b/src/web/app/common/tags/messaging/room.tag @@ -137,8 +137,8 @@ this.connection = new MessagingStreamConnection(this.I, this.user.id); this.on('mount', () => { - this.connection.event.on('message', this.onMessage); - this.connection.event.on('read', this.onRead); + this.connection.on('message', this.onMessage); + this.connection.on('read', this.onRead); document.addEventListener('visibilitychange', this.onVisibilitychange); @@ -153,8 +153,8 @@ }); this.on('unmount', () => { - this.connection.event.off('message', this.onMessage); - this.connection.event.off('read', this.onRead); + this.connection.off('message', this.onMessage); + this.connection.off('read', this.onRead); this.connection.close(); document.removeEventListener('visibilitychange', this.onVisibilitychange); @@ -174,10 +174,10 @@ this.messages.push(message); if (message.user_id != this.I.id && !document.hidden) { - this.connection.socket.send(JSON.stringify({ + this.connection.send({ type: 'read', id: message.id - })); + }); } this.update(); @@ -239,10 +239,10 @@ if (document.hidden) return; this.messages.forEach(message => { if (message.user_id !== this.I.id && !message.is_read) { - this.connection.socket.send(JSON.stringify({ + this.connection.send({ type: 'read', id: message.id - })); + }); } }); }; diff --git a/src/web/app/desktop/tags/home-widgets/activity.tag b/src/web/app/desktop/tags/home-widgets/activity.tag index 621702fa17..3a8afdfa33 100644 --- a/src/web/app/desktop/tags/home-widgets/activity.tag +++ b/src/web/app/desktop/tags/home-widgets/activity.tag @@ -100,6 +100,8 @@ </svg> <style> :scope + display block + > svg display block padding 10px @@ -131,7 +133,7 @@ </mk-activity-home-widget-calender> <mk-activity-home-widget-chart> - <svg riot-viewBox="0 0 { viewBoxX } 60" preserveAspectRatio="none" onmousedown={ onMousedown }> + <svg riot-viewBox="0 0 { viewBoxX } { viewBoxY }" preserveAspectRatio="none" onmousedown={ onMousedown }> <polyline riot-points={ pointsPost } fill="none" @@ -155,6 +157,8 @@ </svg> <style> :scope + display block + > svg display block padding 10px @@ -163,6 +167,7 @@ </style> <script> this.viewBoxX = 140; + this.viewBoxY = 60; this.zoom = 1; this.pos = 0; @@ -176,10 +181,10 @@ this.render = () => { this.update({ - pointsPost: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.posts / peak)) * 60}`).join(' '), - pointsReply: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.replies / peak)) * 60}`).join(' '), - pointsRepost: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.reposts / peak)) * 60}`).join(' '), - pointsTotal: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.total / peak)) * 60}`).join(' ') + pointsPost: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.posts / peak)) * this.viewBoxY}`).join(' '), + pointsReply: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.replies / peak)) * this.viewBoxY}`).join(' '), + pointsRepost: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.reposts / peak)) * this.viewBoxY}`).join(' '), + pointsTotal: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.total / peak)) * this.viewBoxY}`).join(' ') }); }; diff --git a/src/web/app/desktop/tags/home-widgets/server.tag b/src/web/app/desktop/tags/home-widgets/server.tag new file mode 100644 index 0000000000..7a51299585 --- /dev/null +++ b/src/web/app/desktop/tags/home-widgets/server.tag @@ -0,0 +1,177 @@ +<mk-server-home-widget> + <p class="title"><i class="fa fa-server"></i>%i18n:desktop.tags.mk-server-home-widget.title%</p> + <button onclick={ toggle } title="%i18n:desktop.tags.mk-server-home-widget.toggle%"><i class="fa fa-sort"></i></button> + <p class="initializing" if={ initializing }><i class="fa fa-spinner fa-pulse fa-fw"></i>%i18n:common.loading%<mk-ellipsis/></p> + <mk-server-home-widget-stats if={ !initializing && view == 0 }/> + <mk-server-home-widget-info if={ !initializing && view == 1 } meta={ meta }/> + <style> + :scope + display block + background #fff + + > .title + z-index 1 + margin 0 + padding 0 16px + line-height 42px + font-size 0.9em + font-weight bold + color #888 + box-shadow 0 1px rgba(0, 0, 0, 0.07) + + > i + margin-right 4px + + > button + position absolute + z-index 2 + top 0 + right 0 + padding 0 + width 42px + font-size 0.9em + line-height 42px + color #ccc + + &:hover + color #aaa + + &:active + color #999 + + > .initializing + margin 0 + padding 16px + text-align center + color #aaa + + > i + margin-right 4px + + </style> + <script> + this.mixin('api'); + + this.initializing = true; + this.view = 0; + + this.on('mount', () => { + this.api('meta').then(meta => { + this.update({ + initializing: false, + meta + }); + }); + }); + + this.toggle = () => { + this.view++; + if (this.view == 2) this.view = 0; + }; + </script> +</mk-server-home-widget> + +<mk-server-home-widget-stats> + <svg riot-viewBox="0 0 { viewBoxX } { viewBoxY }" preserveAspectRatio="none"> + <text dx="1" dy="5">CPU</text> + <polygon + riot-points={ cpuPolygonPoints } + riot-fill={ cpuColor } + fill-opacity="0.5"/> + <polyline + riot-points={ cpuPolylinePoints } + fill="none" + stroke-width="1" + riot-stroke={ cpuColor }/> + </svg> + <svg riot-viewBox="0 0 { viewBoxX } { viewBoxY }" preserveAspectRatio="none"> + <text dx="1" dy="5">MEM</text> + <polygon + riot-points={ memPolygonPoints } + riot-fill={ memColor } + fill-opacity="0.5"/> + <polyline + riot-points={ memPolylinePoints } + fill="none" + stroke-width="1" + riot-stroke={ memColor }/> + </svg> + <style> + :scope + display block + + > svg + display block + padding 10px + width 50% + float left + + &:first-child + padding-right 5px + + &:last-child + padding-left 5px + + > text + font-size 5px + fill #7b7b7b + + &:after + content "" + display block + clear both + </style> + <script> + import Connection from '../../../common/scripts/server-stream'; + + this.viewBoxX = 50; + this.viewBoxY = 30; + this.stats = []; + this.connection = new Connection(); + + this.on('mount', () => { + this.connection.on('stats', this.onStats); + }); + + this.on('unmount', () => { + this.connection.off('stats', this.onStats); + this.connection.close(); + }); + + this.onStats = stats => { + this.stats.push(stats); + if (this.stats.length > 50) this.stats.shift(); + + const cpuPolylinePoints = this.stats.map((s, i) => `${this.viewBoxX - ((this.stats.length - 1) - i)},${(1 - s.cpu_usage) * this.viewBoxY}`).join(' '); + const memPolylinePoints = this.stats.map((s, i) => `${this.viewBoxX - ((this.stats.length - 1) - i)},${(s.mem.free / s.mem.total) * this.viewBoxY}`).join(' '); + + const cpuPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${ this.viewBoxY } ${ cpuPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`; + const memPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${ this.viewBoxY } ${ memPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`; + + const cpuColor = `hsl(${180 - (stats.cpu_usage * 180)}, 80%, 70%)`; + const memColor = `hsl(${180 - (stats.mem.free / stats.mem.total * 180)}, 80%, 70%)`; + + this.update({ + cpuPolylinePoints, + memPolylinePoints, + cpuPolygonPoints, + memPolygonPoints, + cpuColor, + memColor + }); + }; + </script> +</mk-server-home-widget-stats> + +<mk-server-home-widget-info> + <p>Maintainer: { meta.maintainer }</p> + <style> + :scope + display block + padding 10px + </style> + <script> + this.meta = this.opts.meta; + </script> +</mk-server-home-widget-info> + diff --git a/src/web/app/desktop/tags/home.tag b/src/web/app/desktop/tags/home.tag index 0e4a2ced10..41053ccbbe 100644 --- a/src/web/app/desktop/tags/home.tag +++ b/src/web/app/desktop/tags/home.tag @@ -70,6 +70,7 @@ 'rss-reader', 'trends', 'photo-stream', + 'server', 'version' ], right: [ diff --git a/src/web/app/desktop/tags/index.js b/src/web/app/desktop/tags/index.js index 1e0ebd44cf..177ba41293 100644 --- a/src/web/app/desktop/tags/index.js +++ b/src/web/app/desktop/tags/index.js @@ -45,6 +45,7 @@ require('./home-widgets/version.tag'); require('./home-widgets/recommended-polls.tag'); require('./home-widgets/trends.tag'); require('./home-widgets/activity.tag'); +require('./home-widgets/server.tag'); require('./timeline.tag'); require('./messaging/window.tag'); require('./messaging/room-window.tag'); diff --git a/src/web/app/init.js b/src/web/app/init.js index 17f9a2d09e..b442d36a15 100644 --- a/src/web/app/init.js +++ b/src/web/app/init.js @@ -8,7 +8,7 @@ import * as riot from 'riot'; import api from './common/scripts/api'; import signout from './common/scripts/signout'; import checkForUpdate from './common/scripts/check-for-update'; -import Connection from './common/scripts/stream'; +import Connection from './common/scripts/home-stream'; import mixin from './common/mixins'; import generateDefaultUserdata from './common/scripts/generate-default-userdata'; import CONFIG from './common/scripts/config'; @@ -95,7 +95,7 @@ export default callback => { }); } - // Init stream connection + // Init home stream connection const stream = me ? new Connection(me) : null; // ミックスイン初期化