mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-25 17:27:26 +01:00
225 lines
7.9 KiB
TypeScript
225 lines
7.9 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
'use strict';
|
|
|
|
import {TPromise} from 'vs/base/common/winjs.base';
|
|
import remote = require('vs/base/common/remote');
|
|
import {ThreadAffinity, Remotable, IThreadSynchronizableObject, IDynamicProxy} from 'vs/platform/thread/common/thread';
|
|
import {THREAD_SERVICE_PROPERTY_NAME} from 'vs/platform/thread/common/threadService';
|
|
import instantiation = require('vs/platform/instantiation/common/instantiation');
|
|
import {SyncDescriptor0, createSyncDescriptor, AsyncDescriptor0, AsyncDescriptor1, AsyncDescriptor2, AsyncDescriptor3} from 'vs/platform/instantiation/common/descriptors';
|
|
|
|
export interface IThreadServiceData {
|
|
[id: string]: any;
|
|
}
|
|
|
|
class DynamicProxy<T> implements IDynamicProxy<T> {
|
|
|
|
private _proxyDefinition: T;
|
|
private _disposeDelegate: () => void;
|
|
|
|
constructor(proxyDefinition: T, disposeDelegate: () => void) {
|
|
this._proxyDefinition = proxyDefinition;
|
|
this._disposeDelegate = disposeDelegate;
|
|
}
|
|
|
|
public dispose(): void {
|
|
return this._disposeDelegate();
|
|
}
|
|
|
|
public getProxyDefinition(): T {
|
|
return this._proxyDefinition;
|
|
}
|
|
}
|
|
|
|
export abstract class AbstractThreadService implements remote.IManyHandler {
|
|
|
|
public isInMainThread: boolean;
|
|
|
|
protected _instantiationService: instantiation.IInstantiationService;
|
|
|
|
protected _boundObjects: { [id: string]: IThreadSynchronizableObject<any>; };
|
|
protected _pendingObjects: TPromise<IThreadSynchronizableObject<any>>[];
|
|
private _localObjMap: { [id: string]: any; };
|
|
private _proxyObjMap: { [id: string]: any; };
|
|
|
|
constructor(isInMainThread: boolean) {
|
|
this.isInMainThread = isInMainThread;
|
|
this._boundObjects = {};
|
|
this._pendingObjects = [];
|
|
this._localObjMap = Object.create(null);
|
|
this._proxyObjMap = Object.create(null);
|
|
}
|
|
|
|
setInstantiationService(service: instantiation.IInstantiationService): void {
|
|
this._instantiationService = service;
|
|
}
|
|
|
|
createInstance<T extends IThreadSynchronizableObject<any>>(ctor: instantiation.IConstructorSignature0<T>): T;
|
|
createInstance<A1, T extends IThreadSynchronizableObject<any>>(ctor: instantiation.IConstructorSignature1<A1, T>, a1: A1): T;
|
|
createInstance<A1, A2, T extends IThreadSynchronizableObject<any>>(ctor: instantiation.IConstructorSignature2<A1, A2, T>, a1: A1, a2: A2): T;
|
|
createInstance<A1, A2, A3, T extends IThreadSynchronizableObject<any>>(ctor: instantiation.IConstructorSignature3<A1, A2, A3, T>, a1: A1, a2: A2, a3: A3): T;
|
|
|
|
createInstance<T extends IThreadSynchronizableObject<any>>(descriptor: AsyncDescriptor0<T>): T;
|
|
createInstance<A1, T extends IThreadSynchronizableObject<any>>(descriptor: AsyncDescriptor1<A1, T>, a1: A1): T;
|
|
createInstance<A1, A2, T extends IThreadSynchronizableObject<any>>(descriptor: AsyncDescriptor2<A1, A2, T>, a1: A1, a2: A2): T;
|
|
createInstance<A1, A2, A3, T extends IThreadSynchronizableObject<any>>(descriptor: AsyncDescriptor3<A1, A2, A3, T>, a1: A1, a2: A2, a3: A3): T;
|
|
|
|
createInstance(...params: any[]): any {
|
|
return this._doCreateInstance(params);
|
|
}
|
|
|
|
protected _doCreateInstance(params: any[]): any {
|
|
let instanceOrPromise = this._instantiationService.createInstance.apply(this._instantiationService, params);
|
|
|
|
if (TPromise.is(instanceOrPromise)) {
|
|
|
|
let objInstantiated: TPromise<IThreadSynchronizableObject<any>>;
|
|
objInstantiated = instanceOrPromise.then((instance: IThreadSynchronizableObject<any>): any => {
|
|
if (instance.asyncCtor) {
|
|
let initPromise = instance.asyncCtor();
|
|
if (TPromise.is(initPromise)) {
|
|
return initPromise.then(() => {
|
|
return instance;
|
|
});
|
|
}
|
|
}
|
|
return instance;
|
|
});
|
|
|
|
this._pendingObjects.push(objInstantiated);
|
|
return objInstantiated.then((instance: IThreadSynchronizableObject<any>) => {
|
|
let r = this._finishInstance(instance);
|
|
|
|
for (let i = 0; i < this._pendingObjects.length; i++) {
|
|
if (this._pendingObjects[i] === objInstantiated) {
|
|
this._pendingObjects.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return r;
|
|
});
|
|
|
|
}
|
|
|
|
return this._finishInstance(<IThreadSynchronizableObject<any>>instanceOrPromise);
|
|
}
|
|
|
|
_finishInstance(instance: IThreadSynchronizableObject<any>): IThreadSynchronizableObject<any> {
|
|
instance[THREAD_SERVICE_PROPERTY_NAME] = this;
|
|
this._boundObjects[instance.getId()] = instance;
|
|
|
|
if (instance.creationDone) {
|
|
instance.creationDone();
|
|
}
|
|
|
|
return instance;
|
|
}
|
|
|
|
public handle(rpcId: string, methodName: string, args: any[]): any {
|
|
if (!this._localObjMap[rpcId]) {
|
|
throw new Error('Unknown actor ' + rpcId);
|
|
}
|
|
let actor = this._localObjMap[rpcId];
|
|
let method = actor[methodName];
|
|
if (typeof method !== 'function') {
|
|
throw new Error('Unknown method ' + methodName + ' on actor ' + rpcId);
|
|
}
|
|
return method.apply(actor, args);
|
|
}
|
|
|
|
protected _getOrCreateProxyInstance(remoteCom: remote.IProxyHelper, id: string, descriptor: SyncDescriptor0<any>): any {
|
|
if (this._proxyObjMap[id]) {
|
|
return this._proxyObjMap[id];
|
|
}
|
|
let result = createProxyFromCtor(remoteCom, id, descriptor.ctor);
|
|
this._proxyObjMap[id] = result;
|
|
return result;
|
|
}
|
|
|
|
protected _registerLocalInstance(id: string, obj: any): any {
|
|
this._localObjMap[id] = obj;
|
|
}
|
|
|
|
protected _getOrCreateLocalInstance(id: string, descriptor: SyncDescriptor0<any>): any {
|
|
if (this._localObjMap[id]) {
|
|
return this._localObjMap[id];
|
|
}
|
|
let result = this._instantiationService.createInstance(descriptor);
|
|
this._registerLocalInstance(id, result);
|
|
return result;
|
|
}
|
|
|
|
getRemotable<T>(ctor: instantiation.INewConstructorSignature0<T>): T {
|
|
let id = Remotable.getId(ctor);
|
|
if (!id) {
|
|
throw new Error('Unknown Remotable: <<' + id + '>>');
|
|
}
|
|
|
|
let desc = createSyncDescriptor<T>(ctor);
|
|
|
|
if (Remotable.Registry.MainContext[id]) {
|
|
return this._registerAndInstantiateMainProcessActor(id, desc);
|
|
}
|
|
|
|
if (Remotable.Registry.PluginHostContext[id]) {
|
|
return this._registerAndInstantiatePluginHostActor(id, desc);
|
|
}
|
|
|
|
if (Remotable.Registry.WorkerContext[id]) {
|
|
return this._registerAndInstantiateWorkerActor(id, desc, Remotable.Registry.WorkerContext[id].affinity);
|
|
}
|
|
|
|
throw new Error('Unknown Remotable: <<' + id + '>>');
|
|
}
|
|
|
|
registerRemotableInstance(ctor: any, instance: any): void {
|
|
let id = Remotable.getId(ctor);
|
|
if (!id) {
|
|
throw new Error('Unknown Remotable: <<' + id + '>>');
|
|
}
|
|
|
|
if (Remotable.Registry.MainContext[id]) {
|
|
return this._registerMainProcessActor(id, instance);
|
|
}
|
|
|
|
if (Remotable.Registry.PluginHostContext[id]) {
|
|
return this._registerPluginHostActor(id, instance);
|
|
}
|
|
|
|
if (Remotable.Registry.WorkerContext[id]) {
|
|
return this._registerWorkerActor(id, instance);
|
|
}
|
|
|
|
throw new Error('Unknown Remotable: <<' + id + '>>');
|
|
}
|
|
|
|
protected abstract _registerAndInstantiateMainProcessActor<T>(id: string, descriptor: SyncDescriptor0<T>): T;
|
|
protected abstract _registerMainProcessActor<T>(id: string, actor: T): void;
|
|
protected abstract _registerAndInstantiatePluginHostActor<T>(id: string, descriptor: SyncDescriptor0<T>): T;
|
|
protected abstract _registerPluginHostActor<T>(id: string, actor: T): void;
|
|
protected abstract _registerAndInstantiateWorkerActor<T>(id: string, descriptor: SyncDescriptor0<T>, whichWorker: ThreadAffinity): T;
|
|
protected abstract _registerWorkerActor<T>(id: string, actor: T): void;
|
|
}
|
|
|
|
function createProxyFromCtor(remote:remote.IProxyHelper, id:string, ctor:Function): any {
|
|
var result: any = {
|
|
$__IS_REMOTE_OBJ: true
|
|
};
|
|
for (var prop in ctor.prototype) {
|
|
if (typeof ctor.prototype[prop] === 'function') {
|
|
result[prop] = createMethodProxy(remote, id, prop);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function createMethodProxy(remote:remote.IProxyHelper, proxyId: string, path: string): (...myArgs: any[]) => TPromise<any> {
|
|
return (...myArgs: any[]) => {
|
|
return remote.callOnRemote(proxyId, path, myArgs);
|
|
};
|
|
}
|