From c614e6f5d73b3b4314c7f6abf52260e58cc176ad Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 17 Nov 2017 01:24:44 +0900 Subject: #925, #926, and refactoring --- .../app/common/scripts/streaming/channel-stream.ts | 12 +++ .../scripts/streaming/drive-stream-manager.ts | 20 +++++ .../app/common/scripts/streaming/drive-stream.ts | 12 +++ .../scripts/streaming/home-stream-manager.ts | 20 +++++ .../app/common/scripts/streaming/home-stream.ts | 28 +++++++ .../streaming/messaging-index-stream-manager.ts | 20 +++++ .../scripts/streaming/messaging-index-stream.ts | 12 +++ .../common/scripts/streaming/messaging-stream.ts | 19 +++++ .../scripts/streaming/requests-stream-manager.ts | 12 +++ .../common/scripts/streaming/requests-stream.ts | 10 +++ .../scripts/streaming/server-stream-manager.ts | 12 +++ .../app/common/scripts/streaming/server-stream.ts | 10 +++ .../app/common/scripts/streaming/stream-manager.ts | 73 +++++++++++++++++ src/web/app/common/scripts/streaming/stream.ts | 95 ++++++++++++++++++++++ 14 files changed, 355 insertions(+) create mode 100644 src/web/app/common/scripts/streaming/channel-stream.ts create mode 100644 src/web/app/common/scripts/streaming/drive-stream-manager.ts create mode 100644 src/web/app/common/scripts/streaming/drive-stream.ts create mode 100644 src/web/app/common/scripts/streaming/home-stream-manager.ts create mode 100644 src/web/app/common/scripts/streaming/home-stream.ts create mode 100644 src/web/app/common/scripts/streaming/messaging-index-stream-manager.ts create mode 100644 src/web/app/common/scripts/streaming/messaging-index-stream.ts create mode 100644 src/web/app/common/scripts/streaming/messaging-stream.ts create mode 100644 src/web/app/common/scripts/streaming/requests-stream-manager.ts create mode 100644 src/web/app/common/scripts/streaming/requests-stream.ts create mode 100644 src/web/app/common/scripts/streaming/server-stream-manager.ts create mode 100644 src/web/app/common/scripts/streaming/server-stream.ts create mode 100644 src/web/app/common/scripts/streaming/stream-manager.ts create mode 100644 src/web/app/common/scripts/streaming/stream.ts (limited to 'src/web/app/common/scripts/streaming') diff --git a/src/web/app/common/scripts/streaming/channel-stream.ts b/src/web/app/common/scripts/streaming/channel-stream.ts new file mode 100644 index 0000000000..434b108b9e --- /dev/null +++ b/src/web/app/common/scripts/streaming/channel-stream.ts @@ -0,0 +1,12 @@ +import Stream from './stream'; + +/** + * Channel stream connection + */ +export default class Connection extends Stream { + constructor(channelId) { + super('channel', { + channel: channelId + }); + } +} diff --git a/src/web/app/common/scripts/streaming/drive-stream-manager.ts b/src/web/app/common/scripts/streaming/drive-stream-manager.ts new file mode 100644 index 0000000000..8acdd7cbba --- /dev/null +++ b/src/web/app/common/scripts/streaming/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/streaming/drive-stream.ts b/src/web/app/common/scripts/streaming/drive-stream.ts new file mode 100644 index 0000000000..0da3f12554 --- /dev/null +++ b/src/web/app/common/scripts/streaming/drive-stream.ts @@ -0,0 +1,12 @@ +import Stream from './stream'; + +/** + * Drive stream connection + */ +export default class Connection extends Stream { + constructor(me) { + super('drive', { + i: me.token + }); + } +} diff --git a/src/web/app/common/scripts/streaming/home-stream-manager.ts b/src/web/app/common/scripts/streaming/home-stream-manager.ts new file mode 100644 index 0000000000..ad1dc870eb --- /dev/null +++ b/src/web/app/common/scripts/streaming/home-stream-manager.ts @@ -0,0 +1,20 @@ +import StreamManager from './stream-manager'; +import Connection from './home-stream'; + +export default class HomeStreamManager 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/streaming/home-stream.ts b/src/web/app/common/scripts/streaming/home-stream.ts new file mode 100644 index 0000000000..a78f4acdbe --- /dev/null +++ b/src/web/app/common/scripts/streaming/home-stream.ts @@ -0,0 +1,28 @@ +import Stream from './stream'; +import signout from '../signout'; + +/** + * Home stream connection + */ +export default class Connection extends Stream { + constructor(me) { + super('', { + i: me.token + }); + + // 最終利用日時を更新するため定期的にaliveメッセージを送信 + setInterval(() => { + this.send({ type: 'alive' }); + }, 1000 * 60); + + // 自分の情報が更新されたとき + (this as any).on('i_updated', me.update); + + // トークンが再生成されたとき + // このままではAPIが利用できないので強制的にサインアウトさせる + (this as any).on('my_token_regenerated', () => { + alert('%i18n:common.my-token-regenerated%'); + signout(); + }); + } +} diff --git a/src/web/app/common/scripts/streaming/messaging-index-stream-manager.ts b/src/web/app/common/scripts/streaming/messaging-index-stream-manager.ts new file mode 100644 index 0000000000..0f08b01481 --- /dev/null +++ b/src/web/app/common/scripts/streaming/messaging-index-stream-manager.ts @@ -0,0 +1,20 @@ +import StreamManager from './stream-manager'; +import Connection from './messaging-index-stream'; + +export default class MessagingIndexStreamManager 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/streaming/messaging-index-stream.ts b/src/web/app/common/scripts/streaming/messaging-index-stream.ts new file mode 100644 index 0000000000..8015c840b4 --- /dev/null +++ b/src/web/app/common/scripts/streaming/messaging-index-stream.ts @@ -0,0 +1,12 @@ +import Stream from './stream'; + +/** + * Messaging index stream connection + */ +export default class Connection extends Stream { + constructor(me) { + super('messaging-index', { + i: me.token + }); + } +} diff --git a/src/web/app/common/scripts/streaming/messaging-stream.ts b/src/web/app/common/scripts/streaming/messaging-stream.ts new file mode 100644 index 0000000000..68dfc5ec09 --- /dev/null +++ b/src/web/app/common/scripts/streaming/messaging-stream.ts @@ -0,0 +1,19 @@ +import Stream from './stream'; + +/** + * Messaging stream connection + */ +export default class Connection extends Stream { + constructor(me, otherparty) { + super('messaging', { + i: me.token, + otherparty + }); + + (this as any).on('_connected_', () => { + this.send({ + i: me.token + }); + }); + } +} diff --git a/src/web/app/common/scripts/streaming/requests-stream-manager.ts b/src/web/app/common/scripts/streaming/requests-stream-manager.ts new file mode 100644 index 0000000000..44db913e78 --- /dev/null +++ b/src/web/app/common/scripts/streaming/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/streaming/requests-stream.ts b/src/web/app/common/scripts/streaming/requests-stream.ts new file mode 100644 index 0000000000..22ecea6c07 --- /dev/null +++ b/src/web/app/common/scripts/streaming/requests-stream.ts @@ -0,0 +1,10 @@ +import Stream from './stream'; + +/** + * Requests stream connection + */ +export default class Connection extends Stream { + constructor() { + super('requests'); + } +} diff --git a/src/web/app/common/scripts/streaming/server-stream-manager.ts b/src/web/app/common/scripts/streaming/server-stream-manager.ts new file mode 100644 index 0000000000..a170daebb9 --- /dev/null +++ b/src/web/app/common/scripts/streaming/server-stream-manager.ts @@ -0,0 +1,12 @@ +import StreamManager from './stream-manager'; +import Connection from './server-stream'; + +export default class ServerStreamManager extends StreamManager { + public getConnection() { + if (this.connection == null) { + this.connection = new Connection(); + } + + return this.connection; + } +} diff --git a/src/web/app/common/scripts/streaming/server-stream.ts b/src/web/app/common/scripts/streaming/server-stream.ts new file mode 100644 index 0000000000..b9e0684465 --- /dev/null +++ b/src/web/app/common/scripts/streaming/server-stream.ts @@ -0,0 +1,10 @@ +import Stream from './stream'; + +/** + * Server stream connection + */ +export default class Connection extends Stream { + constructor() { + super('server'); + } +} diff --git a/src/web/app/common/scripts/streaming/stream-manager.ts b/src/web/app/common/scripts/streaming/stream-manager.ts new file mode 100644 index 0000000000..de27235426 --- /dev/null +++ b/src/web/app/common/scripts/streaming/stream-manager.ts @@ -0,0 +1,73 @@ +import { EventEmitter } from 'eventemitter3'; +import * as uuid from 'uuid'; +import Connection from './stream'; + +/** + * ストリーム接続を管理するクラス + * 複数の場所から同じストリームを利用する際、接続をまとめたりする + */ +export default abstract class StreamManager extends EventEmitter { + protected _connection: T = null; + + /** + * コネクションを必要としているユーザー + */ + private users = []; + + protected set connection(connection: T) { + this._connection = connection; + + if (this._connection == null) { + this.emit('disconnected'); + } else { + this.emit('connected', this._connection); + } + } + + protected get connection() { + return this._connection; + } + + /** + * コネクションを持っているか否か + */ + public get hasConnection() { + return this._connection != null; + } + + /** + * コネクションを要求します + */ + public abstract getConnection(): T; + + public borrow() { + return this._connection; + } + + /** + * コネクションを要求するためのユーザーIDを発行します + */ + public use() { + // ユーザーID生成 + const userId = uuid(); + + this.users.push(userId); + + return userId; + } + + /** + * コネクションを利用し終わってもう必要ないことを通知します + * @param userId use で発行したユーザーID + */ + 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/common/scripts/streaming/stream.ts b/src/web/app/common/scripts/streaming/stream.ts new file mode 100644 index 0000000000..97ebdcdd74 --- /dev/null +++ b/src/web/app/common/scripts/streaming/stream.ts @@ -0,0 +1,95 @@ +import { EventEmitter } from 'eventemitter3'; +import * as ReconnectingWebsocket from 'reconnecting-websocket'; +import CONFIG from '../config'; + +/** + * Misskey stream connection + */ +export default class Connection extends EventEmitter { + private state: string; + private buffer: any[]; + private socket: ReconnectingWebsocket; + + constructor(endpoint, params?) { + super(); + + //#region BIND + this.onOpen = this.onOpen.bind(this); + this.onClose = this.onClose.bind(this); + this.onMessage = this.onMessage.bind(this); + this.send = this.send.bind(this); + this.close = this.close.bind(this); + //#endregion + + this.state = 'initializing'; + this.buffer = []; + + const host = CONFIG.apiUrl.replace('http', 'ws'); + const query = params + ? Object.keys(params) + .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) + .join('&') + : null; + + this.socket = new ReconnectingWebsocket(`${host}/${endpoint}${query ? '?' + query : ''}`); + this.socket.addEventListener('open', this.onOpen); + this.socket.addEventListener('close', this.onClose); + this.socket.addEventListener('message', this.onMessage); + } + + /** + * Callback of when open connection + */ + private onOpen() { + this.state = 'connected'; + this.emit('_connected_'); + + // バッファーを処理 + const _buffer = [].concat(this.buffer); // Shallow copy + this.buffer = []; // Clear buffer + _buffer.forEach(message => { + this.send(message); // Resend each buffered messages + }); + } + + /** + * Callback of when close connection + */ + private onClose() { + this.state = 'reconnecting'; + this.emit('_closed_'); + } + + /** + * Callback of when received a message from connection + */ + private onMessage(message) { + try { + const msg = JSON.parse(message.data); + if (msg.type) this.emit(msg.type, msg.body); + } catch (e) { + // noop + } + } + + /** + * Send a message to connection + */ + public send(message) { + // まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する + if (this.state != 'connected') { + this.buffer.push(message); + return; + } + + this.socket.send(JSON.stringify(message)); + } + + /** + * Close this connection + */ + public close() { + this.socket.removeEventListener('open', this.onOpen); + this.socket.removeEventListener('message', this.onMessage); + } +} -- cgit v1.2.3-freya