#925, #926, and refactoring

This commit is contained in:
syuilo 2017-11-17 01:24:44 +09:00
parent 4129dce95a
commit c614e6f5d7
38 changed files with 358 additions and 216 deletions

View file

@ -0,0 +1,12 @@
import Stream from './stream';
/**
* Channel stream connection
*/
export default class Connection extends Stream {
constructor(channelId) {
super('channel', {
channel: channelId
});
}
}

View file

@ -0,0 +1,20 @@
import StreamManager from './stream-manager';
import Connection from './drive-stream';
export default class DriveStreamManager extends StreamManager<Connection> {
private me;
constructor(me) {
super();
this.me = me;
}
public getConnection() {
if (this.connection == null) {
this.connection = new Connection(this.me);
}
return this.connection;
}
}

View file

@ -0,0 +1,12 @@
import Stream from './stream';
/**
* Drive stream connection
*/
export default class Connection extends Stream {
constructor(me) {
super('drive', {
i: me.token
});
}
}

View file

@ -0,0 +1,20 @@
import StreamManager from './stream-manager';
import Connection from './home-stream';
export default class HomeStreamManager extends StreamManager<Connection> {
private me;
constructor(me) {
super();
this.me = me;
}
public getConnection() {
if (this.connection == null) {
this.connection = new Connection(this.me);
}
return this.connection;
}
}

View file

@ -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();
});
}
}

View file

@ -0,0 +1,20 @@
import StreamManager from './stream-manager';
import Connection from './messaging-index-stream';
export default class MessagingIndexStreamManager extends StreamManager<Connection> {
private me;
constructor(me) {
super();
this.me = me;
}
public getConnection() {
if (this.connection == null) {
this.connection = new Connection(this.me);
}
return this.connection;
}
}

View file

@ -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
});
}
}

View file

@ -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
});
});
}
}

View file

@ -0,0 +1,12 @@
import StreamManager from './stream-manager';
import Connection from './requests-stream';
export default class RequestsStreamManager extends StreamManager<Connection> {
public getConnection() {
if (this.connection == null) {
this.connection = new Connection();
}
return this.connection;
}
}

View file

@ -0,0 +1,10 @@
import Stream from './stream';
/**
* Requests stream connection
*/
export default class Connection extends Stream {
constructor() {
super('requests');
}
}

View file

@ -0,0 +1,12 @@
import StreamManager from './stream-manager';
import Connection from './server-stream';
export default class ServerStreamManager extends StreamManager<Connection> {
public getConnection() {
if (this.connection == null) {
this.connection = new Connection();
}
return this.connection;
}
}

View file

@ -0,0 +1,10 @@
import Stream from './stream';
/**
* Server stream connection
*/
export default class Connection extends Stream {
constructor() {
super('server');
}
}

View file

@ -0,0 +1,73 @@
import { EventEmitter } from 'eventemitter3';
import * as uuid from 'uuid';
import Connection from './stream';
/**
*
*
*/
export default abstract class StreamManager<T extends Connection> 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;
}
}
}

View file

@ -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);
}
}