✌️
This commit is contained in:
parent
f02fcd0e2a
commit
1439c3245b
22 changed files with 446 additions and 101 deletions
|
@ -1,9 +1,11 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import * as merge from 'object-assign-deep';
|
import * as merge from 'object-assign-deep';
|
||||||
|
import * as uuid from 'uuid';
|
||||||
|
|
||||||
import { host, apiUrl, swPublickey, version, lang, googleMapsApiKey } from '../config';
|
import { host, apiUrl, swPublickey, version, lang, googleMapsApiKey } from '../config';
|
||||||
import Progress from './scripts/loading';
|
import Progress from './scripts/loading';
|
||||||
|
import Connection from './scripts/streaming/stream';
|
||||||
import { HomeStreamManager } from './scripts/streaming/home';
|
import { HomeStreamManager } from './scripts/streaming/home';
|
||||||
import { DriveStreamManager } from './scripts/streaming/drive';
|
import { DriveStreamManager } from './scripts/streaming/drive';
|
||||||
import { ServerStreamManager } from './scripts/streaming/server';
|
import { ServerStreamManager } from './scripts/streaming/server';
|
||||||
|
@ -151,9 +153,6 @@ export default class MiOS extends EventEmitter {
|
||||||
|
|
||||||
this.shouldRegisterSw = shouldRegisterSw;
|
this.shouldRegisterSw = shouldRegisterSw;
|
||||||
|
|
||||||
this.streams.serverStream = new ServerStreamManager();
|
|
||||||
this.streams.requestsStream = new RequestsStreamManager();
|
|
||||||
|
|
||||||
//#region BIND
|
//#region BIND
|
||||||
this.log = this.log.bind(this);
|
this.log = this.log.bind(this);
|
||||||
this.logInfo = this.logInfo.bind(this);
|
this.logInfo = this.logInfo.bind(this);
|
||||||
|
@ -165,16 +164,6 @@ export default class MiOS extends EventEmitter {
|
||||||
this.registerSw = this.registerSw.bind(this);
|
this.registerSw = this.registerSw.bind(this);
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
this.once('signedin', () => {
|
|
||||||
// Init home stream manager
|
|
||||||
this.stream = new HomeStreamManager(this, this.i);
|
|
||||||
|
|
||||||
// Init other stream manager
|
|
||||||
this.streams.driveStream = new DriveStreamManager(this.i);
|
|
||||||
this.streams.messagingIndexStream = new MessagingIndexStreamManager(this.i);
|
|
||||||
this.streams.othelloStream = new OthelloStreamManager(this.i);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
(window as any).os = this;
|
(window as any).os = this;
|
||||||
}
|
}
|
||||||
|
@ -240,6 +229,21 @@ export default class MiOS extends EventEmitter {
|
||||||
* @param callback A function that call when initialized
|
* @param callback A function that call when initialized
|
||||||
*/
|
*/
|
||||||
public async init(callback) {
|
public async init(callback) {
|
||||||
|
//#region Init stream managers
|
||||||
|
this.streams.serverStream = new ServerStreamManager(this);
|
||||||
|
this.streams.requestsStream = new RequestsStreamManager(this);
|
||||||
|
|
||||||
|
this.once('signedin', () => {
|
||||||
|
// Init home stream manager
|
||||||
|
this.stream = new HomeStreamManager(this, this.i);
|
||||||
|
|
||||||
|
// Init other stream manager
|
||||||
|
this.streams.driveStream = new DriveStreamManager(this, this.i);
|
||||||
|
this.streams.messagingIndexStream = new MessagingIndexStreamManager(this, this.i);
|
||||||
|
this.streams.othelloStream = new OthelloStreamManager(this, this.i);
|
||||||
|
});
|
||||||
|
//#endregion
|
||||||
|
|
||||||
// ユーザーをフェッチしてコールバックする
|
// ユーザーをフェッチしてコールバックする
|
||||||
const fetchme = (token, cb) => {
|
const fetchme = (token, cb) => {
|
||||||
let me = null;
|
let me = null;
|
||||||
|
@ -414,6 +418,8 @@ export default class MiOS extends EventEmitter {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public requests = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Misskey APIにリクエストします
|
* Misskey APIにリクエストします
|
||||||
* @param endpoint エンドポイント名
|
* @param endpoint エンドポイント名
|
||||||
|
@ -446,22 +452,41 @@ export default class MiOS extends EventEmitter {
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
} else {*/
|
} else {*/
|
||||||
|
const req = {
|
||||||
|
id: uuid(),
|
||||||
|
date: new Date(),
|
||||||
|
name: endpoint,
|
||||||
|
data,
|
||||||
|
res: null,
|
||||||
|
status: null
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.debug) {
|
||||||
|
this.requests.push(req);
|
||||||
|
}
|
||||||
|
|
||||||
// Send request
|
// Send request
|
||||||
fetch(endpoint.indexOf('://') > -1 ? endpoint : `${apiUrl}/${endpoint}`, {
|
fetch(endpoint.indexOf('://') > -1 ? endpoint : `${apiUrl}/${endpoint}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
credentials: endpoint === 'signin' ? 'include' : 'omit',
|
credentials: endpoint === 'signin' ? 'include' : 'omit',
|
||||||
cache: 'no-cache'
|
cache: 'no-cache'
|
||||||
}).then(res => {
|
}).then(async (res) => {
|
||||||
if (--pending === 0) spinner.parentNode.removeChild(spinner);
|
if (--pending === 0) spinner.parentNode.removeChild(spinner);
|
||||||
|
|
||||||
|
const body = await res.json();
|
||||||
|
|
||||||
|
if (this.debug) {
|
||||||
|
req.status = res.status;
|
||||||
|
req.res = body;
|
||||||
|
}
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
res.json().then(resolve);
|
resolve(body);
|
||||||
} else if (res.status === 204) {
|
} else if (res.status === 204) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
res.json().then(err => {
|
reject(body.error);
|
||||||
reject(err.error);
|
|
||||||
}, reject);
|
|
||||||
}
|
}
|
||||||
}).catch(reject);
|
}).catch(reject);
|
||||||
/*}*/
|
/*}*/
|
||||||
|
@ -499,17 +524,29 @@ export default class MiOS extends EventEmitter {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public connections: Connection[] = [];
|
||||||
|
|
||||||
|
public registerStreamConnection(connection: Connection) {
|
||||||
|
this.connections.push(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unregisterStreamConnection(connection: Connection) {
|
||||||
|
this.connections = this.connections.filter(c => c != connection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WindowSystem {
|
class WindowSystem extends EventEmitter {
|
||||||
private windows = new Set();
|
public windows = new Set();
|
||||||
|
|
||||||
public add(window) {
|
public add(window) {
|
||||||
this.windows.add(window);
|
this.windows.add(window);
|
||||||
|
this.emit('added', window);
|
||||||
}
|
}
|
||||||
|
|
||||||
public remove(window) {
|
public remove(window) {
|
||||||
this.windows.delete(window);
|
this.windows.delete(window);
|
||||||
|
this.emit('removed', window);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAll() {
|
public getAll() {
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import Stream from './stream';
|
import Stream from './stream';
|
||||||
|
import MiOS from '../../mios';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Channel stream connection
|
* Channel stream connection
|
||||||
*/
|
*/
|
||||||
export default class Connection extends Stream {
|
export default class Connection extends Stream {
|
||||||
constructor(channelId) {
|
constructor(os: MiOS, channelId) {
|
||||||
super('channel', {
|
super(os, 'channel', {
|
||||||
channel: channelId
|
channel: channelId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import Stream from './stream';
|
import Stream from './stream';
|
||||||
import StreamManager from './stream-manager';
|
import StreamManager from './stream-manager';
|
||||||
|
import MiOS from '../../mios';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Drive stream connection
|
* Drive stream connection
|
||||||
*/
|
*/
|
||||||
export class DriveStream extends Stream {
|
export class DriveStream extends Stream {
|
||||||
constructor(me) {
|
constructor(os: MiOS, me) {
|
||||||
super('drive', {
|
super(os, 'drive', {
|
||||||
i: me.token
|
i: me.token
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -14,16 +15,18 @@ export class DriveStream extends Stream {
|
||||||
|
|
||||||
export class DriveStreamManager extends StreamManager<DriveStream> {
|
export class DriveStreamManager extends StreamManager<DriveStream> {
|
||||||
private me;
|
private me;
|
||||||
|
private os: MiOS;
|
||||||
|
|
||||||
constructor(me) {
|
constructor(os: MiOS, me) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.me = me;
|
this.me = me;
|
||||||
|
this.os = os;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getConnection() {
|
public getConnection() {
|
||||||
if (this.connection == null) {
|
if (this.connection == null) {
|
||||||
this.connection = new DriveStream(this.me);
|
this.connection = new DriveStream(this.os, this.me);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.connection;
|
return this.connection;
|
||||||
|
|
|
@ -9,7 +9,7 @@ import MiOS from '../../mios';
|
||||||
*/
|
*/
|
||||||
export class HomeStream extends Stream {
|
export class HomeStream extends Stream {
|
||||||
constructor(os: MiOS, me) {
|
constructor(os: MiOS, me) {
|
||||||
super('', {
|
super(os, '', {
|
||||||
i: me.token
|
i: me.token
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import Stream from './stream';
|
import Stream from './stream';
|
||||||
import StreamManager from './stream-manager';
|
import StreamManager from './stream-manager';
|
||||||
|
import MiOS from '../../mios';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Messaging index stream connection
|
* Messaging index stream connection
|
||||||
*/
|
*/
|
||||||
export class MessagingIndexStream extends Stream {
|
export class MessagingIndexStream extends Stream {
|
||||||
constructor(me) {
|
constructor(os: MiOS, me) {
|
||||||
super('messaging-index', {
|
super(os, 'messaging-index', {
|
||||||
i: me.token
|
i: me.token
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -14,16 +15,18 @@ export class MessagingIndexStream extends Stream {
|
||||||
|
|
||||||
export class MessagingIndexStreamManager extends StreamManager<MessagingIndexStream> {
|
export class MessagingIndexStreamManager extends StreamManager<MessagingIndexStream> {
|
||||||
private me;
|
private me;
|
||||||
|
private os: MiOS;
|
||||||
|
|
||||||
constructor(me) {
|
constructor(os: MiOS, me) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.me = me;
|
this.me = me;
|
||||||
|
this.os = os;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getConnection() {
|
public getConnection() {
|
||||||
if (this.connection == null) {
|
if (this.connection == null) {
|
||||||
this.connection = new MessagingIndexStream(this.me);
|
this.connection = new MessagingIndexStream(this.os, this.me);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.connection;
|
return this.connection;
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import Stream from './stream';
|
import Stream from './stream';
|
||||||
|
import MiOS from '../../mios';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Messaging stream connection
|
* Messaging stream connection
|
||||||
*/
|
*/
|
||||||
export class MessagingStream extends Stream {
|
export class MessagingStream extends Stream {
|
||||||
constructor(me, otherparty) {
|
constructor(os: MiOS, me, otherparty) {
|
||||||
super('messaging', {
|
super(os, 'messaging', {
|
||||||
i: me.token,
|
i: me.token,
|
||||||
otherparty
|
otherparty
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import Stream from './stream';
|
import Stream from './stream';
|
||||||
|
import MiOS from '../../mios';
|
||||||
|
|
||||||
export class OthelloGameStream extends Stream {
|
export class OthelloGameStream extends Stream {
|
||||||
constructor(me, game) {
|
constructor(os: MiOS, me, game) {
|
||||||
super('othello-game', {
|
super(os, 'othello-game', {
|
||||||
i: me ? me.token : null,
|
i: me ? me.token : null,
|
||||||
game: game.id
|
game: game.id
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import StreamManager from './stream-manager';
|
import StreamManager from './stream-manager';
|
||||||
import Stream from './stream';
|
import Stream from './stream';
|
||||||
|
import MiOS from '../../mios';
|
||||||
|
|
||||||
export class OthelloStream extends Stream {
|
export class OthelloStream extends Stream {
|
||||||
constructor(me) {
|
constructor(os: MiOS, me) {
|
||||||
super('othello', {
|
super(os, 'othello', {
|
||||||
i: me.token
|
i: me.token
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -11,16 +12,18 @@ export class OthelloStream extends Stream {
|
||||||
|
|
||||||
export class OthelloStreamManager extends StreamManager<OthelloStream> {
|
export class OthelloStreamManager extends StreamManager<OthelloStream> {
|
||||||
private me;
|
private me;
|
||||||
|
private os: MiOS;
|
||||||
|
|
||||||
constructor(me) {
|
constructor(os: MiOS, me) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.me = me;
|
this.me = me;
|
||||||
|
this.os = os;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getConnection() {
|
public getConnection() {
|
||||||
if (this.connection == null) {
|
if (this.connection == null) {
|
||||||
this.connection = new OthelloStream(this.me);
|
this.connection = new OthelloStream(this.os, this.me);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.connection;
|
return this.connection;
|
||||||
|
|
|
@ -1,19 +1,28 @@
|
||||||
import Stream from './stream';
|
import Stream from './stream';
|
||||||
import StreamManager from './stream-manager';
|
import StreamManager from './stream-manager';
|
||||||
|
import MiOS from '../../mios';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests stream connection
|
* Requests stream connection
|
||||||
*/
|
*/
|
||||||
export class RequestsStream extends Stream {
|
export class RequestsStream extends Stream {
|
||||||
constructor() {
|
constructor(os: MiOS) {
|
||||||
super('requests');
|
super(os, 'requests');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RequestsStreamManager extends StreamManager<RequestsStream> {
|
export class RequestsStreamManager extends StreamManager<RequestsStream> {
|
||||||
|
private os: MiOS;
|
||||||
|
|
||||||
|
constructor(os: MiOS) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.os = os;
|
||||||
|
}
|
||||||
|
|
||||||
public getConnection() {
|
public getConnection() {
|
||||||
if (this.connection == null) {
|
if (this.connection == null) {
|
||||||
this.connection = new RequestsStream();
|
this.connection = new RequestsStream(this.os);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.connection;
|
return this.connection;
|
||||||
|
|
|
@ -1,19 +1,28 @@
|
||||||
import Stream from './stream';
|
import Stream from './stream';
|
||||||
import StreamManager from './stream-manager';
|
import StreamManager from './stream-manager';
|
||||||
|
import MiOS from '../../mios';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Server stream connection
|
* Server stream connection
|
||||||
*/
|
*/
|
||||||
export class ServerStream extends Stream {
|
export class ServerStream extends Stream {
|
||||||
constructor() {
|
constructor(os: MiOS) {
|
||||||
super('server');
|
super(os, 'server');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ServerStreamManager extends StreamManager<ServerStream> {
|
export class ServerStreamManager extends StreamManager<ServerStream> {
|
||||||
|
private os: MiOS;
|
||||||
|
|
||||||
|
constructor(os: MiOS) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.os = os;
|
||||||
|
}
|
||||||
|
|
||||||
public getConnection() {
|
public getConnection() {
|
||||||
if (this.connection == null) {
|
if (this.connection == null) {
|
||||||
this.connection = new ServerStream();
|
this.connection = new ServerStream(this.os);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.connection;
|
return this.connection;
|
||||||
|
|
|
@ -31,6 +31,8 @@ export default abstract class StreamManager<T extends Connection> extends EventE
|
||||||
this._connection.on('_disconnected_', () => {
|
this._connection.on('_disconnected_', () => {
|
||||||
this.emit('_disconnected_');
|
this.emit('_disconnected_');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this._connection.user = 'Managed';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +79,8 @@ export default abstract class StreamManager<T extends Connection> extends EventE
|
||||||
|
|
||||||
this.users.push(userId);
|
this.users.push(userId);
|
||||||
|
|
||||||
|
this._connection.user = `Managed (${ this.users.length })`;
|
||||||
|
|
||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +91,8 @@ export default abstract class StreamManager<T extends Connection> extends EventE
|
||||||
public dispose(userId) {
|
public dispose(userId) {
|
||||||
this.users = this.users.filter(id => id != userId);
|
this.users = this.users.filter(id => id != userId);
|
||||||
|
|
||||||
|
this._connection.user = `Managed (${ this.users.length })`;
|
||||||
|
|
||||||
// 誰もコネクションの利用者がいなくなったら
|
// 誰もコネクションの利用者がいなくなったら
|
||||||
if (this.users.length == 0) {
|
if (this.users.length == 0) {
|
||||||
// また直ぐに再利用される可能性があるので、一定時間待ち、
|
// また直ぐに再利用される可能性があるので、一定時間待ち、
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
|
import * as uuid from 'uuid';
|
||||||
import * as ReconnectingWebsocket from 'reconnecting-websocket';
|
import * as ReconnectingWebsocket from 'reconnecting-websocket';
|
||||||
import { apiUrl } from '../../../config';
|
import { apiUrl } from '../../../config';
|
||||||
|
import MiOS from '../../mios';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Misskey stream connection
|
* Misskey stream connection
|
||||||
|
@ -8,9 +10,21 @@ import { apiUrl } from '../../../config';
|
||||||
export default class Connection extends EventEmitter {
|
export default class Connection extends EventEmitter {
|
||||||
public state: string;
|
public state: string;
|
||||||
private buffer: any[];
|
private buffer: any[];
|
||||||
private socket: ReconnectingWebsocket;
|
public socket: ReconnectingWebsocket;
|
||||||
|
public name: string;
|
||||||
|
public connectedAt: Date;
|
||||||
|
public user: string = null;
|
||||||
|
public in: number = 0;
|
||||||
|
public out: number = 0;
|
||||||
|
public inout: Array<{
|
||||||
|
type: 'in' | 'out',
|
||||||
|
at: Date,
|
||||||
|
data: string
|
||||||
|
}> = [];
|
||||||
|
public id: string;
|
||||||
|
private os: MiOS;
|
||||||
|
|
||||||
constructor(endpoint, params?) {
|
constructor(os: MiOS, endpoint, params?) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
//#region BIND
|
//#region BIND
|
||||||
|
@ -21,6 +35,9 @@ export default class Connection extends EventEmitter {
|
||||||
this.close = this.close.bind(this);
|
this.close = this.close.bind(this);
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
this.id = uuid();
|
||||||
|
this.os = os;
|
||||||
|
this.name = endpoint;
|
||||||
this.state = 'initializing';
|
this.state = 'initializing';
|
||||||
this.buffer = [];
|
this.buffer = [];
|
||||||
|
|
||||||
|
@ -35,6 +52,9 @@ export default class Connection extends EventEmitter {
|
||||||
this.socket.addEventListener('open', this.onOpen);
|
this.socket.addEventListener('open', this.onOpen);
|
||||||
this.socket.addEventListener('close', this.onClose);
|
this.socket.addEventListener('close', this.onClose);
|
||||||
this.socket.addEventListener('message', this.onMessage);
|
this.socket.addEventListener('message', this.onMessage);
|
||||||
|
|
||||||
|
// Register this connection for debugging
|
||||||
|
this.os.registerStreamConnection(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,11 +64,18 @@ export default class Connection extends EventEmitter {
|
||||||
this.state = 'connected';
|
this.state = 'connected';
|
||||||
this.emit('_connected_');
|
this.emit('_connected_');
|
||||||
|
|
||||||
|
this.connectedAt = new Date();
|
||||||
|
|
||||||
// バッファーを処理
|
// バッファーを処理
|
||||||
const _buffer = [].concat(this.buffer); // Shallow copy
|
const _buffer = [].concat(this.buffer); // Shallow copy
|
||||||
this.buffer = []; // Clear buffer
|
this.buffer = []; // Clear buffer
|
||||||
_buffer.forEach(message => {
|
_buffer.forEach(data => {
|
||||||
this.send(message); // Resend each buffered messages
|
this.send(data); // Resend each buffered messages
|
||||||
|
|
||||||
|
if (this.os.debug) {
|
||||||
|
this.out++;
|
||||||
|
this.inout.push({ type: 'out', at: new Date(), data });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +91,11 @@ export default class Connection extends EventEmitter {
|
||||||
* Callback of when received a message from connection
|
* Callback of when received a message from connection
|
||||||
*/
|
*/
|
||||||
private onMessage(message) {
|
private onMessage(message) {
|
||||||
|
if (this.os.debug) {
|
||||||
|
this.in++;
|
||||||
|
this.inout.push({ type: 'in', at: new Date(), data: message.data });
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const msg = JSON.parse(message.data);
|
const msg = JSON.parse(message.data);
|
||||||
if (msg.type) this.emit(msg.type, msg.body);
|
if (msg.type) this.emit(msg.type, msg.body);
|
||||||
|
@ -75,20 +107,26 @@ export default class Connection extends EventEmitter {
|
||||||
/**
|
/**
|
||||||
* Send a message to connection
|
* Send a message to connection
|
||||||
*/
|
*/
|
||||||
public send(message) {
|
public send(data) {
|
||||||
// まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する
|
// まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する
|
||||||
if (this.state != 'connected') {
|
if (this.state != 'connected') {
|
||||||
this.buffer.push(message);
|
this.buffer.push(data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.socket.send(JSON.stringify(message));
|
if (this.os.debug) {
|
||||||
|
this.out++;
|
||||||
|
this.inout.push({ type: 'out', at: new Date(), data });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.socket.send(JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close this connection
|
* Close this connection
|
||||||
*/
|
*/
|
||||||
public close() {
|
public close() {
|
||||||
|
this.os.unregisterStreamConnection(this);
|
||||||
this.socket.removeEventListener('open', this.onOpen);
|
this.socket.removeEventListener('open', this.onOpen);
|
||||||
this.socket.removeEventListener('message', this.onMessage);
|
this.socket.removeEventListener('message', this.onMessage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import pollEditor from './poll-editor.vue';
|
||||||
import reactionIcon from './reaction-icon.vue';
|
import reactionIcon from './reaction-icon.vue';
|
||||||
import reactionsViewer from './reactions-viewer.vue';
|
import reactionsViewer from './reactions-viewer.vue';
|
||||||
import time from './time.vue';
|
import time from './time.vue';
|
||||||
|
import timer from './timer.vue';
|
||||||
import images from './images.vue';
|
import images from './images.vue';
|
||||||
import uploader from './uploader.vue';
|
import uploader from './uploader.vue';
|
||||||
import specialMessage from './special-message.vue';
|
import specialMessage from './special-message.vue';
|
||||||
|
@ -33,6 +34,7 @@ Vue.component('mk-poll-editor', pollEditor);
|
||||||
Vue.component('mk-reaction-icon', reactionIcon);
|
Vue.component('mk-reaction-icon', reactionIcon);
|
||||||
Vue.component('mk-reactions-viewer', reactionsViewer);
|
Vue.component('mk-reactions-viewer', reactionsViewer);
|
||||||
Vue.component('mk-time', time);
|
Vue.component('mk-time', time);
|
||||||
|
Vue.component('mk-timer', timer);
|
||||||
Vue.component('mk-images', images);
|
Vue.component('mk-images', images);
|
||||||
Vue.component('mk-uploader', uploader);
|
Vue.component('mk-uploader', uploader);
|
||||||
Vue.component('mk-special-message', specialMessage);
|
Vue.component('mk-special-message', specialMessage);
|
||||||
|
|
|
@ -66,7 +66,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.connection = new MessagingStream((this as any).os.i, this.user.id);
|
this.connection = new MessagingStream((this as any).os, (this as any).os.i, this.user.id);
|
||||||
|
|
||||||
this.connection.on('message', this.onMessage);
|
this.connection.on('message', this.onMessage);
|
||||||
this.connection.on('read', this.onRead);
|
this.connection.on('read', this.onRead);
|
||||||
|
|
|
@ -25,7 +25,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.g = this.game;
|
this.g = this.game;
|
||||||
this.connection = new OthelloGameStream((this as any).os.i, this.game);
|
this.connection = new OthelloGameStream((this as any).os, (this as any).os.i, this.game);
|
||||||
this.connection.on('started', this.onStarted);
|
this.connection.on('started', this.onStarted);
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
|
|
|
@ -135,44 +135,6 @@ export default Vue.extend({
|
||||||
|
|
||||||
if (this.game.user1_id != (this as any).os.i.id && this.game.settings.form1) this.form = this.game.settings.form1;
|
if (this.game.user1_id != (this as any).os.i.id && this.game.settings.form1) this.form = this.game.settings.form1;
|
||||||
if (this.game.user2_id != (this as any).os.i.id && this.game.settings.form2) this.form = this.game.settings.form2;
|
if (this.game.user2_id != (this as any).os.i.id && this.game.settings.form2) this.form = this.game.settings.form2;
|
||||||
|
|
||||||
// for debugging
|
|
||||||
if ((this as any).os.i.username == 'test1') {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.connection.send({
|
|
||||||
type: 'init-form',
|
|
||||||
body: [{
|
|
||||||
id: 'button1',
|
|
||||||
type: 'button',
|
|
||||||
label: 'Enable hoge',
|
|
||||||
value: false
|
|
||||||
}, {
|
|
||||||
id: 'radio1',
|
|
||||||
type: 'radio',
|
|
||||||
label: '強さ',
|
|
||||||
value: 2,
|
|
||||||
items: [{
|
|
||||||
label: '弱',
|
|
||||||
value: 1
|
|
||||||
}, {
|
|
||||||
label: '中',
|
|
||||||
value: 2
|
|
||||||
}, {
|
|
||||||
label: '強',
|
|
||||||
value: 3
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
|
|
||||||
this.connection.send({
|
|
||||||
type: 'message',
|
|
||||||
body: {
|
|
||||||
text: 'Hey',
|
|
||||||
type: 'info'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
|
|
49
src/web/app/common/views/components/timer.vue
Normal file
49
src/web/app/common/views/components/timer.vue
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<template>
|
||||||
|
<time class="mk-time">
|
||||||
|
{{ hh }}:{{ mm }}:{{ ss }}
|
||||||
|
</time>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
props: {
|
||||||
|
time: {
|
||||||
|
type: [Date, String],
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tickId: null,
|
||||||
|
hh: null,
|
||||||
|
mm: null,
|
||||||
|
ss: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
_time(): Date {
|
||||||
|
return typeof this.time == 'string' ? new Date(this.time) : this.time;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.tick();
|
||||||
|
this.tickId = setInterval(this.tick, 1000);
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
clearInterval(this.tickId);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
tick() {
|
||||||
|
const now = new Date().getTime();
|
||||||
|
const start = this._time.getTime();
|
||||||
|
const ago = Math.floor((now - start) / 1000);
|
||||||
|
|
||||||
|
this.hh = Math.floor(ago / (60 * 60)).toString().padStart(2, '0');
|
||||||
|
this.mm = Math.floor(ago / 60).toString().padStart(2, '0');
|
||||||
|
this.ss = (ago % 60).toString().padStart(2, '0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -173,6 +173,10 @@
|
||||||
<mk-switch v-model="enableExperimental" text="実験的機能を有効にする">
|
<mk-switch v-model="enableExperimental" text="実験的機能を有効にする">
|
||||||
<span>実験的機能を有効にするとMisskeyの動作が不安定になる可能性があります。この設定はブラウザに記憶されます。</span>
|
<span>実験的機能を有効にするとMisskeyの動作が不安定になる可能性があります。この設定はブラウザに記憶されます。</span>
|
||||||
</mk-switch>
|
</mk-switch>
|
||||||
|
<details v-if="debug">
|
||||||
|
<summary>ツール</summary>
|
||||||
|
<button class="ui button block" @click="taskmngr">タスクマネージャ</button>
|
||||||
|
</details>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="other" v-show="page == 'other'">
|
<section class="other" v-show="page == 'other'">
|
||||||
|
@ -196,6 +200,7 @@ import XSignins from './settings.signins.vue';
|
||||||
import XDrive from './settings.drive.vue';
|
import XDrive from './settings.drive.vue';
|
||||||
import { url, docsUrl, license, lang, version } from '../../../config';
|
import { url, docsUrl, license, lang, version } from '../../../config';
|
||||||
import checkForUpdate from '../../../common/scripts/check-for-update';
|
import checkForUpdate from '../../../common/scripts/check-for-update';
|
||||||
|
import MkTaskManager from './taskmanager.vue';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
|
@ -226,6 +231,11 @@ export default Vue.extend({
|
||||||
enableExperimental: localStorage.getItem('enableExperimental') == 'true'
|
enableExperimental: localStorage.getItem('enableExperimental') == 'true'
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
licenseUrl(): string {
|
||||||
|
return `${docsUrl}/${lang}/license`;
|
||||||
|
}
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
autoPopout() {
|
autoPopout() {
|
||||||
localStorage.setItem('autoPopout', this.autoPopout ? 'true' : 'false');
|
localStorage.setItem('autoPopout', this.autoPopout ? 'true' : 'false');
|
||||||
|
@ -252,17 +262,15 @@ export default Vue.extend({
|
||||||
localStorage.setItem('enableExperimental', this.enableExperimental ? 'true' : 'false');
|
localStorage.setItem('enableExperimental', this.enableExperimental ? 'true' : 'false');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
licenseUrl(): string {
|
|
||||||
return `${docsUrl}/${lang}/license`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
created() {
|
||||||
(this as any).os.getMeta().then(meta => {
|
(this as any).os.getMeta().then(meta => {
|
||||||
this.meta = meta;
|
this.meta = meta;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
taskmngr() {
|
||||||
|
(this as any).os.new(MkTaskManager);
|
||||||
|
},
|
||||||
customizeHome() {
|
customizeHome() {
|
||||||
this.$router.push('/i/customize-home');
|
this.$router.push('/i/customize-home');
|
||||||
this.$emit('done');
|
this.$emit('done');
|
||||||
|
|
204
src/web/app/desktop/views/components/taskmanager.vue
Normal file
204
src/web/app/desktop/views/components/taskmanager.vue
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
<template>
|
||||||
|
<mk-window ref="window" width="750px" height="500px" @closed="$destroy" name="TaskManager">
|
||||||
|
<span slot="header" :class="$style.header">%fa:stethoscope%タスクマネージャ</span>
|
||||||
|
<el-tabs :class="$style.content">
|
||||||
|
<el-tab-pane label="Requests">
|
||||||
|
<el-table
|
||||||
|
:data="os.requests"
|
||||||
|
style="width: 100%"
|
||||||
|
:default-sort="{prop: 'date', order: 'descending'}"
|
||||||
|
>
|
||||||
|
<el-table-column type="expand">
|
||||||
|
<template slot-scope="props">
|
||||||
|
<pre>{{ props.row.data }}</pre>
|
||||||
|
<pre>{{ props.row.res }}</pre>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column
|
||||||
|
label="Requested at"
|
||||||
|
prop="date"
|
||||||
|
sortable
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<b style="margin-right: 8px">{{ scope.row.date.getTime() }}</b>
|
||||||
|
<span>(<mk-time :time="scope.row.date"/>)</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column
|
||||||
|
label="Name"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<b>{{ scope.row.name }}</b>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column
|
||||||
|
label="Status"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ scope.row.status || '(pending)' }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<el-tab-pane label="Streams">
|
||||||
|
<el-table
|
||||||
|
:data="os.connections"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<el-table-column
|
||||||
|
label="Uptime"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<mk-timer v-if="scope.row.connectedAt" :time="scope.row.connectedAt"/>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column
|
||||||
|
label="Name"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<b>{{ scope.row.name == '' ? '[Home]' : scope.row.name }}</b>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column
|
||||||
|
label="User"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ scope.row.user || '(anonymous)' }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column
|
||||||
|
prop="state"
|
||||||
|
label="State"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<el-table-column
|
||||||
|
prop="in"
|
||||||
|
label="In"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<el-table-column
|
||||||
|
prop="out"
|
||||||
|
label="Out"
|
||||||
|
/>
|
||||||
|
</el-table>
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<el-tab-pane label="Streams (Inspect)">
|
||||||
|
<el-tabs type="card" style="height:50%">
|
||||||
|
<el-tab-pane v-for="c in os.connections" :label="c.name == '' ? '[Home]' : c.name" :key="c.id" :name="c.id" ref="connectionsTab">
|
||||||
|
<el-table
|
||||||
|
:data="c.inout"
|
||||||
|
style="width: 100%"
|
||||||
|
:default-sort="{prop: 'at', order: 'descending'}"
|
||||||
|
>
|
||||||
|
<el-table-column type="expand">
|
||||||
|
<template slot-scope="props">
|
||||||
|
<pre>{{ props.row.data }}</pre>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column
|
||||||
|
label="Date"
|
||||||
|
prop="at"
|
||||||
|
sortable
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<b style="margin-right: 8px">{{ scope.row.at.getTime() }}</b>
|
||||||
|
<span>(<mk-time :time="scope.row.at"/>)</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column
|
||||||
|
label="Type"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ getMessageType(scope.row.data) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column
|
||||||
|
label="Incoming / Outgoing"
|
||||||
|
prop="type"
|
||||||
|
/>
|
||||||
|
</el-table>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<el-tab-pane label="Windows">
|
||||||
|
<el-table
|
||||||
|
:data="Array.from(os.windows.windows)"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<el-table-column
|
||||||
|
label="Name"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<b>{{ scope.row.name || '(unknown)' }}</b>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column
|
||||||
|
label="Operations"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="danger" @click="scope.row.close">Close</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</mk-window>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
mounted() {
|
||||||
|
(this as any).os.windows.on('added', this.onWindowsChanged);
|
||||||
|
(this as any).os.windows.on('removed', this.onWindowsChanged);
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
(this as any).os.windows.off('added', this.onWindowsChanged);
|
||||||
|
(this as any).os.windows.off('removed', this.onWindowsChanged);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getMessageType(data): string {
|
||||||
|
return data.type ? data.type : '-';
|
||||||
|
},
|
||||||
|
onWindowsChanged() {
|
||||||
|
this.$forceUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" module>
|
||||||
|
.header
|
||||||
|
> [data-fa]
|
||||||
|
margin-right 4px
|
||||||
|
|
||||||
|
.content
|
||||||
|
height 100%
|
||||||
|
overflow auto
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.el-tabs__header {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__item {
|
||||||
|
padding: 0 20px !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -68,7 +68,12 @@ export default Vue.extend({
|
||||||
default: 'auto'
|
default: 'auto'
|
||||||
},
|
},
|
||||||
popoutUrl: {
|
popoutUrl: {
|
||||||
type: [String, Function]
|
type: [String, Function],
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ export default Vue.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
this.disconnect();
|
this.disconnect();
|
||||||
this.connection = new ChannelStream(this.channel.id);
|
this.connection = new ChannelStream((this as any).os, this.channel.id);
|
||||||
this.connection.on('post', this.onPost);
|
this.connection.on('post', this.onPost);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -243,8 +243,12 @@ module.exports = entries.map(x => {
|
||||||
cache: true,
|
cache: true,
|
||||||
devtool: 'source-map',
|
devtool: 'source-map',
|
||||||
optimization: {
|
optimization: {
|
||||||
minimize: doMinify
|
minimize: isProduction && doMinify
|
||||||
},
|
},
|
||||||
mode: doMinify ? 'production' : 'development'
|
mode: isProduction
|
||||||
|
? doMinify
|
||||||
|
? 'production'
|
||||||
|
: 'development'
|
||||||
|
: 'development'
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue