diff --git a/src/vs/workbench/node/extensionHostMain.ts b/src/vs/workbench/node/extensionHostMain.ts index b7ab7c8a81a..b68165573df 100644 --- a/src/vs/workbench/node/extensionHostMain.ts +++ b/src/vs/workbench/node/extensionHostMain.ts @@ -9,7 +9,7 @@ import nls = require('vs/nls'); import pfs = require('vs/base/node/pfs'); import { TPromise } from 'vs/base/common/winjs.base'; import { join } from 'path'; -import { IRemoteCom } from 'vs/workbench/services/extensions/node/ipcRemoteCom'; +import { RPCProtocol } from 'vs/workbench/services/extensions/node/rpcProtocol'; import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; import { ExtHostThreadService } from 'vs/workbench/services/thread/node/extHostThreadService'; import { QueryType, ISearchQuery } from 'vs/platform/search/common/search'; @@ -40,12 +40,12 @@ export class ExtensionHostMain { private _environment: IEnvironment; private _extensionService: ExtHostExtensionService; - constructor(remoteCom: IRemoteCom, initData: IInitData) { + constructor(rpcProtocol: RPCProtocol, initData: IInitData) { this._environment = initData.environment; this._workspace = initData.workspace; // services - const threadService = new ExtHostThreadService(remoteCom); + const threadService = new ExtHostThreadService(rpcProtocol); const telemetryService = new RemoteTelemetryService('pluginHostTelemetry', threadService); this._extensionService = new ExtHostExtensionService(initData, threadService, telemetryService); diff --git a/src/vs/workbench/node/extensionHostProcess.ts b/src/vs/workbench/node/extensionHostProcess.ts index 05853d4b56b..f49c1175a82 100644 --- a/src/vs/workbench/node/extensionHostProcess.ts +++ b/src/vs/workbench/node/extensionHostProcess.ts @@ -8,7 +8,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; import { ExtensionHostMain, exit } from 'vs/workbench/node/extensionHostMain'; -import { IRemoteCom, createProxyProtocol } from 'vs/workbench/services/extensions/node/ipcRemoteCom'; +import { RPCProtocol } from 'vs/workbench/services/extensions/node/rpcProtocol'; import { parse } from 'vs/base/common/marshalling'; import { IInitData } from 'vs/workbench/api/node/extHost.protocol'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; @@ -17,7 +17,7 @@ import { createConnection } from 'net'; import Event, { filterEvent } from 'vs/base/common/event'; interface IRendererConnection { - remoteCom: IRemoteCom; + rpcProtocol: RPCProtocol; initData: IInitData; } @@ -71,7 +71,7 @@ function connectToRenderer(protocol: IMessagePassingProtocol): TPromise { return connectToRenderer(protocol); }).then(renderer => { // setup things - const extensionHostMain = new ExtensionHostMain(renderer.remoteCom, renderer.initData); + const extensionHostMain = new ExtensionHostMain(renderer.rpcProtocol, renderer.initData); onTerminate = () => extensionHostMain.terminate(); return extensionHostMain.start(); }).done(null, err => console.error(err)); diff --git a/src/vs/workbench/services/extensions/node/ipcRemoteCom.ts b/src/vs/workbench/services/extensions/node/rpcProtocol.ts similarity index 86% rename from src/vs/workbench/services/extensions/node/ipcRemoteCom.ts rename to src/vs/workbench/services/extensions/node/rpcProtocol.ts index f94fe537133..b58fa9b22d6 100644 --- a/src/vs/workbench/services/extensions/node/ipcRemoteCom.ts +++ b/src/vs/workbench/services/extensions/node/rpcProtocol.ts @@ -10,22 +10,13 @@ import * as errors from 'vs/base/common/errors'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { LazyPromise } from "vs/workbench/services/extensions/node/lazyPromise"; -export interface IManyHandler { - handle(rpcId: string, method: string, args: any[]): any; +export interface IDispatcher { + invoke(proxyId: string, methodName: string, args: any[]): any; } -export interface IRemoteCom { - callOnRemote(proxyId: string, path: string, args: any[]): TPromise; - setManyHandler(handler: IManyHandler): void; -} +export class RPCProtocol { -export function createProxyProtocol(protocol: IMessagePassingProtocol): IRemoteCom { - return new RPCManager(protocol); -} - -export class RPCManager implements IRemoteCom { - - private _bigHandler: IManyHandler; + private _bigHandler: IDispatcher; private _lastMessageId: number; private readonly _invokedHandlers: { [req: string]: TPromise; }; private readonly _pendingRPCReplies: { [msgId: string]: LazyPromise; }; @@ -97,15 +88,15 @@ export class RPCManager implements IRemoteCom { }); } - private _invokeHandler(rpcId: string, method: string, args: any[]): TPromise { + private _invokeHandler(proxyId: string, methodName: string, args: any[]): TPromise { try { - return TPromise.as(this._bigHandler.handle(rpcId, method, args)); + return TPromise.as(this._bigHandler.invoke(proxyId, methodName, args)); } catch (err) { return TPromise.wrapError(err); } } - public callOnRemote(proxyId: string, path: string, args: any[]): TPromise { + public callOnRemote(proxyId: string, methodName: string, args: any[]): TPromise { let req = String(++this._lastMessageId); let result = new LazyPromise(() => { this._multiplexor.send(MessageFactory.cancel(req)); @@ -113,12 +104,12 @@ export class RPCManager implements IRemoteCom { this._pendingRPCReplies[req] = result; - this._multiplexor.send(MessageFactory.request(req, proxyId, path, args)); + this._multiplexor.send(MessageFactory.request(req, proxyId, methodName, args)); return result; } - public setManyHandler(handler: IManyHandler): void { + public setDispatcher(handler: IDispatcher): void { this._bigHandler = handler; } } diff --git a/src/vs/workbench/services/thread/electron-browser/threadService.ts b/src/vs/workbench/services/thread/electron-browser/threadService.ts index 9b3a101f564..f435eae4e9f 100644 --- a/src/vs/workbench/services/thread/electron-browser/threadService.ts +++ b/src/vs/workbench/services/thread/electron-browser/threadService.ts @@ -6,8 +6,7 @@ 'use strict'; import * as strings from 'vs/base/common/strings'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { IRemoteCom, createProxyProtocol } from 'vs/workbench/services/extensions/node/ipcRemoteCom'; +import { RPCProtocol } from 'vs/workbench/services/extensions/node/rpcProtocol'; import { AbstractThreadService } from 'vs/workbench/services/thread/node/abstractThreadService'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -38,20 +37,11 @@ export class MainThreadService extends AbstractThreadService implements IThreadS _serviceBrand: any; - private _remoteCom: IRemoteCom; - constructor(protocol: IMessagePassingProtocol, @IEnvironmentService environmentService: IEnvironmentService) { - super(true); - if (logExtensionHostCommunication || environmentService.logExtensionHostCommunication) { protocol = asLoggingProtocol(protocol); } - this._remoteCom = createProxyProtocol(protocol); - this._remoteCom.setManyHandler(this); - } - - protected _callOnRemote(proxyId: string, path: string, args: any[]): TPromise { - return this._remoteCom.callOnRemote(proxyId, path, args); + super(new RPCProtocol(protocol), true); } } diff --git a/src/vs/workbench/services/thread/node/abstractThreadService.ts b/src/vs/workbench/services/thread/node/abstractThreadService.ts index 86344d99b55..a76b2f82fac 100644 --- a/src/vs/workbench/services/thread/node/abstractThreadService.ts +++ b/src/vs/workbench/services/thread/node/abstractThreadService.ts @@ -5,31 +5,34 @@ 'use strict'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IManyHandler } from 'vs/workbench/services/extensions/node/ipcRemoteCom'; +import { IDispatcher, RPCProtocol } from 'vs/workbench/services/extensions/node/rpcProtocol'; import { ProxyIdentifier } from 'vs/workbench/services/thread/common/threadService'; // declare var Proxy:any; // TODO@TypeScript -export abstract class AbstractThreadService implements IManyHandler { +export abstract class AbstractThreadService implements IDispatcher { - private _isMain: boolean; - protected _locals: { [id: string]: any; }; - private _proxies: { [id: string]: any; } = Object.create(null); + private readonly _rpcProtocol: RPCProtocol; + private readonly _isMain: boolean; + protected readonly _locals: { [id: string]: any; }; + private readonly _proxies: { [id: string]: any; } = Object.create(null); - constructor(isMain: boolean) { + constructor(rpcProtocol: RPCProtocol, isMain: boolean) { + this._rpcProtocol = rpcProtocol; this._isMain = isMain; this._locals = Object.create(null); this._proxies = Object.create(null); + this._rpcProtocol.setDispatcher(this); } - public handle(rpcId: string, methodName: string, args: any[]): any { - if (!this._locals[rpcId]) { - throw new Error('Unknown actor ' + rpcId); + public invoke(proxyId: string, methodName: string, args: any[]): any { + if (!this._locals[proxyId]) { + throw new Error('Unknown actor ' + proxyId); } - let actor = this._locals[rpcId]; + let actor = this._locals[proxyId]; let method = actor[methodName]; if (typeof method !== 'function') { - throw new Error('Unknown method ' + methodName + ' on actor ' + rpcId); + throw new Error('Unknown method ' + methodName + ' on actor ' + proxyId); } return method.apply(actor, args); } @@ -41,12 +44,12 @@ export abstract class AbstractThreadService implements IManyHandler { return this._proxies[identifier.id]; } - private _createProxy(id: string, methodNames: string[]): T { + private _createProxy(proxyId: string, methodNames: string[]): T { // Check below how to switch to native proxies let result: any = {}; for (let i = 0; i < methodNames.length; i++) { let methodName = methodNames[i]; - result[methodName] = this.createMethodProxy(id, methodName); + result[methodName] = this._createMethodProxy(proxyId, methodName); } return result; @@ -60,9 +63,9 @@ export abstract class AbstractThreadService implements IManyHandler { // return new Proxy({}, handler); } - private createMethodProxy(id: string, methodName: string): (...myArgs: any[]) => TPromise { + private _createMethodProxy(proxyId: string, methodName: string): (...myArgs: any[]) => TPromise { return (...myArgs: any[]) => { - return this._callOnRemote(id, methodName, myArgs); + return this._callOnRemote(proxyId, methodName, myArgs); }; } @@ -73,5 +76,7 @@ export abstract class AbstractThreadService implements IManyHandler { this._locals[identifier.id] = value; } - protected abstract _callOnRemote(proxyId: string, path: string, args: any[]): TPromise; + private _callOnRemote(proxyId: string, methodName: string, args: any[]): TPromise { + return this._rpcProtocol.callOnRemote(proxyId, methodName, args); + } } diff --git a/src/vs/workbench/services/thread/node/extHostThreadService.ts b/src/vs/workbench/services/thread/node/extHostThreadService.ts index 0e8bb80b463..63290966e20 100644 --- a/src/vs/workbench/services/thread/node/extHostThreadService.ts +++ b/src/vs/workbench/services/thread/node/extHostThreadService.ts @@ -4,22 +4,14 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { IRemoteCom } from 'vs/workbench/services/extensions/node/ipcRemoteCom'; -import { TPromise } from 'vs/base/common/winjs.base'; +import { RPCProtocol } from 'vs/workbench/services/extensions/node/rpcProtocol'; import { AbstractThreadService } from 'vs/workbench/services/thread/node/abstractThreadService'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; export class ExtHostThreadService extends AbstractThreadService implements IThreadService { public _serviceBrand: any; - protected _remoteCom: IRemoteCom; - constructor(remoteCom: IRemoteCom) { - super(false); - this._remoteCom = remoteCom; - this._remoteCom.setManyHandler(this); - } - - protected _callOnRemote(proxyId: string, path: string, args: any[]): TPromise { - return this._remoteCom.callOnRemote(proxyId, path, args); + constructor(rpcProtocol: RPCProtocol) { + super(rpcProtocol, false); } } diff --git a/src/vs/workbench/test/electron-browser/api/testThreadService.ts b/src/vs/workbench/test/electron-browser/api/testThreadService.ts index 5e2f511d6d1..4ab57cdf243 100644 --- a/src/vs/workbench/test/electron-browser/api/testThreadService.ts +++ b/src/vs/workbench/test/electron-browser/api/testThreadService.ts @@ -6,7 +6,6 @@ 'use strict'; import { TPromise } from 'vs/base/common/winjs.base'; -import { AbstractThreadService } from 'vs/workbench/services/thread/node/abstractThreadService'; import { IThreadService, ProxyIdentifier } from 'vs/workbench/services/thread/common/threadService'; export function OneGetThreadService(thing: any): IThreadService { @@ -21,7 +20,73 @@ export function OneGetThreadService(thing: any): IThreadService { }; } -export class TestThreadService extends AbstractThreadService implements IThreadService { +export abstract class AbstractTestThreadService { + + private _isMain: boolean; + protected _locals: { [id: string]: any; }; + private _proxies: { [id: string]: any; } = Object.create(null); + + constructor(isMain: boolean) { + this._isMain = isMain; + this._locals = Object.create(null); + this._proxies = Object.create(null); + } + + public handle(rpcId: string, methodName: string, args: any[]): any { + if (!this._locals[rpcId]) { + throw new Error('Unknown actor ' + rpcId); + } + let actor = this._locals[rpcId]; + let method = actor[methodName]; + if (typeof method !== 'function') { + throw new Error('Unknown method ' + methodName + ' on actor ' + rpcId); + } + return method.apply(actor, args); + } + + get(identifier: ProxyIdentifier): T { + if (!this._proxies[identifier.id]) { + this._proxies[identifier.id] = this._createProxy(identifier.id, identifier.methodNames); + } + return this._proxies[identifier.id]; + } + + private _createProxy(id: string, methodNames: string[]): T { + // Check below how to switch to native proxies + let result: any = {}; + for (let i = 0; i < methodNames.length; i++) { + let methodName = methodNames[i]; + result[methodName] = this.createMethodProxy(id, methodName); + } + return result; + + // let handler = { + // get: (target, name) => { + // return (...myArgs: any[]) => { + // return this._callOnRemote(id, name, myArgs); + // }; + // } + // }; + // return new Proxy({}, handler); + } + + private createMethodProxy(id: string, methodName: string): (...myArgs: any[]) => TPromise { + return (...myArgs: any[]) => { + return this._callOnRemote(id, methodName, myArgs); + }; + } + + set(identifier: ProxyIdentifier, value: T): void { + if (identifier.isMain !== this._isMain) { + throw new Error('Mismatch in object registration!'); + } + this._locals[identifier.id] = value; + } + + protected abstract _callOnRemote(proxyId: string, path: string, args: any[]): TPromise; +} + +export class TestThreadService extends AbstractTestThreadService implements IThreadService { public _serviceBrand: any; constructor() {