wip: ipc api

This commit is contained in:
João Moreno 2021-11-23 19:46:38 +01:00
parent ee541af5df
commit 68117af61a
No known key found for this signature in database
GPG key ID: 896B853774D1A575
8 changed files with 173 additions and 2 deletions

View file

@ -74,6 +74,7 @@ import './mainThreadAuthentication';
import './mainThreadTimeline';
import './mainThreadTesting';
import './mainThreadSecretState';
import './mainThreadIPC';
export class ExtensionPoints implements IWorkbenchContribution {

View file

@ -0,0 +1,65 @@
/*---------------------------------------------------------------------------------------------
* 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();
}
}

View file

@ -92,6 +92,7 @@ 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;
@ -177,6 +178,7 @@ 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
@ -760,6 +762,10 @@ 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);
}
};

View file

@ -295,7 +295,7 @@ export interface MainThreadTextEditorsShape extends IDisposable {
}
export interface MainThreadTreeViewsShape extends IDisposable {
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean, dragAndDropMimeTypes: string[] | undefined}): Promise<void>;
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean, dragAndDropMimeTypes: string[] | undefined }): Promise<void>;
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem; }): Promise<void>;
$reveal(treeViewId: string, itemInfo: { item: ITreeItem, parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise<void>;
$setMessage(treeViewId: string, message: string): void;
@ -2195,6 +2195,17 @@ 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 = {
@ -2253,7 +2264,8 @@ export const MainContext = {
MainThreadTheming: createMainId<MainThreadThemingShape>('MainThreadTheming'),
MainThreadTunnelService: createMainId<MainThreadTunnelServiceShape>('MainThreadTunnelService'),
MainThreadTimeline: createMainId<MainThreadTimelineShape>('MainThreadTimeline'),
MainThreadTesting: createMainId<MainThreadTestingShape>('MainThreadTesting')
MainThreadTesting: createMainId<MainThreadTestingShape>('MainThreadTesting'),
MainThreadIPC: createMainId<MainThreadIPCShape>('MainThreadIPC'),
};
export const ExtHostContext = {
@ -2308,4 +2320,5 @@ export const ExtHostContext = {
ExtHostTimeline: createMainId<ExtHostTimelineShape>('ExtHostTimeline'),
ExtHostTesting: createMainId<ExtHostTestingShape>('ExtHostTesting'),
ExtHostTelemetry: createMainId<ExtHostTelemetryShape>('ExtHostTelemetry'),
ExtHostIPC: createMainId<ExtHostIPCShape>('ExtHostIPC'),
};

View file

@ -0,0 +1,49 @@
/*---------------------------------------------------------------------------------------------
* 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();
}
}

View file

@ -25,6 +25,7 @@ export const allApiProposals = Object.freeze({
fsChunks: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.fsChunks.d.ts',
inlayHints: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.inlayHints.d.ts',
inlineCompletions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.inlineCompletions.d.ts',
ipc: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.ipc.d.ts',
languageStatus: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.languageStatus.d.ts',
notebookCellExecutionState: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookCellExecutionState.d.ts',
notebookConcatTextDocument: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookConcatTextDocument.d.ts',

View file

@ -337,6 +337,17 @@ 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
@ -525,6 +536,13 @@ interface IWorkbenchConstructionOptions {
//#endregion
//#region IPC
readonly ipcProvider?: IIPCProvider;
//#endregion
//#region Development options
readonly developmentOptions?: IDevelopmentOptions;

18
src/vscode-dts/vscode.proposed.ipc.d.ts vendored Normal file
View file

@ -0,0 +1,18 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
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>;
}
}