From 68b1721ecf65484c1b679404246edc3627346c1b Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 8 Nov 2017 23:43:47 +0900 Subject: なんかもうめっちゃやった MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/scripts/generate-default-userdata.js | 45 ---------------------- 1 file changed, 45 deletions(-) delete mode 100644 src/web/app/common/scripts/generate-default-userdata.js (limited to 'src/web/app/common') diff --git a/src/web/app/common/scripts/generate-default-userdata.js b/src/web/app/common/scripts/generate-default-userdata.js deleted file mode 100644 index 1200563e1a..0000000000 --- a/src/web/app/common/scripts/generate-default-userdata.js +++ /dev/null @@ -1,45 +0,0 @@ -import uuid from './uuid'; - -const home = { - left: [ - 'profile', - 'calendar', - 'rss-reader', - 'photo-stream', - 'version' - ], - right: [ - 'broadcast', - 'notifications', - 'user-recommendation', - 'donation', - 'nav', - 'tips' - ] -}; - -export default () => { - const homeData = []; - - home.left.forEach(widget => { - homeData.push({ - name: widget, - id: uuid(), - place: 'left' - }); - }); - - home.right.forEach(widget => { - homeData.push({ - name: widget, - id: uuid(), - place: 'right' - }); - }); - - const data = { - home: JSON.stringify(homeData) - }; - - return data; -}; -- cgit v1.2.3-freya From b93a9cdd8c996d9603b382e92b4165f6d5100125 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 10 Nov 2017 01:11:46 +0900 Subject: Use import --- src/web/app/common/scripts/stream.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/web/app/common') diff --git a/src/web/app/common/scripts/stream.js b/src/web/app/common/scripts/stream.js index 981118b5de..a03b7bf200 100644 --- a/src/web/app/common/scripts/stream.js +++ b/src/web/app/common/scripts/stream.js @@ -1,6 +1,6 @@ 'use strict'; -const ReconnectingWebSocket = require('reconnecting-websocket'); +import * as ReconnectingWebsocket from 'reconnecting-websocket'; import * as riot from 'riot'; import CONFIG from './config'; @@ -29,7 +29,7 @@ class Connection { .join('&') : null; - this.socket = new ReconnectingWebSocket(`${host}/${endpoint}${query ? '?' + query : ''}`); + 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); -- cgit v1.2.3-freya From 98dca7b7ac16c4ea38f808bc20d4a71a3acb3355 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 13 Nov 2017 03:47:06 +0900 Subject: 同じ接続を使いまわすように MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 4 +++ src/web/app/common/mixins/index.js | 10 ++++-- src/web/app/common/mixins/stream.js | 5 --- .../app/common/scripts/server-stream-manager.ts | 39 ++++++++++++++++++++++ src/web/app/desktop/tags/home-widgets/server.tag | 9 ++--- src/web/app/init.js | 6 +++- 6 files changed, 60 insertions(+), 13 deletions(-) delete mode 100644 src/web/app/common/mixins/stream.js create mode 100644 src/web/app/common/scripts/server-stream-manager.ts (limited to 'src/web/app/common') diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b506efe30..31c16d2073 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ChangeLog (Release Notes) ========================= 主に notable な changes を書いていきます +unreleased +---------- +* 通信の最適化 + 3040 (2017/11/12) ----------------- * バグ修正 diff --git a/src/web/app/common/mixins/index.js b/src/web/app/common/mixins/index.js index 9718ee949b..19e0690d72 100644 --- a/src/web/app/common/mixins/index.js +++ b/src/web/app/common/mixins/index.js @@ -1,9 +1,13 @@ +import * as riot from 'riot'; + import activateMe from './i'; import activateApi from './api'; -import activateStream from './stream'; -export default (me, stream) => { +export default (me, stream, serverStreamManager) => { activateMe(me); activateApi(me); - activateStream(stream); + + riot.mixin('stream', { stream }); + + riot.mixin('server-stream', { serverStream: serverStreamManager }); }; diff --git a/src/web/app/common/mixins/stream.js b/src/web/app/common/mixins/stream.js deleted file mode 100644 index 4706042b04..0000000000 --- a/src/web/app/common/mixins/stream.js +++ /dev/null @@ -1,5 +0,0 @@ -import * as riot from 'riot'; - -export default stream => { - riot.mixin('stream', { stream }); -}; diff --git a/src/web/app/common/scripts/server-stream-manager.ts b/src/web/app/common/scripts/server-stream-manager.ts new file mode 100644 index 0000000000..e3f03ae40b --- /dev/null +++ b/src/web/app/common/scripts/server-stream-manager.ts @@ -0,0 +1,39 @@ +import Connection from './server-stream'; +import uuid from './uuid'; + +export default class ServerStreamManager { + private connection = null; + + /** + * コネクションを必要としているユーザー + */ + private users = []; + + public getConnection() { + if (this.connection == null) { + this.connection = new Connection(); + } + + return this.connection; + } + + public use() { + // ユーザーID生成 + const userId = uuid(); + + this.users.push(userId); + + return userId; + } + + public dispose(userId) { + this.users = this.users.filter(id => id != userId); + + // 誰もコネクションの利用者がいなくなったら + if (this.users.length == 0) { + // コネクションを切断する + this.connection.close(); + this.connection = null; + } + } +} diff --git a/src/web/app/desktop/tags/home-widgets/server.tag b/src/web/app/desktop/tags/home-widgets/server.tag index 094af87594..f499769b00 100644 --- a/src/web/app/desktop/tags/home-widgets/server.tag +++ b/src/web/app/desktop/tags/home-widgets/server.tag @@ -60,8 +60,6 @@ diff --git a/src/web/app/mobile/tags/index.js b/src/web/app/mobile/tags/index.js deleted file mode 100644 index 19952c20cd..0000000000 --- a/src/web/app/mobile/tags/index.js +++ /dev/null @@ -1,51 +0,0 @@ -require('./ui.tag'); -require('./page/entrance.tag'); -require('./page/entrance/signin.tag'); -require('./page/entrance/signup.tag'); -require('./page/home.tag'); -require('./page/drive.tag'); -require('./page/notifications.tag'); -require('./page/user.tag'); -require('./page/user-followers.tag'); -require('./page/user-following.tag'); -require('./page/post.tag'); -require('./page/new-post.tag'); -require('./page/search.tag'); -require('./page/settings.tag'); -require('./page/settings/profile.tag'); -require('./page/settings/signin.tag'); -require('./page/settings/api.tag'); -require('./page/settings/authorized-apps.tag'); -require('./page/settings/twitter.tag'); -require('./page/messaging.tag'); -require('./page/messaging-room.tag'); -require('./page/selectdrive.tag'); -require('./home.tag'); -require('./home-timeline.tag'); -require('./timeline.tag'); -require('./post-preview.tag'); -require('./sub-post-content.tag'); -require('./images-viewer.tag'); -require('./drive.tag'); -require('./drive-selector.tag'); -require('./drive-folder-selector.tag'); -require('./drive/file.tag'); -require('./drive/folder.tag'); -require('./drive/file-viewer.tag'); -require('./post-form.tag'); -require('./notification.tag'); -require('./notifications.tag'); -require('./notify.tag'); -require('./notification-preview.tag'); -require('./search.tag'); -require('./search-posts.tag'); -require('./post-detail.tag'); -require('./user.tag'); -require('./user-timeline.tag'); -require('./follow-button.tag'); -require('./user-preview.tag'); -require('./users-list.tag'); -require('./user-following.tag'); -require('./user-followers.tag'); -require('./init-following.tag'); -require('./user-card.tag'); diff --git a/src/web/app/mobile/tags/index.ts b/src/web/app/mobile/tags/index.ts new file mode 100644 index 0000000000..19952c20cd --- /dev/null +++ b/src/web/app/mobile/tags/index.ts @@ -0,0 +1,51 @@ +require('./ui.tag'); +require('./page/entrance.tag'); +require('./page/entrance/signin.tag'); +require('./page/entrance/signup.tag'); +require('./page/home.tag'); +require('./page/drive.tag'); +require('./page/notifications.tag'); +require('./page/user.tag'); +require('./page/user-followers.tag'); +require('./page/user-following.tag'); +require('./page/post.tag'); +require('./page/new-post.tag'); +require('./page/search.tag'); +require('./page/settings.tag'); +require('./page/settings/profile.tag'); +require('./page/settings/signin.tag'); +require('./page/settings/api.tag'); +require('./page/settings/authorized-apps.tag'); +require('./page/settings/twitter.tag'); +require('./page/messaging.tag'); +require('./page/messaging-room.tag'); +require('./page/selectdrive.tag'); +require('./home.tag'); +require('./home-timeline.tag'); +require('./timeline.tag'); +require('./post-preview.tag'); +require('./sub-post-content.tag'); +require('./images-viewer.tag'); +require('./drive.tag'); +require('./drive-selector.tag'); +require('./drive-folder-selector.tag'); +require('./drive/file.tag'); +require('./drive/folder.tag'); +require('./drive/file-viewer.tag'); +require('./post-form.tag'); +require('./notification.tag'); +require('./notifications.tag'); +require('./notify.tag'); +require('./notification-preview.tag'); +require('./search.tag'); +require('./search-posts.tag'); +require('./post-detail.tag'); +require('./user.tag'); +require('./user-timeline.tag'); +require('./follow-button.tag'); +require('./user-preview.tag'); +require('./users-list.tag'); +require('./user-following.tag'); +require('./user-followers.tag'); +require('./init-following.tag'); +require('./user-card.tag'); diff --git a/src/web/app/mobile/tags/post-detail.tag b/src/web/app/mobile/tags/post-detail.tag index 8a32101036..28071a5cac 100644 --- a/src/web/app/mobile/tags/post-detail.tag +++ b/src/web/app/mobile/tags/post-detail.tag @@ -285,7 +285,7 @@ this.refs.text.innerHTML = compile(tokens); - this.refs.text.children.forEach(e => { + Array.from(this.refs.text.children).forEach(e => { if (e.tagName == 'MK-URL') riot.mount(e); }); diff --git a/src/web/app/mobile/tags/post-form.tag b/src/web/app/mobile/tags/post-form.tag index d7d382c9e2..2912bfdfa2 100644 --- a/src/web/app/mobile/tags/post-form.tag +++ b/src/web/app/mobile/tags/post-form.tag @@ -207,7 +207,7 @@ }; this.onpaste = e => { - e.clipboardData.items.forEach(item => { + Array.from(e.clipboardData.items).forEach(item => { if (item.kind == 'file') { this.upload(item.getAsFile()); } @@ -228,7 +228,7 @@ }; this.changeFile = () => { - this.refs.file.files.forEach(this.upload); + Array.from(this.refs.file.files).forEach(this.upload); }; this.upload = file => { diff --git a/src/web/app/mobile/tags/sub-post-content.tag b/src/web/app/mobile/tags/sub-post-content.tag index e32e245185..c14233d3b7 100644 --- a/src/web/app/mobile/tags/sub-post-content.tag +++ b/src/web/app/mobile/tags/sub-post-content.tag @@ -37,7 +37,7 @@ const tokens = this.post.ast; this.refs.text.innerHTML = compile(tokens, false); - this.refs.text.children.forEach(e => { + Array.from(this.refs.text.children).forEach(e => { if (e.tagName == 'MK-URL') riot.mount(e); }); } diff --git a/src/web/app/mobile/tags/timeline.tag b/src/web/app/mobile/tags/timeline.tag index f9ec2cca60..52f6f27ea8 100644 --- a/src/web/app/mobile/tags/timeline.tag +++ b/src/web/app/mobile/tags/timeline.tag @@ -538,7 +538,7 @@ this.refs.text.innerHTML = this.refs.text.innerHTML.replace('

', compile(tokens)); - this.refs.text.children.forEach(e => { + Array.from(this.refs.text.children).forEach(e => { if (e.tagName == 'MK-URL') riot.mount(e); }); diff --git a/src/web/app/stats/script.js b/src/web/app/stats/script.js deleted file mode 100644 index 75063501bb..0000000000 --- a/src/web/app/stats/script.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Stats - */ - -// Style -import './style.styl'; - -import * as riot from 'riot'; -require('./tags'); -import init from '../init'; - -document.title = 'Misskey Statistics'; - -/** - * init - */ -init(me => { - mount(document.createElement('mk-index')); -}); - -function mount(content) { - riot.mount(document.getElementById('app').appendChild(content)); -} diff --git a/src/web/app/stats/script.ts b/src/web/app/stats/script.ts new file mode 100644 index 0000000000..75063501bb --- /dev/null +++ b/src/web/app/stats/script.ts @@ -0,0 +1,23 @@ +/** + * Stats + */ + +// Style +import './style.styl'; + +import * as riot from 'riot'; +require('./tags'); +import init from '../init'; + +document.title = 'Misskey Statistics'; + +/** + * init + */ +init(me => { + mount(document.createElement('mk-index')); +}); + +function mount(content) { + riot.mount(document.getElementById('app').appendChild(content)); +} diff --git a/src/web/app/stats/tags/index.js b/src/web/app/stats/tags/index.js deleted file mode 100644 index f41151949f..0000000000 --- a/src/web/app/stats/tags/index.js +++ /dev/null @@ -1 +0,0 @@ -require('./index.tag'); diff --git a/src/web/app/stats/tags/index.ts b/src/web/app/stats/tags/index.ts new file mode 100644 index 0000000000..f41151949f --- /dev/null +++ b/src/web/app/stats/tags/index.ts @@ -0,0 +1 @@ +require('./index.tag'); diff --git a/src/web/app/status/script.js b/src/web/app/status/script.js deleted file mode 100644 index 06d4d9a7a4..0000000000 --- a/src/web/app/status/script.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Status - */ - -// Style -import './style.styl'; - -import * as riot from 'riot'; -require('./tags'); -import init from '../init'; - -document.title = 'Misskey System Status'; - -/** - * init - */ -init(me => { - mount(document.createElement('mk-index')); -}); - -function mount(content) { - riot.mount(document.getElementById('app').appendChild(content)); -} diff --git a/src/web/app/status/script.ts b/src/web/app/status/script.ts new file mode 100644 index 0000000000..06d4d9a7a4 --- /dev/null +++ b/src/web/app/status/script.ts @@ -0,0 +1,23 @@ +/** + * Status + */ + +// Style +import './style.styl'; + +import * as riot from 'riot'; +require('./tags'); +import init from '../init'; + +document.title = 'Misskey System Status'; + +/** + * init + */ +init(me => { + mount(document.createElement('mk-index')); +}); + +function mount(content) { + riot.mount(document.getElementById('app').appendChild(content)); +} diff --git a/src/web/app/status/tags/index.js b/src/web/app/status/tags/index.js deleted file mode 100644 index f41151949f..0000000000 --- a/src/web/app/status/tags/index.js +++ /dev/null @@ -1 +0,0 @@ -require('./index.tag'); diff --git a/src/web/app/status/tags/index.ts b/src/web/app/status/tags/index.ts new file mode 100644 index 0000000000..f41151949f --- /dev/null +++ b/src/web/app/status/tags/index.ts @@ -0,0 +1 @@ +require('./index.tag'); diff --git a/tslint.json b/tslint.json index 1c44579512..d3f96000b9 100644 --- a/tslint.json +++ b/tslint.json @@ -13,6 +13,7 @@ "object-literal-sort-keys": false, "curly": false, "no-console": [false], + "no-empty":false, "ordered-imports": [false], "arrow-parens": false, "object-literal-shorthand": false, diff --git a/webpack/webpack.config.ts b/webpack/webpack.config.ts index 97782a4102..f2bcf48f31 100644 --- a/webpack/webpack.config.ts +++ b/webpack/webpack.config.ts @@ -14,13 +14,13 @@ module.exports = langs.map(([lang, locale]) => { // Entries const entry = { - desktop: './src/web/app/desktop/script.js', - mobile: './src/web/app/mobile/script.js', - ch: './src/web/app/ch/script.js', - stats: './src/web/app/stats/script.js', - status: './src/web/app/status/script.js', - dev: './src/web/app/dev/script.js', - auth: './src/web/app/auth/script.js' + desktop: './src/web/app/desktop/script.ts', + mobile: './src/web/app/mobile/script.ts', + ch: './src/web/app/ch/script.ts', + stats: './src/web/app/stats/script.ts', + status: './src/web/app/status/script.ts', + dev: './src/web/app/dev/script.ts', + auth: './src/web/app/auth/script.ts' }; const output = { @@ -33,6 +33,11 @@ module.exports = langs.map(([lang, locale]) => { entry, module: module_(lang, locale), plugins: plugins(version, lang), - output + output, + resolve: { + extensions: [ + '.js', '.ts' + ] + } }; }); -- cgit v1.2.3-freya From 0a994e5b9885265873e02b3b3ab9add7ec7e7e6b Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 13 Nov 2017 19:58:29 +0900 Subject: Add access log widget --- locales/en.yml | 3 + locales/ja.yml | 3 + src/api/stream/requests.ts | 19 +++++ src/api/streaming.ts | 6 ++ src/log-request.ts | 21 +++++ src/server.ts | 6 ++ src/web/app/common/mixins/index.ts | 2 + .../app/common/scripts/requests-stream-manager.ts | 12 +++ src/web/app/common/scripts/requests-stream.ts | 14 ++++ .../app/desktop/tags/home-widgets/access-log.tag | 93 ++++++++++++++++++++++ src/web/app/desktop/tags/home.tag | 1 + src/web/app/desktop/tags/index.ts | 1 + 12 files changed, 181 insertions(+) create mode 100644 src/api/stream/requests.ts create mode 100644 src/log-request.ts create mode 100644 src/web/app/common/scripts/requests-stream-manager.ts create mode 100644 src/web/app/common/scripts/requests-stream.ts create mode 100644 src/web/app/desktop/tags/home-widgets/access-log.tag (limited to 'src/web/app/common') diff --git a/locales/en.yml b/locales/en.yml index 574af26a68..d464b2fe2f 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -390,6 +390,9 @@ desktop: post: "Post" placeholder: "What's happening?" + mk-access-log-home-widget: + title: "Access log" + mk-repost-form: quote: "Quote..." cancel: "Cancel" diff --git a/locales/ja.yml b/locales/ja.yml index 9e6251d0d7..5c6f8e38e1 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -390,6 +390,9 @@ desktop: post: "投稿" placeholder: "いまどうしてる?" + mk-access-log-home-widget: + title: "アクセスログ" + mk-repost-form: quote: "引用する..." cancel: "キャンセル" diff --git a/src/api/stream/requests.ts b/src/api/stream/requests.ts new file mode 100644 index 0000000000..2c36e58b6e --- /dev/null +++ b/src/api/stream/requests.ts @@ -0,0 +1,19 @@ +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 onRequest = request => { + connection.send(JSON.stringify({ + type: 'request', + body: request + })); + }; + + ev.addListener('request', onRequest); + + connection.on('close', () => { + ev.removeListener('request', onRequest); + }); +} diff --git a/src/api/streaming.ts b/src/api/streaming.ts index 0e512fb210..6caf7db3e8 100644 --- a/src/api/streaming.ts +++ b/src/api/streaming.ts @@ -9,6 +9,7 @@ import isNativeToken from './common/is-native-token'; import homeStream from './stream/home'; import messagingStream from './stream/messaging'; import serverStream from './stream/server'; +import requestsStream from './stream/requests'; import channelStream from './stream/channel'; module.exports = (server: http.Server) => { @@ -27,6 +28,11 @@ module.exports = (server: http.Server) => { return; } + if (request.resourceURL.pathname === '/requests') { + requestsStream(request, connection); + return; + } + // Connect to Redis const subscriber = redis.createClient( config.redis.port, config.redis.host); diff --git a/src/log-request.ts b/src/log-request.ts new file mode 100644 index 0000000000..e431aa271d --- /dev/null +++ b/src/log-request.ts @@ -0,0 +1,21 @@ +import * as crypto from 'crypto'; +import * as express from 'express'; +import * as proxyAddr from 'proxy-addr'; +import Xev from 'xev'; + +const ev = new Xev(); + +export default function(req: express.Request) { + const ip = proxyAddr(req, () => true); + + const md5 = crypto.createHash('md5'); + md5.update(ip); + const hashedIp = md5.digest('hex').substr(0, 3); + + ev.emit('request', { + ip: hashedIp, + method: req.method, + hostname: req.hostname, + path: req.originalUrl + }); +} diff --git a/src/server.ts b/src/server.ts index 3e9bd44eef..9cf44eb0d0 100644 --- a/src/server.ts +++ b/src/server.ts @@ -11,6 +11,7 @@ import * as morgan from 'morgan'; import Accesses from 'accesses'; import vhost = require('vhost'); +import log from './log-request'; import config from './conf'; /** @@ -35,6 +36,11 @@ app.use(morgan(process.env.NODE_ENV == 'production' ? 'combined' : 'dev', { stream: config.accesslog ? fs.createWriteStream(config.accesslog) : null })); +app.use((req, res, next) => { + log(req); + next(); +}); + // Drop request when without 'Host' header app.use((req, res, next) => { if (!req.headers['host']) { diff --git a/src/web/app/common/mixins/index.ts b/src/web/app/common/mixins/index.ts index 45427fb9d3..a11bfa7b64 100644 --- a/src/web/app/common/mixins/index.ts +++ b/src/web/app/common/mixins/index.ts @@ -3,6 +3,7 @@ import * as riot from 'riot'; import activateMe from './i'; import activateApi from './api'; import ServerStreamManager from '../scripts/server-stream-manager'; +import RequestsStreamManager from '../scripts/requests-stream-manager'; export default (me, stream) => { activateMe(me); @@ -11,4 +12,5 @@ export default (me, stream) => { (riot as any).mixin('stream', { stream }); (riot as any).mixin('server-stream', { serverStream: new ServerStreamManager() }); + (riot as any).mixin('requests-stream', { requestsStream: new RequestsStreamManager() }); }; diff --git a/src/web/app/common/scripts/requests-stream-manager.ts b/src/web/app/common/scripts/requests-stream-manager.ts new file mode 100644 index 0000000000..44db913e78 --- /dev/null +++ b/src/web/app/common/scripts/requests-stream-manager.ts @@ -0,0 +1,12 @@ +import StreamManager from './stream-manager'; +import Connection from './requests-stream'; + +export default class RequestsStreamManager extends StreamManager { + public getConnection() { + if (this.connection == null) { + this.connection = new Connection(); + } + + return this.connection; + } +} diff --git a/src/web/app/common/scripts/requests-stream.ts b/src/web/app/common/scripts/requests-stream.ts new file mode 100644 index 0000000000..325224587a --- /dev/null +++ b/src/web/app/common/scripts/requests-stream.ts @@ -0,0 +1,14 @@ +'use strict'; + +import Stream from './stream'; + +/** + * Requests stream connection + */ +class Connection extends Stream { + constructor() { + super('requests'); + } +} + +export default Connection; diff --git a/src/web/app/desktop/tags/home-widgets/access-log.tag b/src/web/app/desktop/tags/home-widgets/access-log.tag new file mode 100644 index 0000000000..a148577563 --- /dev/null +++ b/src/web/app/desktop/tags/home-widgets/access-log.tag @@ -0,0 +1,93 @@ + + +

%i18n:desktop.tags.mk-access-log-home-widget.title%

+
+
+

+ { ip } + { method } + { path } +

+
+ + +
diff --git a/src/web/app/desktop/tags/home.tag b/src/web/app/desktop/tags/home.tag index fd286851d9..88d06d2baa 100644 --- a/src/web/app/desktop/tags/home.tag +++ b/src/web/app/desktop/tags/home.tag @@ -20,6 +20,7 @@ + diff --git a/src/web/app/desktop/tags/index.ts b/src/web/app/desktop/tags/index.ts index 15677471c3..8b5a52d670 100644 --- a/src/web/app/desktop/tags/index.ts +++ b/src/web/app/desktop/tags/index.ts @@ -43,6 +43,7 @@ require('./home-widgets/slideshow.tag'); require('./home-widgets/channel.tag'); require('./home-widgets/timemachine.tag'); require('./home-widgets/post-form.tag'); +require('./home-widgets/access-log.tag'); require('./timeline.tag'); require('./messaging/window.tag'); require('./messaging/room-window.tag'); -- cgit v1.2.3-freya From ab2293aa4c0832f9e57d64aa22d2fce319fbfcb1 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 14 Nov 2017 00:54:16 +0900 Subject: Add messaging widget --- locales/en.yml | 3 + locales/ja.yml | 3 + src/api/common/read-messaging-message.ts | 2 + src/api/endpoints/messaging/messages/create.ts | 3 + src/api/event.ts | 6 ++ src/api/stream/messaging-index.ts | 10 +++ src/api/streaming.ts | 2 + src/web/app/common/mixins/index.ts | 2 + .../scripts/messaging-index-stream-manager.ts | 20 ++++++ .../app/common/scripts/messaging-index-stream.ts | 14 ++++ src/web/app/common/tags/messaging/index.tag | 76 ++++++++++++++++++++-- .../app/desktop/tags/home-widgets/messaging.tag | 50 ++++++++++++++ src/web/app/desktop/tags/home.tag | 1 + src/web/app/desktop/tags/index.ts | 1 + 14 files changed, 186 insertions(+), 7 deletions(-) create mode 100644 src/api/stream/messaging-index.ts create mode 100644 src/web/app/common/scripts/messaging-index-stream-manager.ts create mode 100644 src/web/app/common/scripts/messaging-index-stream.ts create mode 100644 src/web/app/desktop/tags/home-widgets/messaging.tag (limited to 'src/web/app/common') diff --git a/locales/en.yml b/locales/en.yml index d464b2fe2f..d6fcd1e6d4 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -393,6 +393,9 @@ desktop: mk-access-log-home-widget: title: "Access log" + mk-messaging-home-widget: + title: "Messaging" + mk-repost-form: quote: "Quote..." cancel: "Cancel" diff --git a/locales/ja.yml b/locales/ja.yml index 5c6f8e38e1..478afac132 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -393,6 +393,9 @@ desktop: mk-access-log-home-widget: title: "アクセスログ" + mk-messaging-home-widget: + title: "メッセージ" + mk-repost-form: quote: "引用する..." cancel: "キャンセル" diff --git a/src/api/common/read-messaging-message.ts b/src/api/common/read-messaging-message.ts index 3257ec8b07..8e5e5b2b68 100644 --- a/src/api/common/read-messaging-message.ts +++ b/src/api/common/read-messaging-message.ts @@ -3,6 +3,7 @@ import Message from '../models/messaging-message'; import { IMessagingMessage as IMessage } from '../models/messaging-message'; import publishUserStream from '../event'; import { publishMessagingStream } from '../event'; +import { publishMessagingIndexStream } from '../event'; /** * Mark as read message(s) @@ -49,6 +50,7 @@ export default ( // Publish event publishMessagingStream(otherpartyId, userId, 'read', ids.map(id => id.toString())); + publishMessagingIndexStream(userId, 'read', ids.map(id => id.toString())); // Calc count of my unread messages const count = await Message diff --git a/src/api/endpoints/messaging/messages/create.ts b/src/api/endpoints/messaging/messages/create.ts index 149852c093..29a4671f84 100644 --- a/src/api/endpoints/messaging/messages/create.ts +++ b/src/api/endpoints/messaging/messages/create.ts @@ -10,6 +10,7 @@ import DriveFile from '../../../models/drive-file'; import serialize from '../../../serializers/messaging-message'; import publishUserStream from '../../../event'; import { publishMessagingStream } from '../../../event'; +import { publishMessagingIndexStream } from '../../../event'; import config from '../../../../conf'; /** @@ -85,10 +86,12 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // 自分のストリーム publishMessagingStream(message.user_id, message.recipient_id, 'message', messageObj); + publishMessagingIndexStream(message.user_id, 'message', messageObj); publishUserStream(message.user_id, 'messaging_message', messageObj); // 相手のストリーム publishMessagingStream(message.recipient_id, message.user_id, 'message', messageObj); + publishMessagingIndexStream(message.recipient_id, 'message', messageObj); publishUserStream(message.recipient_id, 'messaging_message', messageObj); // 3秒経っても(今回作成した)メッセージが既読にならなかったら「未読のメッセージがありますよ」イベントを発行する diff --git a/src/api/event.ts b/src/api/event.ts index 909b0d2556..927883737e 100644 --- a/src/api/event.ts +++ b/src/api/event.ts @@ -25,6 +25,10 @@ class MisskeyEvent { this.publish(`messaging-stream:${userId}-${otherpartyId}`, type, typeof value === 'undefined' ? null : value); } + public publishMessagingIndexStream(userId: ID, type: string, value?: any): void { + this.publish(`messaging-index-stream:${userId}`, type, typeof value === 'undefined' ? null : value); + } + public publishChannelStream(channelId: ID, type: string, value?: any): void { this.publish(`channel-stream:${channelId}`, type, typeof value === 'undefined' ? null : value); } @@ -46,4 +50,6 @@ export const publishPostStream = ev.publishPostStream.bind(ev); export const publishMessagingStream = ev.publishMessagingStream.bind(ev); +export const publishMessagingIndexStream = ev.publishMessagingIndexStream.bind(ev); + export const publishChannelStream = ev.publishChannelStream.bind(ev); diff --git a/src/api/stream/messaging-index.ts b/src/api/stream/messaging-index.ts new file mode 100644 index 0000000000..c1b2fbc806 --- /dev/null +++ b/src/api/stream/messaging-index.ts @@ -0,0 +1,10 @@ +import * as websocket from 'websocket'; +import * as redis from 'redis'; + +export default function(request: websocket.request, connection: websocket.connection, subscriber: redis.RedisClient, user: any): void { + // Subscribe messaging index stream + subscriber.subscribe(`misskey:messaging-index-stream:${user._id}`); + subscriber.on('message', (_, data) => { + connection.send(data); + }); +} diff --git a/src/api/streaming.ts b/src/api/streaming.ts index 6caf7db3e8..1f0ba848c1 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 messagingIndexStream from './stream/messaging-index'; import serverStream from './stream/server'; import requestsStream from './stream/requests'; import channelStream from './stream/channel'; @@ -58,6 +59,7 @@ module.exports = (server: http.Server) => { const channel = request.resourceURL.pathname === '/' ? homeStream : request.resourceURL.pathname === '/messaging' ? messagingStream : + request.resourceURL.pathname === '/messaging-index' ? messagingIndexStream : null; if (channel !== null) { diff --git a/src/web/app/common/mixins/index.ts b/src/web/app/common/mixins/index.ts index a11bfa7b64..c0c1c0555f 100644 --- a/src/web/app/common/mixins/index.ts +++ b/src/web/app/common/mixins/index.ts @@ -4,6 +4,7 @@ import activateMe from './i'; import activateApi from './api'; import ServerStreamManager from '../scripts/server-stream-manager'; import RequestsStreamManager from '../scripts/requests-stream-manager'; +import MessagingIndexStream from '../scripts/messaging-index-stream-manager'; export default (me, stream) => { activateMe(me); @@ -13,4 +14,5 @@ export default (me, stream) => { (riot as any).mixin('server-stream', { serverStream: new ServerStreamManager() }); (riot as any).mixin('requests-stream', { requestsStream: new RequestsStreamManager() }); + (riot as any).mixin('messaging-index-stream', { messagingIndexStream: new MessagingIndexStream(me) }); }; diff --git a/src/web/app/common/scripts/messaging-index-stream-manager.ts b/src/web/app/common/scripts/messaging-index-stream-manager.ts new file mode 100644 index 0000000000..dc386204ca --- /dev/null +++ b/src/web/app/common/scripts/messaging-index-stream-manager.ts @@ -0,0 +1,20 @@ +import StreamManager from './stream-manager'; +import Connection from './messaging-index-stream'; + +export default class ServerStreamManager extends StreamManager { + private me; + + constructor(me) { + super(); + + this.me = me; + } + + public getConnection() { + if (this.connection == null) { + this.connection = new Connection(this.me); + } + + return this.connection; + } +} diff --git a/src/web/app/common/scripts/messaging-index-stream.ts b/src/web/app/common/scripts/messaging-index-stream.ts new file mode 100644 index 0000000000..c194e663c2 --- /dev/null +++ b/src/web/app/common/scripts/messaging-index-stream.ts @@ -0,0 +1,14 @@ +import Stream from './stream'; + +/** + * Messaging index stream connection + */ +class Connection extends Stream { + constructor(me) { + super('messaging-index', { + i: me.token + }); + } +} + +export default Connection; diff --git a/src/web/app/common/tags/messaging/index.tag b/src/web/app/common/tags/messaging/index.tag index 731c9da2c7..4c1bf0c6e4 100644 --- a/src/web/app/common/tags/messaging/index.tag +++ b/src/web/app/common/tags/messaging/index.tag @@ -1,5 +1,5 @@ - - diff --git a/src/web/app/desktop/tags/home-widgets/broadcast.tag b/src/web/app/desktop/tags/home-widgets/broadcast.tag index 7caf4dcddd..00fef83742 100644 --- a/src/web/app/desktop/tags/home-widgets/broadcast.tag +++ b/src/web/app/desktop/tags/home-widgets/broadcast.tag @@ -1,4 +1,4 @@ - +
@@ -8,22 +8,35 @@
-

開発者募集中!

-

Misskeyはオープンソースで開発されています。リポジトリはこちら。

+

%i18n:desktop.tags.mk-broadcast-home-widget.fetching%

+

{ + broadcasts.length == 0 ? '%i18n:desktop.tags.mk-broadcast-home-widget.no-broadcasts%' : broadcasts[i].title + }

+

%i18n:desktop.tags.mk-broadcast-home-widget.have-a-nice-day%

+ 1 } onclick={ next }>%i18n:desktop.tags.mk-broadcast-home-widget.next% >>
-- cgit v1.2.3-freya From a8c6d0ed9023f7e0699cfe5c519532231e49cc3b Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 16 Nov 2017 23:46:36 +0900 Subject: #465 --- src/api/common/add-file-to-drive.ts | 3 ++- src/api/endpoints/drive/files/update.ts | 6 +++--- src/api/endpoints/drive/folders/create.ts | 6 +++--- src/api/endpoints/drive/folders/update.ts | 6 +++--- src/api/event.ts | 6 ++++++ src/api/stream/drive.ts | 10 ++++++++++ src/api/streaming.ts | 2 ++ src/web/app/common/mixins.ts | 3 ++- src/web/app/common/scripts/drive-stream-manager.ts | 20 ++++++++++++++++++++ src/web/app/common/scripts/drive-stream.ts | 14 ++++++++++++++ src/web/app/desktop/tags/drive/browser.tag | 22 +++++++++++++--------- src/web/app/mobile/tags/drive.tag | 22 +++++++++++++--------- 12 files changed, 91 insertions(+), 29 deletions(-) create mode 100644 src/api/stream/drive.ts create mode 100644 src/web/app/common/scripts/drive-stream-manager.ts create mode 100644 src/web/app/common/scripts/drive-stream.ts (limited to 'src/web/app/common') diff --git a/src/api/common/add-file-to-drive.ts b/src/api/common/add-file-to-drive.ts index f96f58cb66..2a649788af 100644 --- a/src/api/common/add-file-to-drive.ts +++ b/src/api/common/add-file-to-drive.ts @@ -13,7 +13,7 @@ import prominence = require('prominence'); import DriveFile, { getGridFSBucket } from '../models/drive-file'; import DriveFolder from '../models/drive-folder'; import serialize from '../serializers/drive-file'; -import event from '../event'; +import event, { publishDriveStream } from '../event'; import config from '../../conf'; const log = debug('misskey:register-drive-file'); @@ -243,6 +243,7 @@ export default (user: any, file: string | stream.Readable, ...args) => new Promi serialize(file).then(serializedFile => { // Publish drive_file_created event event(user._id, 'drive_file_created', serializedFile); + publishDriveStream(user._id, 'file_created', serializedFile); // Register to search database if (config.elasticsearch.enable) { diff --git a/src/api/endpoints/drive/files/update.ts b/src/api/endpoints/drive/files/update.ts index f265142c4d..f39a420d6e 100644 --- a/src/api/endpoints/drive/files/update.ts +++ b/src/api/endpoints/drive/files/update.ts @@ -6,7 +6,7 @@ import DriveFolder from '../../../models/drive-folder'; import DriveFile from '../../../models/drive-file'; import { validateFileName } from '../../../models/drive-file'; import serialize from '../../../serializers/drive-file'; -import event from '../../../event'; +import { publishDriveStream } from '../../../event'; /** * Update a file @@ -72,6 +72,6 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Response res(fileObj); - // Publish drive_file_updated event - event(user._id, 'drive_file_updated', fileObj); + // Publish file_updated event + publishDriveStream(user._id, 'file_updated', fileObj); }); diff --git a/src/api/endpoints/drive/folders/create.ts b/src/api/endpoints/drive/folders/create.ts index 8c875db164..be847b2153 100644 --- a/src/api/endpoints/drive/folders/create.ts +++ b/src/api/endpoints/drive/folders/create.ts @@ -5,7 +5,7 @@ import $ from 'cafy'; import DriveFolder from '../../../models/drive-folder'; import { isValidFolderName } from '../../../models/drive-folder'; import serialize from '../../../serializers/drive-folder'; -import event from '../../../event'; +import { publishDriveStream } from '../../../event'; /** * Create drive folder @@ -52,6 +52,6 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Response res(folderObj); - // Publish drive_folder_created event - event(user._id, 'drive_folder_created', folderObj); + // Publish folder_created event + publishDriveStream(user._id, 'folder_created', folderObj); }); diff --git a/src/api/endpoints/drive/folders/update.ts b/src/api/endpoints/drive/folders/update.ts index 4f2e3d2a7a..ff673402ab 100644 --- a/src/api/endpoints/drive/folders/update.ts +++ b/src/api/endpoints/drive/folders/update.ts @@ -5,7 +5,7 @@ import $ from 'cafy'; import DriveFolder from '../../../models/drive-folder'; import { isValidFolderName } from '../../../models/drive-folder'; import serialize from '../../../serializers/drive-folder'; -import event from '../../../event'; +import { publishDriveStream } from '../../../event'; /** * Update a folder @@ -96,6 +96,6 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Response res(folderObj); - // Publish drive_folder_updated event - event(user._id, 'drive_folder_updated', folderObj); + // Publish folder_updated event + publishDriveStream(user._id, 'folder_updated', folderObj); }); diff --git a/src/api/event.ts b/src/api/event.ts index 927883737e..8605a0f1e4 100644 --- a/src/api/event.ts +++ b/src/api/event.ts @@ -17,6 +17,10 @@ class MisskeyEvent { this.publish(`user-stream:${userId}`, type, typeof value === 'undefined' ? null : value); } + public publishDriveStream(userId: ID, type: string, value?: any): void { + this.publish(`drive-stream:${userId}`, type, typeof value === 'undefined' ? null : value); + } + public publishPostStream(postId: ID, type: string, value?: any): void { this.publish(`post-stream:${postId}`, type, typeof value === 'undefined' ? null : value); } @@ -46,6 +50,8 @@ const ev = new MisskeyEvent(); export default ev.publishUserStream.bind(ev); +export const publishDriveStream = ev.publishDriveStream.bind(ev); + export const publishPostStream = ev.publishPostStream.bind(ev); export const publishMessagingStream = ev.publishMessagingStream.bind(ev); diff --git a/src/api/stream/drive.ts b/src/api/stream/drive.ts new file mode 100644 index 0000000000..c97ab80dcc --- /dev/null +++ b/src/api/stream/drive.ts @@ -0,0 +1,10 @@ +import * as websocket from 'websocket'; +import * as redis from 'redis'; + +export default function(request: websocket.request, connection: websocket.connection, subscriber: redis.RedisClient, user: any): void { + // Subscribe drive stream + subscriber.subscribe(`misskey:drive-stream:${user._id}`); + subscriber.on('message', (_, data) => { + connection.send(data); + }); +} diff --git a/src/api/streaming.ts b/src/api/streaming.ts index 1f0ba848c1..c06d64c245 100644 --- a/src/api/streaming.ts +++ b/src/api/streaming.ts @@ -7,6 +7,7 @@ import AccessToken from './models/access-token'; import isNativeToken from './common/is-native-token'; import homeStream from './stream/home'; +import driveStream from './stream/drive'; import messagingStream from './stream/messaging'; import messagingIndexStream from './stream/messaging-index'; import serverStream from './stream/server'; @@ -58,6 +59,7 @@ module.exports = (server: http.Server) => { const channel = request.resourceURL.pathname === '/' ? homeStream : + request.resourceURL.pathname === '/drive' ? driveStream : request.resourceURL.pathname === '/messaging' ? messagingStream : request.resourceURL.pathname === '/messaging-index' ? messagingIndexStream : null; diff --git a/src/web/app/common/mixins.ts b/src/web/app/common/mixins.ts index b5eb1acc78..5949069624 100644 --- a/src/web/app/common/mixins.ts +++ b/src/web/app/common/mixins.ts @@ -4,6 +4,7 @@ import MiOS from './mios'; import ServerStreamManager from './scripts/server-stream-manager'; import RequestsStreamManager from './scripts/requests-stream-manager'; import MessagingIndexStream from './scripts/messaging-index-stream-manager'; +import DriveStreamManager from './scripts/drive-stream-manager'; export default (mios: MiOS) => { (riot as any).mixin('os', { @@ -30,7 +31,7 @@ export default (mios: MiOS) => { (riot as any).mixin('api', { api: mios.api }); - + (riot as any).mixin('drive-stream', { driveStream: new DriveStreamManager(mios.i) }); (riot as any).mixin('stream', { stream: mios.stream }); (riot as any).mixin('server-stream', { serverStream: new ServerStreamManager() }); diff --git a/src/web/app/common/scripts/drive-stream-manager.ts b/src/web/app/common/scripts/drive-stream-manager.ts new file mode 100644 index 0000000000..8acdd7cbba --- /dev/null +++ b/src/web/app/common/scripts/drive-stream-manager.ts @@ -0,0 +1,20 @@ +import StreamManager from './stream-manager'; +import Connection from './drive-stream'; + +export default class DriveStreamManager extends StreamManager { + private me; + + constructor(me) { + super(); + + this.me = me; + } + + public getConnection() { + if (this.connection == null) { + this.connection = new Connection(this.me); + } + + return this.connection; + } +} diff --git a/src/web/app/common/scripts/drive-stream.ts b/src/web/app/common/scripts/drive-stream.ts new file mode 100644 index 0000000000..1b33435578 --- /dev/null +++ b/src/web/app/common/scripts/drive-stream.ts @@ -0,0 +1,14 @@ +import Stream from './stream'; + +/** + * Drive stream connection + */ +class Connection extends Stream { + constructor(me) { + super('drive', { + i: me.token + }); + } +} + +export default Connection; diff --git a/src/web/app/desktop/tags/drive/browser.tag b/src/web/app/desktop/tags/drive/browser.tag index 18e27f24bc..311209fcb6 100644 --- a/src/web/app/desktop/tags/drive/browser.tag +++ b/src/web/app/desktop/tags/drive/browser.tag @@ -247,7 +247,10 @@ this.mixin('i'); this.mixin('api'); - this.mixin('stream'); + + this.mixin('drive-stream'); + this.connection = this.driveStream.getConnection(); + this.connectionId = this.driveStream.use(); this.files = []; this.folders = []; @@ -280,10 +283,10 @@ }); }); - this.stream.on('drive_file_created', this.onStreamDriveFileCreated); - this.stream.on('drive_file_updated', this.onStreamDriveFileUpdated); - this.stream.on('drive_folder_created', this.onStreamDriveFolderCreated); - this.stream.on('drive_folder_updated', this.onStreamDriveFolderUpdated); + this.connection.on('file_created', this.onStreamDriveFileCreated); + this.connection.on('file_updated', this.onStreamDriveFileUpdated); + this.connection.on('folder_created', this.onStreamDriveFolderCreated); + this.connection.on('folder_updated', this.onStreamDriveFolderUpdated); if (this.opts.folder) { this.move(this.opts.folder); @@ -293,10 +296,11 @@ }); this.on('unmount', () => { - this.stream.off('drive_file_created', this.onStreamDriveFileCreated); - this.stream.off('drive_file_updated', this.onStreamDriveFileUpdated); - this.stream.off('drive_folder_created', this.onStreamDriveFolderCreated); - this.stream.off('drive_folder_updated', this.onStreamDriveFolderUpdated); + this.connection.off('file_created', this.onStreamDriveFileCreated); + this.connection.off('file_updated', this.onStreamDriveFileUpdated); + this.connection.off('folder_created', this.onStreamDriveFolderCreated); + this.connection.off('folder_updated', this.onStreamDriveFolderUpdated); + this.driveStream.dispose(this.connectionId); }); this.onStreamDriveFileCreated = file => { diff --git a/src/web/app/mobile/tags/drive.tag b/src/web/app/mobile/tags/drive.tag index 870a451acb..2c36c43ac5 100644 --- a/src/web/app/mobile/tags/drive.tag +++ b/src/web/app/mobile/tags/drive.tag @@ -172,7 +172,10 @@ diff --git a/src/web/app/desktop/script.ts b/src/web/app/desktop/script.ts index b4a8d829d6..bc0fc8dfe3 100644 --- a/src/web/app/desktop/script.ts +++ b/src/web/app/desktop/script.ts @@ -13,6 +13,7 @@ import route from './router'; import fuckAdBlock from './scripts/fuck-ad-block'; import getPostSummary from '../../../common/get-post-summary'; import MiOS from '../common/mios'; +import HomeStreamManager from '../common/scripts/streaming/home-stream-manager'; /** * init @@ -41,52 +42,62 @@ init(async (mios: MiOS) => { route(mios); }); -function registerNotifications(stream) { +function registerNotifications(stream: HomeStreamManager) { if (stream == null) return; - stream.on('drive_file_created', file => { - const n = new Notification('ファイルがアップロードされました', { - body: file.name, - icon: file.url + '?thumbnail&size=64' - }); - setTimeout(n.close.bind(n), 5000); + if (stream.hasConnection) { + attach(stream.borrow()); + } + + stream.on('connected', connection => { + attach(connection); }); - stream.on('mention', post => { - const n = new Notification(`${post.user.name}さんから:`, { - body: getPostSummary(post), - icon: post.user.avatar_url + '?thumbnail&size=64' + function attach(connection) { + connection.on('drive_file_created', file => { + const n = new Notification('ファイルがアップロードされました', { + body: file.name, + icon: file.url + '?thumbnail&size=64' + }); + setTimeout(n.close.bind(n), 5000); }); - setTimeout(n.close.bind(n), 6000); - }); - stream.on('reply', post => { - const n = new Notification(`${post.user.name}さんから返信:`, { - body: getPostSummary(post), - icon: post.user.avatar_url + '?thumbnail&size=64' + connection.on('mention', post => { + const n = new Notification(`${post.user.name}さんから:`, { + body: getPostSummary(post), + icon: post.user.avatar_url + '?thumbnail&size=64' + }); + setTimeout(n.close.bind(n), 6000); }); - setTimeout(n.close.bind(n), 6000); - }); - stream.on('quote', post => { - const n = new Notification(`${post.user.name}さんが引用:`, { - body: getPostSummary(post), - icon: post.user.avatar_url + '?thumbnail&size=64' + connection.on('reply', post => { + const n = new Notification(`${post.user.name}さんから返信:`, { + body: getPostSummary(post), + icon: post.user.avatar_url + '?thumbnail&size=64' + }); + setTimeout(n.close.bind(n), 6000); }); - setTimeout(n.close.bind(n), 6000); - }); - stream.on('unread_messaging_message', message => { - const n = new Notification(`${message.user.name}さんからメッセージ:`, { - body: message.text, // TODO: getMessagingMessageSummary(message), - icon: message.user.avatar_url + '?thumbnail&size=64' + connection.on('quote', post => { + const n = new Notification(`${post.user.name}さんが引用:`, { + body: getPostSummary(post), + icon: post.user.avatar_url + '?thumbnail&size=64' + }); + setTimeout(n.close.bind(n), 6000); }); - n.onclick = () => { - n.close(); - (riot as any).mount(document.body.appendChild(document.createElement('mk-messaging-room-window')), { - user: message.user + + connection.on('unread_messaging_message', message => { + const n = new Notification(`${message.user.name}さんからメッセージ:`, { + body: message.text, // TODO: getMessagingMessageSummary(message), + icon: message.user.avatar_url + '?thumbnail&size=64' }); - }; - setTimeout(n.close.bind(n), 7000); - }); + n.onclick = () => { + n.close(); + (riot as any).mount(document.body.appendChild(document.createElement('mk-messaging-room-window')), { + user: message.user + }); + }; + setTimeout(n.close.bind(n), 7000); + }); + } } diff --git a/src/web/app/desktop/tags/big-follow-button.tag b/src/web/app/desktop/tags/big-follow-button.tag index 86df2d4924..8897748ae1 100644 --- a/src/web/app/desktop/tags/big-follow-button.tag +++ b/src/web/app/desktop/tags/big-follow-button.tag @@ -74,7 +74,10 @@ this.mixin('i'); this.mixin('api'); + this.mixin('stream'); + this.connection = this.stream.getConnection(); + this.connectionId = this.stream.use(); this.user = null; this.userPromise = isPromise(this.opts.user) @@ -89,14 +92,15 @@ init: false, user: user }); - this.stream.on('follow', this.onStreamFollow); - this.stream.on('unfollow', this.onStreamUnfollow); + this.connection.on('follow', this.onStreamFollow); + this.connection.on('unfollow', this.onStreamUnfollow); }); }); this.on('unmount', () => { - this.stream.off('follow', this.onStreamFollow); - this.stream.off('unfollow', this.onStreamUnfollow); + this.connection.off('follow', this.onStreamFollow); + this.connection.off('unfollow', this.onStreamUnfollow); + this.stream.dispose(this.connectionId); }); this.onStreamFollow = user => { diff --git a/src/web/app/desktop/tags/follow-button.tag b/src/web/app/desktop/tags/follow-button.tag index 00ff686f69..a1cbc191d8 100644 --- a/src/web/app/desktop/tags/follow-button.tag +++ b/src/web/app/desktop/tags/follow-button.tag @@ -71,7 +71,10 @@ this.mixin('i'); this.mixin('api'); + this.mixin('stream'); + this.connection = this.stream.getConnection(); + this.connectionId = this.stream.use(); this.user = null; this.userPromise = isPromise(this.opts.user) @@ -86,14 +89,15 @@ init: false, user: user }); - this.stream.on('follow', this.onStreamFollow); - this.stream.on('unfollow', this.onStreamUnfollow); + this.connection.on('follow', this.onStreamFollow); + this.connection.on('unfollow', this.onStreamUnfollow); }); }); this.on('unmount', () => { - this.stream.off('follow', this.onStreamFollow); - this.stream.off('unfollow', this.onStreamUnfollow); + this.connection.off('follow', this.onStreamFollow); + this.connection.off('unfollow', this.onStreamUnfollow); + this.stream.dispose(this.connectionId); }); this.onStreamFollow = user => { diff --git a/src/web/app/desktop/tags/home-widgets/channel.tag b/src/web/app/desktop/tags/home-widgets/channel.tag index 28c66df5c0..fc4a27e4f4 100644 --- a/src/web/app/desktop/tags/home-widgets/channel.tag +++ b/src/web/app/desktop/tags/home-widgets/channel.tag @@ -138,7 +138,7 @@ + + + + + + + + + +

直近1年間分の統計です。一番右が現在で、一番左が1年前です。青は通常の投稿、赤は返信、緑はRepostをそれぞれ表しています。

+

+ だいたい*1日に{ averageOfAllTypePostsEachDays }回投稿(返信、Repost含む)しています。
+ だいたい*1日に{ averageOfPostsEachDays }回投稿(通常の)しています。
+ だいたい*1日に{ averageOfRepliesEachDays }回返信しています。
+ だいたい*1日に{ averageOfRepostsEachDays }回Repostしています。
+

+

* 中央値

+ + + +
-- cgit v1.2.3-freya From 1436617aab030fa5b3760a3eeae37a1cdeeba2df Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 21 Nov 2017 03:40:09 +0900 Subject: wip --- package.json | 1 + src/api/common/push-sw.ts | 44 +++++++++++++++++++++++++++++++ src/api/endpoints.ts | 5 ++++ src/api/endpoints/posts/create.ts | 7 ++--- src/api/endpoints/sw/register.ts | 50 ++++++++++++++++++++++++++++++++++++ src/api/event.ts | 7 +++++ src/api/models/sw-subscription.ts | 3 +++ src/config.ts | 10 +++++++- src/web/app/boot.js | 4 ++- src/web/app/common/mios.ts | 49 +++++++++++++++++++++++++++++++++++ src/web/app/common/scripts/config.ts | 10 +++++--- src/web/assets/sw.js | 31 ++++++++++++++++++++++ src/web/server.ts | 27 +++++++++++++++---- 13 files changed, 234 insertions(+), 14 deletions(-) create mode 100644 src/api/common/push-sw.ts create mode 100644 src/api/endpoints/sw/register.ts create mode 100644 src/api/models/sw-subscription.ts create mode 100644 src/web/assets/sw.js (limited to 'src/web/app/common') diff --git a/package.json b/package.json index 9d14e8b415..c41c561ef1 100644 --- a/package.json +++ b/package.json @@ -159,6 +159,7 @@ "typescript": "2.6.1", "uuid": "3.1.0", "vhost": "3.0.2", + "web-push": "^3.2.4", "websocket": "1.0.25", "xev": "2.0.0" } diff --git a/src/api/common/push-sw.ts b/src/api/common/push-sw.ts new file mode 100644 index 0000000000..927dc50635 --- /dev/null +++ b/src/api/common/push-sw.ts @@ -0,0 +1,44 @@ +const push = require('web-push'); +import * as mongo from 'mongodb'; +import Subscription from '../models/sw-subscription'; +import config from '../../conf'; + +push.setGCMAPIKey(config.sw.gcm_api_key); + +export default async function(userId: mongo.ObjectID | string, type, body?) { + if (typeof userId === 'string') { + userId = new mongo.ObjectID(userId); + } + + // Fetch + const subscriptions = await Subscription.find({ + user_id: userId + }); + + subscriptions.forEach(subscription => { + const pushSubscription = { + endpoint: subscription.endpoint, + keys: { + auth: subscription.auth, + p256dh: subscription.publickey + } + }; + + push.sendNotification(pushSubscription, JSON.stringify({ + type, body + })).catch(err => { + //console.log(err.statusCode); + //console.log(err.headers); + //console.log(err.body); + + if (err.statusCode == 410) { + Subscription.remove({ + user_id: userId, + endpoint: subscription.endpoint, + auth: subscription.auth, + publickey: subscription.publickey + }); + } + }); + }); +} diff --git a/src/api/endpoints.ts b/src/api/endpoints.ts index 2783c92027..06fb9a64ae 100644 --- a/src/api/endpoints.ts +++ b/src/api/endpoints.ts @@ -146,6 +146,11 @@ const endpoints: Endpoint[] = [ name: 'aggregation/posts/reactions' }, + { + name: 'sw/register', + withCredential: true + }, + { name: 'i', withCredential: true diff --git a/src/api/endpoints/posts/create.ts b/src/api/endpoints/posts/create.ts index 4f4b7e2e83..ae4959dae4 100644 --- a/src/api/endpoints/posts/create.ts +++ b/src/api/endpoints/posts/create.ts @@ -14,7 +14,7 @@ import ChannelWatching from '../../models/channel-watching'; import serialize from '../../serializers/post'; import notify from '../../common/notify'; import watch from '../../common/watch-post'; -import { default as event, publishChannelStream } from '../../event'; +import event, { pushSw, publishChannelStream } from '../../event'; import config from '../../../conf'; /** @@ -234,7 +234,7 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { const mentions = []; - function addMention(mentionee, type) { + function addMention(mentionee, reason) { // Reject if already added if (mentions.some(x => x.equals(mentionee))) return; @@ -243,7 +243,8 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { // Publish event if (!user._id.equals(mentionee)) { - event(mentionee, type, postObj); + event(mentionee, reason, postObj); + pushSw(mentionee, reason, postObj); } } diff --git a/src/api/endpoints/sw/register.ts b/src/api/endpoints/sw/register.ts new file mode 100644 index 0000000000..99406138db --- /dev/null +++ b/src/api/endpoints/sw/register.ts @@ -0,0 +1,50 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import Subscription from '../../models/sw-subscription'; + +/** + * subscribe service worker + * + * @param {any} params + * @param {any} user + * @param {any} _ + * @param {boolean} isSecure + * @return {Promise} + */ +module.exports = async (params, user, _, isSecure) => new Promise(async (res, rej) => { + // Get 'endpoint' parameter + const [endpoint, endpointErr] = $(params.endpoint).string().$; + if (endpointErr) return rej('invalid endpoint param'); + + // Get 'auth' parameter + const [auth, authErr] = $(params.auth).string().$; + if (authErr) return rej('invalid auth param'); + + // Get 'publickey' parameter + const [publickey, publickeyErr] = $(params.publickey).string().$; + if (publickeyErr) return rej('invalid publickey param'); + + // if already subscribed + const exist = await Subscription.findOne({ + user_id: user._id, + endpoint: endpoint, + auth: auth, + publickey: publickey, + deleted_at: { $exists: false } + }); + + if (exist !== null) { + return res(); + } + + await Subscription.insert({ + user_id: user._id, + endpoint: endpoint, + auth: auth, + publickey: publickey + }); + + res(); +}); diff --git a/src/api/event.ts b/src/api/event.ts index 8605a0f1e4..4a2e4e453d 100644 --- a/src/api/event.ts +++ b/src/api/event.ts @@ -1,5 +1,6 @@ import * as mongo from 'mongodb'; import * as redis from 'redis'; +import swPush from './common/push-sw'; import config from '../conf'; type ID = string | mongo.ObjectID; @@ -17,6 +18,10 @@ class MisskeyEvent { this.publish(`user-stream:${userId}`, type, typeof value === 'undefined' ? null : value); } + public publishSw(userId: ID, type: string, value?: any): void { + swPush(userId, type, value); + } + public publishDriveStream(userId: ID, type: string, value?: any): void { this.publish(`drive-stream:${userId}`, type, typeof value === 'undefined' ? null : value); } @@ -50,6 +55,8 @@ const ev = new MisskeyEvent(); export default ev.publishUserStream.bind(ev); +export const pushSw = ev.publishSw.bind(ev); + export const publishDriveStream = ev.publishDriveStream.bind(ev); export const publishPostStream = ev.publishPostStream.bind(ev); diff --git a/src/api/models/sw-subscription.ts b/src/api/models/sw-subscription.ts new file mode 100644 index 0000000000..ecca04cb91 --- /dev/null +++ b/src/api/models/sw-subscription.ts @@ -0,0 +1,3 @@ +import db from '../../db/mongodb'; + +export default db.get('sw_subscriptions') as any; // fuck type definition diff --git a/src/config.ts b/src/config.ts index d37d227a41..e8322d8333 100644 --- a/src/config.ts +++ b/src/config.ts @@ -75,6 +75,14 @@ type Source = { analysis?: { mecab_command?: string; }; + + /** + * Service Worker + */ + sw?: { + gcm_sender_id: string; + gcm_api_key: string; + }; }; /** @@ -109,7 +117,7 @@ export default function load() { const url = URL.parse(config.url); const head = url.host.split('.')[0]; - if (head != 'misskey') { + if (head != 'misskey' && head != 'localhost') { console.error(`プライマリドメインは、必ず「misskey」ドメインで始まっていなければなりません(現在の設定では「${head}」で始まっています)。例えば「https://misskey.xyz」「http://misskey.my.app.example.com」などが正しいプライマリURLです。`); process.exit(); } diff --git a/src/web/app/boot.js b/src/web/app/boot.js index ac6c18d649..4a8ea030a1 100644 --- a/src/web/app/boot.js +++ b/src/web/app/boot.js @@ -27,7 +27,9 @@ // misskey.alice => misskey // misskey.strawberry.pasta => misskey // dev.misskey.arisu.tachibana => dev - let app = url.host.split('.')[0]; + let app = url.host == 'localhost' + ? 'misskey' + : url.host.split('.')[0]; // Detect the user language // Note: The default language is English diff --git a/src/web/app/common/mios.ts b/src/web/app/common/mios.ts index 9704e92af8..4a36d6375f 100644 --- a/src/web/app/common/mios.ts +++ b/src/web/app/common/mios.ts @@ -37,6 +37,11 @@ export default class MiOS extends EventEmitter { */ public stream: HomeStreamManager; + /** + * A registration of service worker + */ + private swRegistration: ServiceWorkerRegistration = null; + constructor() { super(); @@ -44,6 +49,7 @@ export default class MiOS extends EventEmitter { this.init = this.init.bind(this); this.api = this.api.bind(this); this.getMeta = this.getMeta.bind(this); + this.swSubscribe = this.swSubscribe.bind(this); //#endregion } @@ -126,6 +132,25 @@ export default class MiOS extends EventEmitter { // Finish init callback(); + + //#region Service worker + const isSwSupported = + ('serviceWorker' in navigator) && ('PushManager' in window); + + if (isSwSupported && this.isSignedin) { + // When service worker activated + navigator.serviceWorker.ready.then(this.swSubscribe); + + // Register service worker + navigator.serviceWorker.register('/sw.js').then(registration => { + // 登録成功 + console.info('ServiceWorker registration successful with scope: ', registration.scope); + }).catch(err => { + // 登録失敗 :( + console.error('ServiceWorker registration failed: ', err); + }); + } + //#endregion }; // Get cached account data @@ -147,6 +172,30 @@ export default class MiOS extends EventEmitter { } } + private async swSubscribe(swRegistration: ServiceWorkerRegistration) { + this.swRegistration = swRegistration; + + // Subscribe + this.swRegistration.pushManager.subscribe({ + // A boolean indicating that the returned push subscription + // will only be used for messages whose effect is made visible to the user. + userVisibleOnly: true + }).then(subscription => { + console.log('Subscribe OK:', subscription); + + // Register + this.api('sw/register', { + endpoint: subscription.endpoint, + auth: subscription.getKey('auth') ? btoa(String.fromCharCode.apply(null, new Uint8Array(subscription.getKey('auth')))) : '', + publickey: subscription.getKey('p256dh') ? btoa(String.fromCharCode.apply(null, new Uint8Array(subscription.getKey('p256dh')))) : '' + }); + }).then(() => { + console.log('Server Stored Subscription.'); + }).catch(err => { + console.error('Subscribe Error:', err); + }); + } + /** * Misskey APIにリクエストします * @param endpoint エンドポイント名 diff --git a/src/web/app/common/scripts/config.ts b/src/web/app/common/scripts/config.ts index c5015622f0..b4801a44de 100644 --- a/src/web/app/common/scripts/config.ts +++ b/src/web/app/common/scripts/config.ts @@ -1,9 +1,11 @@ -const Url = new URL(location.href); +const _url = new URL(location.href); -const isRoot = Url.host.split('.')[0] == 'misskey'; +const isRoot = _url.host == 'localhost' + ? true + : _url.host.split('.')[0] == 'misskey'; -const host = isRoot ? Url.host : Url.host.substring(Url.host.indexOf('.') + 1, Url.host.length); -const scheme = Url.protocol; +const host = isRoot ? _url.host : _url.host.substring(_url.host.indexOf('.') + 1, _url.host.length); +const scheme = _url.protocol; const url = `${scheme}//${host}`; const apiUrl = `${scheme}//api.${host}`; const chUrl = `${scheme}//ch.${host}`; diff --git a/src/web/assets/sw.js b/src/web/assets/sw.js new file mode 100644 index 0000000000..6a1251614a --- /dev/null +++ b/src/web/assets/sw.js @@ -0,0 +1,31 @@ +/** + * Service Worker + */ + +// インストールされたとき +self.addEventListener('install', () => { + console.log('[sw]', 'Your ServiceWorker is installed'); +}); + +// プッシュ通知を受け取ったとき +self.addEventListener('push', ev => { + // クライアント取得 + self.clients.matchAll({ + includeUncontrolled: true + }).then(clients => { + // クライアントがあったらストリームに接続しているということなので通知しない + if (clients.length != 0) return; + + const { type, body } = ev.data.json(); + handlers[type](body); + }); +}); + +const handlers = { + mention: body => { + self.registration.showNotification('mentioned', { + body: body.text, + icon: body.user.avatar_url + '?thumbnail&size=64', + }); + } +}; diff --git a/src/web/server.ts b/src/web/server.ts index dde4eca5ec..300f3ed477 100644 --- a/src/web/server.ts +++ b/src/web/server.ts @@ -37,28 +37,45 @@ app.use((req, res, next) => { * Static assets */ app.use(favicon(`${__dirname}/assets/favicon.ico`)); -app.get('/manifest.json', (req, res) => res.sendFile(`${__dirname}/assets/manifest.json`)); app.get('/apple-touch-icon.png', (req, res) => res.sendFile(`${__dirname}/assets/apple-touch-icon.png`)); app.use('/assets', express.static(`${__dirname}/assets`, { maxAge: ms('7 days') })); +app.get('/sw.js', (req, res) => res.sendFile(`${__dirname}/assets/sw.js`)); + /** - * Common API + * Manifest */ -app.get(/\/api:url/, require('./service/url-preview')); +app.get('/manifest.json', (req, res) => { + const manifest = require((`${__dirname}/assets/manifest.json`)); + + // Service Worker + if (config.sw) { + manifest['gcm_sender_id'] = config.sw.gcm_sender_id; + } + + res.send(manifest); +}); /** * Serve config */ app.get('/config.json', (req, res) => { - res.send({ + const conf = { recaptcha: { siteKey: config.recaptcha.siteKey } - }); + }; + + res.send(conf); }); +/** + * Common API + */ +app.get(/\/api:url/, require('./service/url-preview')); + /** * Routing */ -- cgit v1.2.3-freya From c598a9cba2d4cdecf2aec3dcde1a893ee039bce3 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 21 Nov 2017 05:09:45 +0900 Subject: wip --- src/api/endpoints/messaging/messages/create.ts | 4 +- src/web/app/common/mios.ts | 5 ++- src/web/app/common/scripts/compose-notification.ts | 52 ++++++++++++++++++++++ src/web/app/desktop/script.ts | 37 ++++++++------- src/web/app/sw.js | 30 +++++++++++++ src/web/assets/sw.js | 31 ------------- src/web/server.ts | 2 +- webpack/webpack.config.ts | 3 +- 8 files changed, 112 insertions(+), 52 deletions(-) create mode 100644 src/web/app/common/scripts/compose-notification.ts create mode 100644 src/web/app/sw.js delete mode 100644 src/web/assets/sw.js (limited to 'src/web/app/common') diff --git a/src/api/endpoints/messaging/messages/create.ts b/src/api/endpoints/messaging/messages/create.ts index 29a4671f84..3c7689f967 100644 --- a/src/api/endpoints/messaging/messages/create.ts +++ b/src/api/endpoints/messaging/messages/create.ts @@ -9,8 +9,7 @@ import User from '../../../models/user'; import DriveFile from '../../../models/drive-file'; import serialize from '../../../serializers/messaging-message'; import publishUserStream from '../../../event'; -import { publishMessagingStream } from '../../../event'; -import { publishMessagingIndexStream } from '../../../event'; +import { publishMessagingStream, publishMessagingIndexStream, pushSw } from '../../../event'; import config from '../../../../conf'; /** @@ -99,6 +98,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { const freshMessage = await Message.findOne({ _id: message._id }, { is_read: true }); if (!freshMessage.is_read) { publishUserStream(message.recipient_id, 'unread_messaging_message', messageObj); + pushSw(message.recipient_id, 'unread_messaging_message', messageObj); } }, 3000); diff --git a/src/web/app/common/mios.ts b/src/web/app/common/mios.ts index 4a36d6375f..a98ef5f477 100644 --- a/src/web/app/common/mios.ts +++ b/src/web/app/common/mios.ts @@ -6,6 +6,9 @@ import HomeStreamManager from './scripts/streaming/home-stream-manager'; import CONFIG from './scripts/config'; import api from './scripts/api'; +declare var VERSION: string; +declare var LANG: string; + /** * Misskey Operating System */ @@ -142,7 +145,7 @@ export default class MiOS extends EventEmitter { navigator.serviceWorker.ready.then(this.swSubscribe); // Register service worker - navigator.serviceWorker.register('/sw.js').then(registration => { + navigator.serviceWorker.register(`/sw.${VERSION}.${LANG}.js`).then(registration => { // 登録成功 console.info('ServiceWorker registration successful with scope: ', registration.scope); }).catch(err => { diff --git a/src/web/app/common/scripts/compose-notification.ts b/src/web/app/common/scripts/compose-notification.ts new file mode 100644 index 0000000000..181dca734f --- /dev/null +++ b/src/web/app/common/scripts/compose-notification.ts @@ -0,0 +1,52 @@ +import getPostSummary from '../../../../common/get-post-summary'; + +type Notification = { + title: string; + body: string; + icon: string; + onclick?: any; +}; + +// TODO: i18n + +export default function(type, data): Notification { + switch (type) { + case 'drive_file_created': + return { + title: 'ファイルがアップロードされました', + body: data.name, + icon: data.url + '?thumbnail&size=64' + }; + + case 'mention': + return { + title: `${data.user.name}さんから:`, + body: getPostSummary(data), + icon: data.user.avatar_url + '?thumbnail&size=64' + }; + + case 'reply': + return { + title: `${data.user.name}さんから返信:`, + body: getPostSummary(data), + icon: data.user.avatar_url + '?thumbnail&size=64' + }; + + case 'quote': + return { + title: `${data.user.name}さんが引用:`, + body: getPostSummary(data), + icon: data.user.avatar_url + '?thumbnail&size=64' + }; + + case 'unread_messaging_message': + return { + title: `${data.user.name}さんからメッセージ:`, + body: data.text, // TODO: getMessagingMessageSummary(data), + icon: data.user.avatar_url + '?thumbnail&size=64' + }; + + default: + return null; + } +} diff --git a/src/web/app/desktop/script.ts b/src/web/app/desktop/script.ts index bc0fc8dfe3..694cb7879c 100644 --- a/src/web/app/desktop/script.ts +++ b/src/web/app/desktop/script.ts @@ -11,9 +11,9 @@ import * as riot from 'riot'; import init from '../init'; import route from './router'; import fuckAdBlock from './scripts/fuck-ad-block'; -import getPostSummary from '../../../common/get-post-summary'; import MiOS from '../common/mios'; import HomeStreamManager from '../common/scripts/streaming/home-stream-manager'; +import composeNotification from '../common/scripts/compose-notification'; /** * init @@ -55,41 +55,46 @@ function registerNotifications(stream: HomeStreamManager) { function attach(connection) { connection.on('drive_file_created', file => { - const n = new Notification('ファイルがアップロードされました', { - body: file.name, - icon: file.url + '?thumbnail&size=64' + const _n = composeNotification('drive_file_created', file); + const n = new Notification(_n.title, { + body: _n.body, + icon: _n.icon }); setTimeout(n.close.bind(n), 5000); }); connection.on('mention', post => { - const n = new Notification(`${post.user.name}さんから:`, { - body: getPostSummary(post), - icon: post.user.avatar_url + '?thumbnail&size=64' + const _n = composeNotification('mention', post); + const n = new Notification(_n.title, { + body: _n.body, + icon: _n.icon }); setTimeout(n.close.bind(n), 6000); }); connection.on('reply', post => { - const n = new Notification(`${post.user.name}さんから返信:`, { - body: getPostSummary(post), - icon: post.user.avatar_url + '?thumbnail&size=64' + const _n = composeNotification('reply', post); + const n = new Notification(_n.title, { + body: _n.body, + icon: _n.icon }); setTimeout(n.close.bind(n), 6000); }); connection.on('quote', post => { - const n = new Notification(`${post.user.name}さんが引用:`, { - body: getPostSummary(post), - icon: post.user.avatar_url + '?thumbnail&size=64' + const _n = composeNotification('quote', post); + const n = new Notification(_n.title, { + body: _n.body, + icon: _n.icon }); setTimeout(n.close.bind(n), 6000); }); connection.on('unread_messaging_message', message => { - const n = new Notification(`${message.user.name}さんからメッセージ:`, { - body: message.text, // TODO: getMessagingMessageSummary(message), - icon: message.user.avatar_url + '?thumbnail&size=64' + const _n = composeNotification('unread_messaging_message', message); + const n = new Notification(_n.title, { + body: _n.body, + icon: _n.icon }); n.onclick = () => { n.close(); diff --git a/src/web/app/sw.js b/src/web/app/sw.js new file mode 100644 index 0000000000..463ae0c75e --- /dev/null +++ b/src/web/app/sw.js @@ -0,0 +1,30 @@ +/** + * Service Worker + */ + +import composeNotification from './common/scripts/compose-notification'; + +// インストールされたとき +self.addEventListener('install', () => { + console.log('[sw]', 'Your ServiceWorker is installed'); +}); + +// プッシュ通知を受け取ったとき +self.addEventListener('push', ev => { + // クライアント取得 + self.clients.matchAll({ + includeUncontrolled: true + }).then(clients => { + // クライアントがあったらストリームに接続しているということなので通知しない + if (clients.length != 0) return; + + const { type, body } = ev.data.json(); + const n = composeNotification(type, body); + if (n) { + self.registration.showNotification(n.title, { + body: n.body, + icon: n.icon, + }); + } + }); +}); diff --git a/src/web/assets/sw.js b/src/web/assets/sw.js deleted file mode 100644 index 6a1251614a..0000000000 --- a/src/web/assets/sw.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Service Worker - */ - -// インストールされたとき -self.addEventListener('install', () => { - console.log('[sw]', 'Your ServiceWorker is installed'); -}); - -// プッシュ通知を受け取ったとき -self.addEventListener('push', ev => { - // クライアント取得 - self.clients.matchAll({ - includeUncontrolled: true - }).then(clients => { - // クライアントがあったらストリームに接続しているということなので通知しない - if (clients.length != 0) return; - - const { type, body } = ev.data.json(); - handlers[type](body); - }); -}); - -const handlers = { - mention: body => { - self.registration.showNotification('mentioned', { - body: body.text, - icon: body.user.avatar_url + '?thumbnail&size=64', - }); - } -}; diff --git a/src/web/server.ts b/src/web/server.ts index 300f3ed477..0be07b2d8b 100644 --- a/src/web/server.ts +++ b/src/web/server.ts @@ -42,7 +42,7 @@ app.use('/assets', express.static(`${__dirname}/assets`, { maxAge: ms('7 days') })); -app.get('/sw.js', (req, res) => res.sendFile(`${__dirname}/assets/sw.js`)); +app.get(/^\/sw\.(.+?)\.js$/, (req, res) => res.sendFile(`${__dirname}/assets/sw.${req.params[0]}.js`)); /** * Manifest diff --git a/webpack/webpack.config.ts b/webpack/webpack.config.ts index f2bcf48f31..753d89fede 100644 --- a/webpack/webpack.config.ts +++ b/webpack/webpack.config.ts @@ -20,7 +20,8 @@ module.exports = langs.map(([lang, locale]) => { stats: './src/web/app/stats/script.ts', status: './src/web/app/status/script.ts', dev: './src/web/app/dev/script.ts', - auth: './src/web/app/auth/script.ts' + auth: './src/web/app/auth/script.ts', + sw: './src/web/app/sw.js' }; const output = { -- cgit v1.2.3-freya From cad1e0458ff7f24c984ccc64d18759d9b9da451a Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 21 Nov 2017 05:37:29 +0900 Subject: Update mios.ts --- src/web/app/common/mios.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/web/app/common') diff --git a/src/web/app/common/mios.ts b/src/web/app/common/mios.ts index a98ef5f477..5e76d82a38 100644 --- a/src/web/app/common/mios.ts +++ b/src/web/app/common/mios.ts @@ -189,8 +189,8 @@ export default class MiOS extends EventEmitter { // Register this.api('sw/register', { endpoint: subscription.endpoint, - auth: subscription.getKey('auth') ? btoa(String.fromCharCode.apply(null, new Uint8Array(subscription.getKey('auth')))) : '', - publickey: subscription.getKey('p256dh') ? btoa(String.fromCharCode.apply(null, new Uint8Array(subscription.getKey('p256dh')))) : '' + auth: btoa(String.fromCharCode.apply(null, new Uint8Array(subscription.getKey('auth')))), + publickey: btoa(String.fromCharCode.apply(null, new Uint8Array(subscription.getKey('p256dh')))) }); }).then(() => { console.log('Server Stored Subscription.'); -- cgit v1.2.3-freya From 411c006d9fc525d8abccc3880eefa8a1e422a6a1 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 21 Nov 2017 07:06:36 +0900 Subject: :v: --- src/web/app/common/mios.ts | 132 ++++++++++++++++++++++++++++++++------------- src/web/app/sw.js | 21 ++++---- 2 files changed, 107 insertions(+), 46 deletions(-) (limited to 'src/web/app/common') diff --git a/src/web/app/common/mios.ts b/src/web/app/common/mios.ts index 5e76d82a38..cf7841d848 100644 --- a/src/web/app/common/mios.ts +++ b/src/web/app/common/mios.ts @@ -35,6 +35,13 @@ export default class MiOS extends EventEmitter { return this.i != null; } + /** + * Whether is debug mode + */ + public get debug() { + return localStorage.getItem('debug') == 'true'; + } + /** * A connection manager of home stream */ @@ -49,13 +56,37 @@ export default class MiOS extends EventEmitter { super(); //#region BIND + this.log = this.log.bind(this); + this.logInfo = this.logInfo.bind(this); + this.logWarn = this.logWarn.bind(this); + this.logError = this.logError.bind(this); this.init = this.init.bind(this); this.api = this.api.bind(this); this.getMeta = this.getMeta.bind(this); - this.swSubscribe = this.swSubscribe.bind(this); + this.registerSw = this.registerSw.bind(this); //#endregion } + public log(...args) { + if (!this.debug) return; + console.log.apply(null, args); + } + + public logInfo(...args) { + if (!this.debug) return; + console.info.apply(null, args); + } + + public logWarn(...args) { + if (!this.debug) return; + console.warn.apply(null, args); + } + + public logError(...args) { + if (!this.debug) return; + console.error.apply(null, args); + } + /** * Initialize MiOS (boot) * @param callback A function that call when initialized @@ -136,30 +167,20 @@ export default class MiOS extends EventEmitter { // Finish init callback(); - //#region Service worker - const isSwSupported = - ('serviceWorker' in navigator) && ('PushManager' in window); - - if (isSwSupported && this.isSignedin) { - // When service worker activated - navigator.serviceWorker.ready.then(this.swSubscribe); - - // Register service worker - navigator.serviceWorker.register(`/sw.${VERSION}.${LANG}.js`).then(registration => { - // 登録成功 - console.info('ServiceWorker registration successful with scope: ', registration.scope); - }).catch(err => { - // 登録失敗 :( - console.error('ServiceWorker registration failed: ', err); - }); - } + //#region Post + + // Init service worker + this.registerSw(); + //#endregion }; // Get cached account data const cachedMe = JSON.parse(localStorage.getItem('me')); + // キャッシュがあったとき if (cachedMe) { + // とりあえずキャッシュされたデータでお茶を濁して(?)おいて、 fetched(cachedMe); // 後から新鮮なデータをフェッチ @@ -175,27 +196,64 @@ export default class MiOS extends EventEmitter { } } - private async swSubscribe(swRegistration: ServiceWorkerRegistration) { - this.swRegistration = swRegistration; - - // Subscribe - this.swRegistration.pushManager.subscribe({ - // A boolean indicating that the returned push subscription - // will only be used for messages whose effect is made visible to the user. - userVisibleOnly: true - }).then(subscription => { - console.log('Subscribe OK:', subscription); - - // Register - this.api('sw/register', { - endpoint: subscription.endpoint, - auth: btoa(String.fromCharCode.apply(null, new Uint8Array(subscription.getKey('auth')))), - publickey: btoa(String.fromCharCode.apply(null, new Uint8Array(subscription.getKey('p256dh')))) + /** + * Register service worker + */ + private registerSw() { + // Check whether service worker and push manager supported + const isSwSupported = + ('serviceWorker' in navigator) && ('PushManager' in window); + + // Reject when browser not service worker supported + if (!isSwSupported) return; + + // Reject when not signed in to Misskey + if (!this.isSignedin) return; + + // When service worker activated + navigator.serviceWorker.ready.then(registration => { + this.log('[sw] ready: ', registration); + + this.swRegistration = registration; + + // Options of pushManager.subscribe + const opts = { + // A boolean indicating that the returned push subscription + // will only be used for messages whose effect is made visible to the user. + userVisibleOnly: true + }; + + // Subscribe push notification + this.swRegistration.pushManager.subscribe(opts).then(subscription => { + this.log('[sw] Subscribe OK:', subscription); + + function encode(buffer: ArrayBuffer) { + return btoa(String.fromCharCode.apply(null, new Uint8Array(buffer))); + } + + // Register + this.api('sw/register', { + endpoint: subscription.endpoint, + auth: encode(subscription.getKey('auth')), + publickey: encode(subscription.getKey('p256dh')) + }); + }).then(() => { + this.logInfo('[sw] Server Stored Subscription.'); + }).catch(err => { + this.logError('[sw] Subscribe Error:', err); }); - }).then(() => { - console.log('Server Stored Subscription.'); + }); + + // The path of service worker script + const sw = `/sw.${VERSION}.${LANG}.js`; + + // Register service worker + navigator.serviceWorker.register(sw).then(registration => { + // 登録成功 + this.logInfo('[sw] Registration successful with scope: ', registration.scope); }).catch(err => { - console.error('Subscribe Error:', err); + // 登録失敗 :( + this.logError('[sw] Registration failed: ', err); }); } diff --git a/src/web/app/sw.js b/src/web/app/sw.js index 463ae0c75e..a7c84d022a 100644 --- a/src/web/app/sw.js +++ b/src/web/app/sw.js @@ -6,25 +6,28 @@ import composeNotification from './common/scripts/compose-notification'; // インストールされたとき self.addEventListener('install', () => { - console.log('[sw]', 'Your ServiceWorker is installed'); + console.info('installed'); }); // プッシュ通知を受け取ったとき self.addEventListener('push', ev => { + console.log('pushed'); + // クライアント取得 - self.clients.matchAll({ + ev.waitUntil(self.clients.matchAll({ includeUncontrolled: true }).then(clients => { // クライアントがあったらストリームに接続しているということなので通知しない if (clients.length != 0) return; const { type, body } = ev.data.json(); + + console.log(type, body); + const n = composeNotification(type, body); - if (n) { - self.registration.showNotification(n.title, { - body: n.body, - icon: n.icon, - }); - } - }); + return self.registration.showNotification(n.title, { + body: n.body, + icon: n.icon, + }); + })); }); -- cgit v1.2.3-freya From c47addc973af1a685dfa39ed1e484df85a02e306 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 21 Nov 2017 10:01:00 +0900 Subject: #934 --- src/web/app/common/mios.ts | 15 +++++++++++++-- src/web/app/desktop/script.ts | 2 +- src/web/app/init.ts | 4 ++-- src/web/app/mobile/script.ts | 2 +- 4 files changed, 17 insertions(+), 6 deletions(-) (limited to 'src/web/app/common') diff --git a/src/web/app/common/mios.ts b/src/web/app/common/mios.ts index cf7841d848..838be9c370 100644 --- a/src/web/app/common/mios.ts +++ b/src/web/app/common/mios.ts @@ -52,9 +52,20 @@ export default class MiOS extends EventEmitter { */ private swRegistration: ServiceWorkerRegistration = null; - constructor() { + /** + * Whether should register ServiceWorker + */ + private shouldRegisterSw: boolean; + + /** + * MiOSインスタンスを作成します + * @param shouldRegisterSw ServiceWorkerを登録するかどうか + */ + constructor(shouldRegisterSw = false) { super(); + this.shouldRegisterSw = shouldRegisterSw; + //#region BIND this.log = this.log.bind(this); this.logInfo = this.logInfo.bind(this); @@ -170,7 +181,7 @@ export default class MiOS extends EventEmitter { //#region Post // Init service worker - this.registerSw(); + if (this.shouldRegisterSw) this.registerSw(); //#endregion }; diff --git a/src/web/app/desktop/script.ts b/src/web/app/desktop/script.ts index 694cb7879c..b06cb180e1 100644 --- a/src/web/app/desktop/script.ts +++ b/src/web/app/desktop/script.ts @@ -40,7 +40,7 @@ init(async (mios: MiOS) => { // Start routing route(mios); -}); +}, true); function registerNotifications(stream: HomeStreamManager) { if (stream == null) return; diff --git a/src/web/app/init.ts b/src/web/app/init.ts index 652cbfde40..19605dc8a5 100644 --- a/src/web/app/init.ts +++ b/src/web/app/init.ts @@ -52,8 +52,8 @@ if (localStorage.getItem('should-refresh') == 'true') { } // MiOSを初期化してコールバックする -export default callback => { - const mios = new MiOS(); +export default (callback, sw = false) => { + const mios = new MiOS(sw); mios.init(() => { // ミックスイン初期化 diff --git a/src/web/app/mobile/script.ts b/src/web/app/mobile/script.ts index 74dfe3dfe8..4dfff8f72f 100644 --- a/src/web/app/mobile/script.ts +++ b/src/web/app/mobile/script.ts @@ -19,4 +19,4 @@ init((mios: MiOS) => { // Start routing route(mios); -}); +}, true); -- cgit v1.2.3-freya From ed18d3cc2283ea15c6909df9bfbc16027c0ab003 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 21 Nov 2017 12:40:48 +0900 Subject: #935 --- src/web/app/common/mios.ts | 1 + src/web/app/desktop/tags/home.tag | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'src/web/app/common') diff --git a/src/web/app/common/mios.ts b/src/web/app/common/mios.ts index 838be9c370..96dac70f61 100644 --- a/src/web/app/common/mios.ts +++ b/src/web/app/common/mios.ts @@ -198,6 +198,7 @@ export default class MiOS extends EventEmitter { fetchme(cachedMe.token, freshData => { Object.assign(cachedMe, freshData); cachedMe.trigger('updated'); + cachedMe.trigger('refreshed'); }); } else { // Get token from cookie diff --git a/src/web/app/desktop/tags/home.tag b/src/web/app/desktop/tags/home.tag index fb244941a7..c751117517 100644 --- a/src/web/app/desktop/tags/home.tag +++ b/src/web/app/desktop/tags/home.tag @@ -193,11 +193,16 @@ this.home = []; + this.bakeHomeData = () => JSON.stringify(this.I.client_settings.home); + this.bakedHomeData = this.bakeHomeData(); + this.on('mount', () => { this.refs.tl.on('loaded', () => { this.trigger('loaded'); }); + this.I.on('refreshed', this.onMeRefreshed); + this.I.client_settings.home.forEach(widget => { try { this.setWidget(widget); @@ -256,6 +261,8 @@ }); this.on('unmount', () => { + this.I.off('refreshed', this.onMeRefreshed); + this.home.forEach(widget => { widget.unmount(); }); @@ -266,6 +273,12 @@ } }); + this.onMeRefreshed = () => { + if (this.bakedHomeData != this.bakeHomeData()) { + alert('別の場所でホームが編集されました。ページを再度読み込みすると編集が反映されます。'); + } + }; + this.setWidget = (widget, prepend = false) => { const el = document.createElement(`mk-${widget.name}-home-widget`); @@ -366,7 +379,6 @@ this.api('i/update_home', { home: data }).then(() => { - this.I.client_settings.home = data; this.I.update(); }); }; -- cgit v1.2.3-freya From 3f8ebac466ece8e9598432f3f574ec44e420c03b Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 23 Nov 2017 05:43:00 +0900 Subject: なんかもうめっちゃ変えた MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #940 --- .travis/default.yml | 4 +- .travis/test.yml | 4 +- docs/config.md | 55 ++++++++++++++++++++++ docs/setup.en.md | 27 ++++------- docs/setup.ja.md | 29 ++++-------- src/api/common/push-sw.ts | 6 ++- src/api/private/signup.ts | 2 +- src/config.ts | 31 ++++++------ src/web/app/ch/tags/channel.tag | 13 ++--- src/web/app/ch/tags/header.tag | 6 +-- src/web/app/common/mios.ts | 37 ++++++++++++--- src/web/app/common/scripts/api.ts | 4 +- src/web/app/common/scripts/check-for-update.ts | 6 +-- src/web/app/common/scripts/config.ts | 27 ----------- src/web/app/common/scripts/signout.ts | 4 +- src/web/app/common/scripts/streaming/stream.ts | 5 +- src/web/app/common/scripts/text-compiler.ts | 5 +- src/web/app/common/tags/error.tag | 4 +- src/web/app/common/tags/introduction.tag | 2 +- src/web/app/common/tags/nav-links.tag | 2 +- src/web/app/common/tags/signup.tag | 26 +++++----- src/web/app/common/tags/twitter-setting.tag | 12 ++--- src/web/app/common/tags/uploader.tag | 2 +- src/web/app/desktop/scripts/fuck-ad-block.ts | 2 +- src/web/app/desktop/scripts/update-avatar.ts | 5 +- src/web/app/desktop/scripts/update-banner.ts | 5 +- src/web/app/desktop/tags/analog-clock.tag | 2 +- src/web/app/desktop/tags/drive/browser-window.tag | 6 +-- .../app/desktop/tags/home-widgets/broadcast.tag | 4 +- src/web/app/desktop/tags/home-widgets/channel.tag | 2 +- src/web/app/desktop/tags/home-widgets/version.tag | 4 +- src/web/app/desktop/tags/messaging/room-window.tag | 4 +- src/web/app/desktop/tags/pages/entrance.tag | 2 +- src/web/app/desktop/tags/timeline.tag | 2 +- src/web/app/desktop/tags/ui.tag | 4 +- src/web/app/init.ts | 20 ++++---- src/web/app/mobile/tags/page/settings.tag | 4 +- src/web/app/mobile/tags/timeline.tag | 2 +- src/web/app/mobile/tags/ui.tag | 4 +- src/web/app/stats/tags/index.tag | 2 +- src/web/app/status/tags/index.tag | 2 +- src/web/server.ts | 26 +--------- webpack/module/rules/consts.ts | 36 ++++++++++++++ webpack/module/rules/index.ts | 2 + webpack/plugins/const.ts | 14 ------ webpack/plugins/index.ts | 2 - 46 files changed, 244 insertions(+), 225 deletions(-) create mode 100644 docs/config.md delete mode 100644 src/web/app/common/scripts/config.ts create mode 100644 webpack/module/rules/consts.ts delete mode 100644 webpack/plugins/const.ts (limited to 'src/web/app/common') diff --git a/.travis/default.yml b/.travis/default.yml index 1875748d68..471a2a7c46 100644 --- a/.travis/default.yml +++ b/.travis/default.yml @@ -22,5 +22,5 @@ elasticsearch: port: 9200 pass: '' recaptcha: - siteKey: hima - secretKey: saku + site_key: hima + secret_key: saku diff --git a/.travis/test.yml b/.travis/test.yml index f311310c7c..6a115d6ab8 100644 --- a/.travis/test.yml +++ b/.travis/test.yml @@ -22,5 +22,5 @@ elasticsearch: port: 9200 pass: '' recaptcha: - siteKey: hima - secretKey: saku + site_key: hima + secret_key: saku diff --git a/docs/config.md b/docs/config.md new file mode 100644 index 0000000000..0e23e09ae8 --- /dev/null +++ b/docs/config.md @@ -0,0 +1,55 @@ +``` yaml +# サーバーのメンテナ情報 +maintainer: + # メンテナの名前 + name: + + # メンテナの連絡先(URLかmailto形式のURL) + url: + +# プライマリURL +url: + +# セカンダリURL +secondary_url: + +# 待受ポート +port: + +# TLSの設定 +https: + # TLSを有効にするか否か + enable: false + + key: null + cert: null + ca: null + +# MongoDBの設定 +mongodb: + host: localhost + port: 27017 + db: misskey + user: + pass: + +# Redisの設定 +redis: + host: localhost + port: 6379 + pass: + +# reCAPTCHAの設定 +recaptcha: + site_key: + secret_key: + +# ServiceWrokerの設定 +sw: + # VAPIDの公開鍵 + public_key: + + # VAPIDの秘密鍵 + private_key: + +``` diff --git a/docs/setup.en.md b/docs/setup.en.md index 5ad57d5abd..9c31e4f177 100644 --- a/docs/setup.en.md +++ b/docs/setup.en.md @@ -36,6 +36,15 @@ Note that Misskey uses following subdomains: Misskey requires reCAPTCHA tokens. Please visit https://www.google.com/recaptcha/intro/ and generate keys. +*(optional)* Generating VAPID keys +---------------------------------------------------------------- +If you want to enable ServiceWroker, you need to generate VAPID keys: + +``` shell +npm install web-push -g +web-push generate-vapid-keys +``` + *3.* Install dependencies ---------------------------------------------------------------- Please install and setup these softwares: @@ -51,24 +60,6 @@ Please install and setup these softwares: *4.* Install Misskey ---------------------------------------------------------------- -There is **two ways** to install Misskey: - -### WAY 1) Using built code (recommended) -We have the official release of Misskey. -The built code is automatically pushed to https://github.com/syuilo/misskey/tree/release after the CI test succeeds. - -1. `git clone -b release git://github.com/syuilo/misskey.git` -2. `cd misskey` -3. `npm install` - -#### Update -1. `git fetch` -2. `git reset --hard origin/release` -3. `npm install` - -### WAY 2) Using source code -If you want to build Misskey manually, you can do it via the -`build` command after download the source code of Misskey and install dependencies: 1. `git clone -b master git://github.com/syuilo/misskey.git` 2. `cd misskey` diff --git a/docs/setup.ja.md b/docs/setup.ja.md index 602fd9b6a1..1e8bb553fa 100644 --- a/docs/setup.ja.md +++ b/docs/setup.ja.md @@ -37,6 +37,15 @@ Misskeyは以下のサブドメインを使います: MisskeyはreCAPTCHAトークンを必要とします。 https://www.google.com/recaptcha/intro/ にアクセスしてトークンを生成してください。 +*(オプション)* VAPIDキーペアの生成 +---------------------------------------------------------------- +ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります: + +``` shell +npm install web-push -g +web-push generate-vapid-keys +``` + *3.* 依存関係をインストールする ---------------------------------------------------------------- これらのソフトウェアをインストール・設定してください: @@ -52,26 +61,6 @@ https://www.google.com/recaptcha/intro/ にアクセスしてトークンを生 *4.* Misskeyのインストール ---------------------------------------------------------------- -Misskeyをインストールするには**2つの方法**があります: - -### 方法 1) ビルドされたコードを利用する (推奨) -Misskeyには公式のリリースがあります。 -ビルドされたコードはCIテストに合格した後、自動で https://github.com/syuilo/misskey/tree/release にpushされています。 - -1. `git clone -b release git://github.com/syuilo/misskey.git` -2. `cd misskey` -3. `npm install` - -#### アップデートするには: -1. `git fetch` -2. `git reset --hard origin/release` -3. `npm install` - -### 方法 2) ソースコードを利用する -> 注: この方法では正しくビルド・動作できることは保証されません。 - -Misskeyを手動でビルドしたい場合は、Misskeyのソースコードと依存関係をインストールした後、 -`build`コマンドを用いることができます: 1. `git clone -b master git://github.com/syuilo/misskey.git` 2. `cd misskey` diff --git a/src/api/common/push-sw.ts b/src/api/common/push-sw.ts index 782a4a6a6c..2993c760ee 100644 --- a/src/api/common/push-sw.ts +++ b/src/api/common/push-sw.ts @@ -4,7 +4,11 @@ import Subscription from '../models/sw-subscription'; import config from '../../conf'; if (config.sw) { - push.setGCMAPIKey(config.sw.gcm_api_key); + // アプリケーションの連絡先と、サーバーサイドの鍵ペアの情報を登録 + push.setVapidDetails( + config.maintainer.url, + config.sw.public_key, + config.sw.private_key); } export default async function(userId: mongo.ObjectID | string, type, body?) { diff --git a/src/api/private/signup.ts b/src/api/private/signup.ts index e24734f80c..466c6a489f 100644 --- a/src/api/private/signup.ts +++ b/src/api/private/signup.ts @@ -9,7 +9,7 @@ import generateUserToken from '../common/generate-native-user-token'; import config from '../../conf'; recaptcha.init({ - secret_key: config.recaptcha.secretKey + secret_key: config.recaptcha.secret_key }); const home = { diff --git a/src/config.ts b/src/config.ts index e8322d8333..7237b666f2 100644 --- a/src/config.ts +++ b/src/config.ts @@ -3,7 +3,6 @@ */ import * as fs from 'fs'; -import * as URL from 'url'; import * as yaml from 'js-yaml'; import isUrl = require('is-url'); @@ -23,7 +22,19 @@ export const path = process.env.NODE_ENV == 'test' * ユーザーが設定する必要のある情報 */ type Source = { - maintainer: string; + /** + * メンテナ情報 + */ + maintainer: { + /** + * メンテナの名前 + */ + name: string; + /** + * メンテナの連絡先(URLかmailto形式のURL) + */ + url: string; + }; url: string; secondary_url: string; port: number; @@ -52,8 +63,8 @@ type Source = { pass: string; }; recaptcha: { - siteKey: string; - secretKey: string; + site_key: string; + secret_key: string; }; accesslog?: string; accesses?: { @@ -80,8 +91,8 @@ type Source = { * Service Worker */ sw?: { - gcm_sender_id: string; - gcm_api_key: string; + public_key: string; + private_key: string; }; }; @@ -114,14 +125,6 @@ export default function load() { if (!isUrl(config.url)) urlError(config.url); if (!isUrl(config.secondary_url)) urlError(config.secondary_url); - const url = URL.parse(config.url); - const head = url.host.split('.')[0]; - - if (head != 'misskey' && head != 'localhost') { - console.error(`プライマリドメインは、必ず「misskey」ドメインで始まっていなければなりません(現在の設定では「${head}」で始まっています)。例えば「https://misskey.xyz」「http://misskey.my.app.example.com」などが正しいプライマリURLです。`); - process.exit(); - } - config.url = normalizeUrl(config.url); config.secondary_url = normalizeUrl(config.secondary_url); diff --git a/src/web/app/ch/tags/channel.tag b/src/web/app/ch/tags/channel.tag index 8300bd5715..716d61cde4 100644 --- a/src/web/app/ch/tags/channel.tag +++ b/src/web/app/ch/tags/channel.tag @@ -26,11 +26,11 @@
-

参加するにはログインまたは新規登録してください

+

参加するにはログインまたは新規登録してください


- Misskey ver { version } (葵 aoi) + Misskey ver { _VERSION_ } (葵 aoi)
diff --git a/src/web/app/desktop/tags/messaging/room-window.tag b/src/web/app/desktop/tags/messaging/room-window.tag index dca0172be3..1c6ff7c4bc 100644 --- a/src/web/app/desktop/tags/messaging/room-window.tag +++ b/src/web/app/desktop/tags/messaging/room-window.tag @@ -19,11 +19,9 @@ diff --git a/src/web/app/mobile/tags/timeline.tag b/src/web/app/mobile/tags/timeline.tag index 1d6ce23598..074422a20e 100644 --- a/src/web/app/mobile/tags/timeline.tag +++ b/src/web/app/mobile/tags/timeline.tag @@ -164,7 +164,7 @@
-

{ p.channel.title }:

+

{ p.channel.title }:

diff --git a/src/web/app/mobile/tags/ui.tag b/src/web/app/mobile/tags/ui.tag index 0c969d3902..bad6bf73fe 100644 --- a/src/web/app/mobile/tags/ui.tag +++ b/src/web/app/mobile/tags/ui.tag @@ -239,7 +239,7 @@
  • %i18n:mobile.tags.mk-ui-nav.messaging%
  • -

    %i18n:mobile.tags.mk-ui-nav.about%

    +

    %i18n:mobile.tags.mk-ui-nav.about%