提交 4339a247 编写于 作者: A Alex Dima

Initialize extension host customers only after a connection has been...

Initialize extension host customers only after a connection has been established with the extension host; retire IThreadService
上级 44895196
......@@ -8,10 +8,6 @@
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { Registry } from 'vs/platform/registry/common/platform';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IThreadService, ProxyIdentifier } from 'vs/workbench/services/thread/common/threadService';
import { MainContext, IExtHostContext } from '../node/extHost.protocol';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import { ExtHostCustomersRegistry } from "vs/workbench/api/electron-browser/extHostCustomers";
// --- other interested parties
import { JSONValidationExtensionPoint } from 'vs/platform/jsonschemas/common/jsonValidationExtensionPoint';
......@@ -49,41 +45,6 @@ import './mainThreadTerminalService';
import './mainThreadTreeViews';
import './mainThreadWorkspace';
export class ExtHostContribution implements IWorkbenchContribution {
constructor(
@IThreadService threadService: IThreadService,
@IInstantiationService instantiationService: IInstantiationService,
@IExtensionService extensionService: IExtensionService
) {
const extHostContext: IExtHostContext = threadService;
// Named customers
const namedCustomers = ExtHostCustomersRegistry.getNamedCustomers();
for (let i = 0, len = namedCustomers.length; i < len; i++) {
const [id, ctor] = namedCustomers[i];
threadService.set(id, instantiationService.createInstance(ctor, extHostContext));
}
// Customers
const customers = ExtHostCustomersRegistry.getCustomers();
for (let i = 0, len = customers.length; i < len; i++) {
const ctor = customers[i];
instantiationService.createInstance(ctor, extHostContext);
}
// Check that no named customers are missing
const expected: ProxyIdentifier<any>[] = Object.keys(MainContext).map((key) => MainContext[key]);
threadService.assertRegistered(expected);
}
public getId(): string {
return 'vs.api.extHost';
}
}
export class ExtensionPoints implements IWorkbenchContribution {
constructor(
......@@ -100,9 +61,6 @@ export class ExtensionPoints implements IWorkbenchContribution {
}
}
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(
ExtHostContribution
);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(
ExtensionPoints
);
\ No newline at end of file
);
......@@ -123,11 +123,10 @@ class MainThreadDocumentAndEditorStateComputer {
@ICodeEditorService private _codeEditorService: ICodeEditorService,
@IWorkbenchEditorService private _workbenchEditorService: IWorkbenchEditorService
) {
this._modelService.onModelAdded(this._updateState, this, this._toDispose);
this._modelService.onModelRemoved(this._updateState, this, this._toDispose);
this._modelService.onModelAdded(this.updateState, this, this._toDispose);
this._modelService.onModelRemoved(this.updateState, this, this._toDispose);
this._codeEditorService.onCodeEditorAdd(this._onDidAddEditor, this, this._toDispose);
this._codeEditorService.onCodeEditorRemove(this._onDidRemoveEditor, this, this._toDispose);
// this._updateState();
}
dispose(): void {
......@@ -135,10 +134,10 @@ class MainThreadDocumentAndEditorStateComputer {
}
private _onDidAddEditor(e: ICommonCodeEditor): void {
this._toDisposeOnEditorRemove.set(e.getId(), e.onDidChangeModel(() => this._updateState()));
this._toDisposeOnEditorRemove.set(e.getId(), e.onDidFocusEditor(() => this._updateState()));
this._toDisposeOnEditorRemove.set(e.getId(), e.onDidBlurEditor(() => this._updateState()));
this._updateState();
this._toDisposeOnEditorRemove.set(e.getId(), e.onDidChangeModel(() => this.updateState()));
this._toDisposeOnEditorRemove.set(e.getId(), e.onDidFocusEditor(() => this.updateState()));
this._toDisposeOnEditorRemove.set(e.getId(), e.onDidBlurEditor(() => this.updateState()));
this.updateState();
}
private _onDidRemoveEditor(e: ICommonCodeEditor): void {
......@@ -146,11 +145,11 @@ class MainThreadDocumentAndEditorStateComputer {
if (sub) {
this._toDisposeOnEditorRemove.delete(e.getId());
sub.dispose();
this._updateState();
this.updateState();
}
}
private _updateState(): void {
updateState(): void {
// models: ignore too large models
const models = this._modelService.getModels();
......@@ -263,6 +262,8 @@ export class MainThreadDocumentsAndEditors {
this._onDocumentAdd,
this._onDocumentRemove,
];
this._stateComputer.updateState();
}
dispose(): void {
......
......@@ -61,7 +61,6 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { IMessageService, IChoiceService, Severity } from 'vs/platform/message/common/message';
import { ChoiceChannel } from 'vs/platform/message/common/messageIpc';
import { ISearchService } from 'vs/platform/search/common/search';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { CommandService } from 'vs/platform/commands/common/commandService';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
......@@ -323,7 +322,6 @@ export class WorkbenchShell {
this.extensionService = instantiationService.createInstance(ExtensionService);
serviceCollection.set(IExtensionService, this.extensionService);
serviceCollection.set(IThreadService, this.extensionService);
this.timerService.beforeExtensionLoad = Date.now();
this.extensionService.onReady().done(() => {
......
......@@ -74,7 +74,7 @@ export class ExtensionHostProcessWorker {
private isExtensionDevelopmentDebug: boolean;
private isExtensionDevelopmentDebugBrk: boolean;
public readonly messagingProtocol = new LazyMessagePassingProtol();
readonly messagingProtocol = new LazyMessagePassingProtol();
private extensionService: ExtensionService;
......@@ -122,10 +122,10 @@ export class ExtensionHostProcessWorker {
}
}
public start(extensionService: ExtensionService): void {
public start(extensionService: ExtensionService): TPromise<IMessagePassingProtocol> {
this.extensionService = extensionService;
TPromise.join<any>([this.tryListenOnPipe(), this.tryFindDebugPort()]).then(data => {
return TPromise.join<any>([this.tryListenOnPipe(), this.tryFindDebugPort()]).then(data => {
const [server, hook] = <[Server, string]>data[0];
const port = <number>data[1];
......@@ -219,10 +219,10 @@ export class ExtensionHostProcessWorker {
}
// Initialize extension host process with hand shakes
return this.tryExtHostHandshake(server).then(() => clearTimeout(startupTimeoutHandle));
}).done(undefined, err => {
console.error('ERROR starting extension host');
console.error(err);
return this.tryExtHostHandshake(server).then((protocol) => {
clearTimeout(startupTimeoutHandle);
return protocol;
});
});
}
......@@ -262,7 +262,7 @@ export class ExtensionHostProcessWorker {
});
}
private tryExtHostHandshake(server: Server): TPromise<any> {
private tryExtHostHandshake(server: Server): TPromise<IMessagePassingProtocol> {
return new TPromise<IMessagePassingProtocol>((resolve, reject) => {
let handle = setTimeout(() => reject('timeout'), 60 * 1000);
......@@ -276,15 +276,18 @@ export class ExtensionHostProcessWorker {
}).then(protocol => {
protocol.onMessage(msg => {
if (msg === 'ready') {
// 1) Host is ready to receive messages, initialize it
return this.createExtHostInitData().then(data => protocol.send(stringify(data)));
} else if (msg === 'initialized') {
// 2) Host is initialized
this.messagingProtocol.resolve(protocol);
}
return undefined;
return new TPromise<IMessagePassingProtocol>((resolve, reject) => {
protocol.onMessage(msg => {
if (msg === 'ready') {
// 1) Host is ready to receive messages, initialize it
return this.createExtHostInitData().then(data => protocol.send(stringify(data)));
} else if (msg === 'initialized') {
// 2) Host is initialized
this.messagingProtocol.resolve(protocol);
resolve(protocol);
}
return undefined;
});
});
});
}
......
......@@ -17,8 +17,8 @@ import { areSameExtensions, getGloballyDisabledExtensions } from 'vs/platform/ex
import { ExtensionsRegistry, ExtensionPoint, IExtensionPointUser, ExtensionMessageCollector, IExtensionPoint } from 'vs/platform/extensions/common/extensionsRegistry';
import { ExtensionScanner, ILog } from 'vs/workbench/services/extensions/electron-browser/extensionPoints';
import { IMessageService } from 'vs/platform/message/common/message';
import { IThreadService, ProxyIdentifier } from 'vs/workbench/services/thread/common/threadService';
import { ExtHostContext, ExtHostExtensionServiceShape } from "vs/workbench/api/node/extHost.protocol";
import { ProxyIdentifier } from 'vs/workbench/services/thread/common/threadService';
import { ExtHostContext, ExtHostExtensionServiceShape, IExtHostContext, MainContext } from "vs/workbench/api/node/extHost.protocol";
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IStorageService } from 'vs/platform/storage/common/storage';
......@@ -26,6 +26,8 @@ import { IInstantiationService } from "vs/platform/instantiation/common/instanti
import { ExtensionHostProcessWorker } from "vs/workbench/services/extensions/electron-browser/extensionHost";
import { MainThreadService } from "vs/workbench/services/thread/electron-browser/threadService";
import { Barrier } from "vs/workbench/services/extensions/node/barrier";
import { IMessagePassingProtocol } from "vs/base/parts/ipc/common/ipc";
import { ExtHostCustomersRegistry } from "vs/workbench/api/electron-browser/extHostCustomers";
const SystemExtensionsRoot = path.normalize(path.join(URI.parse(require.toUrl('')).fsPath, '..', 'extensions'));
......@@ -43,7 +45,7 @@ function messageWithSource2(source: string, message: string): string {
const hasOwnProperty = Object.hasOwnProperty;
const NO_OP_VOID_PROMISE = TPromise.as<void>(void 0);
export class ExtensionService implements IThreadService, IExtensionService {
export class ExtensionService implements IExtensionService {
public _serviceBrand: any;
private _registry: ExtensionDescriptionRegistry;
......@@ -54,8 +56,10 @@ export class ExtensionService implements IThreadService, IExtensionService {
* A map of already activated events to speed things up if the same activation event is triggered multiple times.
*/
private readonly _alreadyActivatedEvents: { [activationEvent: string]: boolean; };
private readonly _threadService: IThreadService;
private readonly _proxy: ExtHostExtensionServiceShape;
// winjs believes a proxy is a promise because it has a `then` method,
// so wrap the result in an object.
private _proxy: TPromise<{ value: ExtHostExtensionServiceShape; }>;
constructor(
@IInstantiationService private readonly _instantiationService: IInstantiationService,
......@@ -72,28 +76,38 @@ export class ExtensionService implements IThreadService, IExtensionService {
this._alreadyActivatedEvents = Object.create(null);
const extensionHostProcessWorker = this._instantiationService.createInstance(ExtensionHostProcessWorker);
this._threadService = this._instantiationService.createInstance(MainThreadService, extensionHostProcessWorker.messagingProtocol);
this._proxy = this._threadService.get(ExtHostContext.ExtHostExtensionService);
extensionHostProcessWorker.start(this);
this._proxy = extensionHostProcessWorker.start(this).then((protocol) => {
return { value: this._begin(protocol) };
});
this._initialize();
this._scanAndHandleExtensions();
}
// ---- begin IThreadService
private _begin(protocol: IMessagePassingProtocol): ExtHostExtensionServiceShape {
public get<T>(identifier: ProxyIdentifier<T>): T {
return this._threadService.get(identifier);
}
const threadService = this._instantiationService.createInstance(MainThreadService, protocol);
const extHostContext: IExtHostContext = threadService;
public set<T, R extends T>(identifier: ProxyIdentifier<T>, value: R): R {
return this._threadService.set<T, R>(identifier, value);
}
// Named customers
const namedCustomers = ExtHostCustomersRegistry.getNamedCustomers();
for (let i = 0, len = namedCustomers.length; i < len; i++) {
const [id, ctor] = namedCustomers[i];
threadService.set(id, this._instantiationService.createInstance(ctor, extHostContext));
}
public assertRegistered(identifiers: ProxyIdentifier<any>[]): void {
this._threadService.assertRegistered(identifiers);
}
// Customers
const customers = ExtHostCustomersRegistry.getCustomers();
for (let i = 0, len = customers.length; i < len; i++) {
const ctor = customers[i];
this._instantiationService.createInstance(ctor, extHostContext);
}
// ---- end IThreadService
// Check that no named customers are missing
const expected: ProxyIdentifier<any>[] = Object.keys(MainContext).map((key) => MainContext[key]);
threadService.assertRegistered(expected);
return threadService.get(ExtHostContext.ExtHostExtensionService);
}
// ---- begin IExtensionService
......@@ -109,7 +123,9 @@ export class ExtensionService implements IThreadService, IExtensionService {
if (this._alreadyActivatedEvents[activationEvent]) {
return NO_OP_VOID_PROMISE;
}
return this._proxy.$activateByEvent(activationEvent).then(() => {
return this._proxy.then((proxy) => {
return proxy.value.$activateByEvent(activationEvent);
}).then(() => {
this._alreadyActivatedEvents[activationEvent] = true;
});
}
......@@ -149,7 +165,7 @@ export class ExtensionService implements IThreadService, IExtensionService {
// --- impl
private _initialize(): void {
private _scanAndHandleExtensions(): void {
const log = new Logger((severity, source, message) => {
this._logOrShowMessage(severity, this._isDev ? messageWithSource2(source, message) : message);
......
......@@ -4,13 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
export const IThreadService = createDecorator<IThreadService>('threadService');
export interface IThreadService {
_serviceBrand: any;
/**
* Always returns a proxy.
*/
......
......@@ -34,9 +34,6 @@ function asLoggingProtocol(protocol: IMessagePassingProtocol): IMessagePassingPr
export class MainThreadService extends AbstractThreadService implements IThreadService {
_serviceBrand: any;
constructor(protocol: IMessagePassingProtocol, @IEnvironmentService environmentService: IEnvironmentService) {
if (logExtensionHostCommunication || environmentService.logExtensionHostCommunication) {
protocol = asLoggingProtocol(protocol);
......
......@@ -9,8 +9,6 @@ import { AbstractThreadService } from 'vs/workbench/services/thread/node/abstrac
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
export class ExtHostThreadService extends AbstractThreadService implements IThreadService {
public _serviceBrand: any;
constructor(rpcProtocol: RPCProtocol) {
super(rpcProtocol, false);
}
......
......@@ -71,6 +71,7 @@ suite('MainThreadDocumentsAndEditors', () => {
test('Model#add', () => {
deltas.length = 0;
modelService.createModel('farboo', null, null);
......@@ -125,6 +126,8 @@ suite('MainThreadDocumentsAndEditors', () => {
});
test('editor with model', () => {
deltas.length = 0;
const model = modelService.createModel('farboo', null, null);
codeEditorService.addCodeEditor(mockCodeEditor(null, { model }));
......
......@@ -10,7 +10,6 @@ import { IThreadService, ProxyIdentifier } from 'vs/workbench/services/thread/co
export function OneGetThreadService(thing: any): IThreadService {
return {
_serviceBrand: undefined,
get<T>(): T {
return thing;
},
......@@ -77,8 +76,6 @@ export abstract class AbstractTestThreadService {
}
export class TestThreadService extends AbstractTestThreadService implements IThreadService {
public _serviceBrand: any;
constructor() {
super(false);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册