wip: send message ports upfront
This commit is contained in:
parent
68117af61a
commit
2ff9b87972
|
@ -74,7 +74,6 @@ import './mainThreadAuthentication';
|
|||
import './mainThreadTimeline';
|
||||
import './mainThreadTesting';
|
||||
import './mainThreadSecretState';
|
||||
import './mainThreadIPC';
|
||||
|
||||
export class ExtensionPoints implements IWorkbenchContribution {
|
||||
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, IExtHostContext, MainContext, MainThreadIPCShape, IPCHandle, ExtHostIPCShape } from '../common/extHost.protocol';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadIPC)
|
||||
export class MainThreadIPC implements MainThreadIPCShape {
|
||||
|
||||
private static Handles = 0;
|
||||
|
||||
private readonly emitter = new Emitter<{ handle: IPCHandle, message: VSBuffer }>();
|
||||
private readonly disposables = new Map<IPCHandle, IDisposable>();
|
||||
private proxy: ExtHostIPCShape | undefined;
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
if (!environmentService.options?.ipcProvider) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostIPC);
|
||||
}
|
||||
|
||||
async $register(extensionId: ExtensionIdentifier): Promise<IPCHandle | undefined> {
|
||||
if (!this.proxy) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const ipc = await this.environmentService.options?.ipcProvider?.getMessagePassingProtocol(extensionId.value);
|
||||
|
||||
if (!ipc) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const handle = MainThreadIPC.Handles++;
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
ipc.onDidReceiveMessage(message => this.proxy!.$sendMessage(handle, VSBuffer.wrap(message)), undefined, disposables);
|
||||
Event.chain(this.emitter.event)
|
||||
.filter(e => e.handle === handle)
|
||||
.map(({ message }) => message.buffer)
|
||||
.event(message => ipc.sendMessage(message), undefined, disposables);
|
||||
|
||||
this.disposables.set(handle, disposables);
|
||||
return handle;
|
||||
}
|
||||
|
||||
async $sendMessage(handle: IPCHandle, message: VSBuffer): Promise<void> {
|
||||
this.emitter.fire({ handle, message });
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.emitter.dispose();
|
||||
}
|
||||
}
|
|
@ -92,7 +92,6 @@ import { ExtHostNotebookDocuments } from 'vs/workbench/api/common/extHostNoteboo
|
|||
import { ExtHostInteractive } from 'vs/workbench/api/common/extHostInteractive';
|
||||
import { combinedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { checkProposedApiEnabled, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtHostIPC } from 'vs/workbench/api/common/extHostIPC';
|
||||
|
||||
export interface IExtensionApiFactory {
|
||||
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
|
||||
|
@ -178,7 +177,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
|||
const extHostWebviewViews = rpcProtocol.set(ExtHostContext.ExtHostWebviewViews, new ExtHostWebviewViews(rpcProtocol, extHostWebviews));
|
||||
const extHostTesting = rpcProtocol.set(ExtHostContext.ExtHostTesting, new ExtHostTesting(rpcProtocol, extHostCommands));
|
||||
const extHostUriOpeners = rpcProtocol.set(ExtHostContext.ExtHostUriOpeners, new ExtHostUriOpeners(rpcProtocol));
|
||||
const extHostIPC = rpcProtocol.set(ExtHostContext.ExtHostIPC, new ExtHostIPC(rpcProtocol));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostInteractive, new ExtHostInteractive(rpcProtocol, extHostNotebook, extHostDocumentsAndEditors, extHostCommands));
|
||||
|
||||
// Check that no named customers are missing
|
||||
|
@ -762,10 +760,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
|||
getInlineCompletionItemController<T extends vscode.InlineCompletionItem>(provider: vscode.InlineCompletionItemProvider<T>): vscode.InlineCompletionController<T> {
|
||||
checkProposedApiEnabled(extension, 'inlineCompletions');
|
||||
return InlineCompletionController.get(provider);
|
||||
},
|
||||
getMessagePassingProtocol() {
|
||||
checkProposedApiEnabled(extension, 'ipc');
|
||||
return extHostIPC.getMessagePassingProtocol(extension);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -113,6 +113,7 @@ export interface IInitData {
|
|||
autoStart: boolean;
|
||||
remote: { isRemote: boolean; authority: string | undefined; connectionData: IRemoteConnectionData | null; };
|
||||
uiKind: UIKind;
|
||||
messagePorts?: ReadonlyMap<string, MessagePort>;
|
||||
}
|
||||
|
||||
export interface IConfigurationInitData extends IConfigurationData {
|
||||
|
@ -2195,17 +2196,6 @@ export interface MainThreadTestingShape {
|
|||
$finishedExtensionTestRun(runId: string): void;
|
||||
}
|
||||
|
||||
export type IPCHandle = number;
|
||||
|
||||
export interface ExtHostIPCShape {
|
||||
$sendMessage(handle: IPCHandle, message: VSBuffer): Promise<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadIPCShape {
|
||||
$register(extensionId: ExtensionIdentifier): Promise<IPCHandle | undefined>;
|
||||
$sendMessage(handle: IPCHandle, message: VSBuffer): Promise<void>;
|
||||
}
|
||||
|
||||
// --- proxy identifiers
|
||||
|
||||
export const MainContext = {
|
||||
|
@ -2265,7 +2255,6 @@ export const MainContext = {
|
|||
MainThreadTunnelService: createMainId<MainThreadTunnelServiceShape>('MainThreadTunnelService'),
|
||||
MainThreadTimeline: createMainId<MainThreadTimelineShape>('MainThreadTimeline'),
|
||||
MainThreadTesting: createMainId<MainThreadTestingShape>('MainThreadTesting'),
|
||||
MainThreadIPC: createMainId<MainThreadIPCShape>('MainThreadIPC'),
|
||||
};
|
||||
|
||||
export const ExtHostContext = {
|
||||
|
@ -2320,5 +2309,4 @@ export const ExtHostContext = {
|
|||
ExtHostTimeline: createMainId<ExtHostTimelineShape>('ExtHostTimeline'),
|
||||
ExtHostTesting: createMainId<ExtHostTestingShape>('ExtHostTesting'),
|
||||
ExtHostTelemetry: createMainId<ExtHostTelemetryShape>('ExtHostTelemetry'),
|
||||
ExtHostIPC: createMainId<ExtHostIPCShape>('ExtHostIPC'),
|
||||
};
|
||||
|
|
|
@ -447,7 +447,8 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
|||
checkProposedApiEnabled(extensionDescription, 'extensionRuntime');
|
||||
return that.extensionRuntime;
|
||||
},
|
||||
get environmentVariableCollection() { return that._extHostTerminalService.getEnvironmentVariableCollection(extensionDescription); }
|
||||
get environmentVariableCollection() { return that._extHostTerminalService.getEnvironmentVariableCollection(extensionDescription); },
|
||||
messagePort: this._initData.messagePorts?.get(ExtensionIdentifier.toKey(extensionDescription.identifier))
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { ExtHostIPCShape, IPCHandle, MainContext, MainThreadIPCShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { MessagePassingProtocol } from 'vscode';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
export class ExtHostIPC implements ExtHostIPCShape {
|
||||
|
||||
private readonly emitter = new Emitter<{ handle: IPCHandle, message: VSBuffer }>();
|
||||
private proxy: MainThreadIPCShape;
|
||||
|
||||
constructor(@IExtHostRpcService rpc: IExtHostRpcService) {
|
||||
this.proxy = rpc.getProxy(MainContext.MainThreadIPC);
|
||||
}
|
||||
|
||||
async getMessagePassingProtocol(extension: IExtensionDescription): Promise<MessagePassingProtocol | undefined> {
|
||||
const handle = await this.proxy.$register(extension.identifier);
|
||||
|
||||
if (handle === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const onDidReceiveMessage = Event.chain(this.emitter.event)
|
||||
.filter(e => e.handle === handle)
|
||||
.map(({ message }) => message.buffer)
|
||||
.event;
|
||||
|
||||
return {
|
||||
onDidReceiveMessage,
|
||||
sendMessage: (message) => {
|
||||
this.proxy.$sendMessage(handle, VSBuffer.wrap(message));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async $sendMessage(handle: IPCHandle, message: VSBuffer): Promise<void> {
|
||||
this.emitter.fire({ handle, message });
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.emitter.dispose();
|
||||
}
|
||||
}
|
|
@ -295,6 +295,9 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
|||
}
|
||||
);
|
||||
|
||||
const messagePorts = this._environmentService.options?.messagePorts ?? new Map();
|
||||
worker.postMessage(messagePorts as any, [...messagePorts.values()]);
|
||||
|
||||
// await MessagePort and use it to directly communicate
|
||||
// with the worker extension host
|
||||
await barrier.wait();
|
||||
|
|
|
@ -45,7 +45,8 @@ export class ExtensionHostMain {
|
|||
protocol: IMessagePassingProtocol,
|
||||
initData: IInitData,
|
||||
hostUtils: IHostUtils,
|
||||
uriTransformer: IURITransformer | null
|
||||
uriTransformer: IURITransformer | null,
|
||||
messagePorts?: ReadonlyMap<string, MessagePort>
|
||||
) {
|
||||
this._isTerminating = false;
|
||||
this._hostUtils = hostUtils;
|
||||
|
@ -56,7 +57,7 @@ export class ExtensionHostMain {
|
|||
|
||||
// bootstrap services
|
||||
const services = new ServiceCollection(...getSingletonServiceDescriptors());
|
||||
services.set(IExtHostInitDataService, { _serviceBrand: undefined, ...initData });
|
||||
services.set(IExtHostInitDataService, { _serviceBrand: undefined, ...initData, messagePorts });
|
||||
services.set(IExtHostRpcService, new ExtHostRpcService(this._rpcProtocol));
|
||||
services.set(IURITransformerService, new URITransformerService(uriTransformer));
|
||||
services.set(IHostUtils, hostUtils);
|
||||
|
|
|
@ -219,18 +219,24 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRenderer
|
|||
|
||||
let onTerminate = (reason: string) => nativeClose();
|
||||
|
||||
export function create(): void {
|
||||
const res = new ExtensionWorker();
|
||||
export function create(): { onmessage: (message: any) => void } {
|
||||
performance.mark(`code/extHost/willConnectToRenderer`);
|
||||
connectToRenderer(res.protocol).then(data => {
|
||||
performance.mark(`code/extHost/didWaitForInitData`);
|
||||
const extHostMain = new ExtensionHostMain(
|
||||
data.protocol,
|
||||
data.initData,
|
||||
hostUtil,
|
||||
null,
|
||||
);
|
||||
|
||||
onTerminate = (reason: string) => extHostMain.terminate(reason);
|
||||
});
|
||||
return {
|
||||
onmessage(messagePorts: ReadonlyMap<string, MessagePort>) {
|
||||
const res = new ExtensionWorker();
|
||||
connectToRenderer(res.protocol).then(data => {
|
||||
performance.mark(`code/extHost/didWaitForInitData`);
|
||||
const extHostMain = new ExtensionHostMain(
|
||||
data.protocol,
|
||||
data.initData,
|
||||
hostUtil,
|
||||
null,
|
||||
messagePorts
|
||||
);
|
||||
|
||||
onTerminate = (reason: string) => extHostMain.terminate(reason);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -337,17 +337,6 @@ interface ISettingsSyncOptions {
|
|||
enablementHandler?(enablement: boolean): void;
|
||||
}
|
||||
|
||||
export type Message = Uint8Array;
|
||||
|
||||
export interface IMessagePassingProtocol {
|
||||
readonly onDidReceiveMessage: Event<Message>;
|
||||
sendMessage(message: Message): void;
|
||||
}
|
||||
|
||||
export interface IIPCProvider {
|
||||
getMessagePassingProtocol(extensionId: string): Promise<IMessagePassingProtocol | undefined>;
|
||||
}
|
||||
|
||||
interface IWorkbenchConstructionOptions {
|
||||
|
||||
//#region Connection related configuration
|
||||
|
@ -538,7 +527,7 @@ interface IWorkbenchConstructionOptions {
|
|||
|
||||
//#region IPC
|
||||
|
||||
readonly ipcProvider?: IIPCProvider;
|
||||
readonly messagePorts?: ReadonlyMap<ExtensionId, MessagePort>;
|
||||
|
||||
//#endregion
|
||||
|
||||
|
|
11
src/vscode-dts/vscode.proposed.ipc.d.ts
vendored
11
src/vscode-dts/vscode.proposed.ipc.d.ts
vendored
|
@ -5,14 +5,7 @@
|
|||
|
||||
declare module 'vscode' {
|
||||
|
||||
export type Message = Uint8Array;
|
||||
|
||||
export interface MessagePassingProtocol {
|
||||
readonly onDidReceiveMessage: Event<Message>;
|
||||
sendMessage(message: Message): void;
|
||||
}
|
||||
|
||||
export namespace window {
|
||||
export function getMessagePassingProtocol(): Thenable<MessagePassingProtocol | undefined>;
|
||||
export interface ExtensionContext {
|
||||
readonly messagePort: MessagePort | undefined;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue