2020-06-25 16:05:36 -07:00
|
|
|
/**
|
|
|
|
* Copyright (c) Microsoft Corporation.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
import { EventEmitter } from 'events';
|
|
|
|
import { helper } from '../helper';
|
|
|
|
import { Channel } from './channels';
|
2020-06-27 11:10:07 -07:00
|
|
|
import { serializeError } from './serializers';
|
2020-06-25 16:05:36 -07:00
|
|
|
|
2020-06-26 17:24:21 -07:00
|
|
|
export class Dispatcher<Type, Initializer> extends EventEmitter implements Channel {
|
2020-06-25 16:05:36 -07:00
|
|
|
readonly _guid: string;
|
|
|
|
readonly _type: string;
|
|
|
|
protected _scope: DispatcherScope;
|
|
|
|
_object: any;
|
|
|
|
|
2020-06-26 17:24:21 -07:00
|
|
|
constructor(scope: DispatcherScope, object: Type, type: string, initializer: Initializer, guid = type + '@' + helper.guid()) {
|
2020-06-25 16:05:36 -07:00
|
|
|
super();
|
|
|
|
this._type = type;
|
|
|
|
this._guid = guid;
|
|
|
|
this._object = object;
|
|
|
|
this._scope = scope;
|
|
|
|
scope.dispatchers.set(this._guid, this);
|
2020-06-26 17:24:21 -07:00
|
|
|
(object as any)[scope.dispatcherSymbol] = this;
|
2020-06-26 12:28:27 -07:00
|
|
|
this._scope.sendMessageToClient(this._guid, '__create__', { type, initializer });
|
2020-06-25 16:05:36 -07:00
|
|
|
}
|
|
|
|
|
2020-06-26 17:24:21 -07:00
|
|
|
_dispatchEvent(method: string, params: Dispatcher<any, any> | any = {}) {
|
2020-06-25 16:05:36 -07:00
|
|
|
this._scope.sendMessageToClient(this._guid, method, params);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export class DispatcherScope {
|
2020-06-26 17:24:21 -07:00
|
|
|
readonly dispatchers = new Map<string, Dispatcher<any, any>>();
|
2020-06-25 16:05:36 -07:00
|
|
|
readonly dispatcherSymbol = Symbol('dispatcher');
|
2020-06-27 11:32:27 -07:00
|
|
|
onmessage = (message: string) => {};
|
2020-06-25 16:05:36 -07:00
|
|
|
|
|
|
|
async sendMessageToClient(guid: string, method: string, params: any): Promise<any> {
|
2020-06-27 11:32:27 -07:00
|
|
|
this.onmessage(JSON.stringify({ guid, method, params: this._replaceDispatchersWithGuids(params) }));
|
2020-06-25 16:05:36 -07:00
|
|
|
}
|
|
|
|
|
2020-06-27 11:32:27 -07:00
|
|
|
async send(message: string) {
|
2020-06-27 11:10:07 -07:00
|
|
|
const parsedMessage = JSON.parse(message);
|
|
|
|
const { id, guid, method, params } = parsedMessage;
|
|
|
|
const dispatcher = this.dispatchers.get(guid)!;
|
|
|
|
try {
|
|
|
|
const result = await (dispatcher as any)[method](this._replaceGuidsWithDispatchers(params));
|
2020-06-27 11:32:27 -07:00
|
|
|
this.onmessage(JSON.stringify({ id, result: this._replaceDispatchersWithGuids(result) }));
|
2020-06-27 11:10:07 -07:00
|
|
|
} catch (e) {
|
2020-06-27 11:32:27 -07:00
|
|
|
this.onmessage(JSON.stringify({ id, error: serializeError(e) }));
|
2020-06-27 11:10:07 -07:00
|
|
|
}
|
2020-06-25 16:05:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
private _replaceDispatchersWithGuids(payload: any): any {
|
|
|
|
if (!payload)
|
|
|
|
return payload;
|
|
|
|
if (payload instanceof Dispatcher)
|
|
|
|
return { guid: payload._guid };
|
|
|
|
if (Array.isArray(payload))
|
|
|
|
return payload.map(p => this._replaceDispatchersWithGuids(p));
|
2020-06-26 11:51:47 -07:00
|
|
|
// TODO: send base64
|
|
|
|
if (payload instanceof Buffer)
|
|
|
|
return payload;
|
2020-06-26 17:24:21 -07:00
|
|
|
if (typeof payload === 'object') {
|
|
|
|
const result: any = {};
|
|
|
|
for (const key of Object.keys(payload))
|
|
|
|
result[key] = this._replaceDispatchersWithGuids(payload[key]);
|
|
|
|
return result;
|
|
|
|
}
|
2020-06-25 16:05:36 -07:00
|
|
|
return payload;
|
|
|
|
}
|
|
|
|
|
|
|
|
private _replaceGuidsWithDispatchers(payload: any): any {
|
|
|
|
if (!payload)
|
|
|
|
return payload;
|
|
|
|
if (Array.isArray(payload))
|
|
|
|
return payload.map(p => this._replaceGuidsWithDispatchers(p));
|
|
|
|
if (payload.guid && this.dispatchers.has(payload.guid))
|
|
|
|
return this.dispatchers.get(payload.guid);
|
2020-06-26 11:51:47 -07:00
|
|
|
// TODO: send base64
|
|
|
|
if (payload instanceof Buffer)
|
|
|
|
return payload;
|
2020-06-26 17:24:21 -07:00
|
|
|
if (typeof payload === 'object') {
|
|
|
|
const result: any = {};
|
|
|
|
for (const key of Object.keys(payload))
|
|
|
|
result[key] = this._replaceGuidsWithDispatchers(payload[key]);
|
|
|
|
return result;
|
|
|
|
}
|
2020-06-25 16:05:36 -07:00
|
|
|
return payload;
|
|
|
|
}
|
|
|
|
}
|