Path: blob/main/src/vs/workbench/contrib/notebook/browser/services/notebookRendererMessagingServiceImpl.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { Emitter } from '../../../../../base/common/event.js';6import { Disposable } from '../../../../../base/common/lifecycle.js';7import { INotebookRendererMessagingService, IScopedRendererMessaging } from '../../common/notebookRendererMessagingService.js';8import { IExtensionService } from '../../../../services/extensions/common/extensions.js';910type MessageToSend = { editorId: string; rendererId: string; message: unknown };1112export class NotebookRendererMessagingService extends Disposable implements INotebookRendererMessagingService {13declare _serviceBrand: undefined;14/**15* Activation promises. Maps renderer IDs to a queue of messages that should16* be sent once activation finishes, or undefined if activation is complete.17*/18private readonly activations = new Map<string /* rendererId */, undefined | MessageToSend[]>();19private readonly scopedMessaging = new Map</* editorId */ string, IScopedRendererMessaging>();20private readonly postMessageEmitter = this._register(new Emitter<MessageToSend>());21public readonly onShouldPostMessage = this.postMessageEmitter.event;2223constructor(24@IExtensionService private readonly extensionService: IExtensionService25) {26super();27}2829/** @inheritdoc */30public receiveMessage(editorId: string | undefined, rendererId: string, message: unknown): Promise<boolean> {31if (editorId === undefined) {32const sends = [...this.scopedMessaging.values()].map(e => e.receiveMessageHandler?.(rendererId, message));33return Promise.all(sends).then(s => s.some(s => !!s));34}3536return this.scopedMessaging.get(editorId)?.receiveMessageHandler?.(rendererId, message) ?? Promise.resolve(false);37}3839/** @inheritdoc */40public prepare(rendererId: string) {41if (this.activations.has(rendererId)) {42return;43}4445const queue: MessageToSend[] = [];46this.activations.set(rendererId, queue);4748this.extensionService.activateByEvent(`onRenderer:${rendererId}`).then(() => {49for (const message of queue) {50this.postMessageEmitter.fire(message);51}5253this.activations.set(rendererId, undefined);54});55}5657/** @inheritdoc */58public getScoped(editorId: string): IScopedRendererMessaging {59const existing = this.scopedMessaging.get(editorId);60if (existing) {61return existing;62}6364const messaging: IScopedRendererMessaging = {65postMessage: (rendererId, message) => this.postMessage(editorId, rendererId, message),66dispose: () => this.scopedMessaging.delete(editorId),67};6869this.scopedMessaging.set(editorId, messaging);70return messaging;71}7273private postMessage(editorId: string, rendererId: string, message: unknown): void {74if (!this.activations.has(rendererId)) {75this.prepare(rendererId);76}7778const activation = this.activations.get(rendererId);79const toSend = { rendererId, editorId, message };80if (activation === undefined) {81this.postMessageEmitter.fire(toSend);82} else {83activation.push(toSend);84}85}86}878889