@codingame/monaco-vscode-extensions-service-override
Version:
VSCode public API plugged on the monaco editor - extensions service-override
297 lines (294 loc) • 15.5 kB
JavaScript
import { __decorate, __param } from 'vscode/external/tslib/tslib.es6.js';
import { addDisposableListener } from 'vscode/vscode/vs/base/browser/dom';
import { parentOriginHash } from 'vscode/vscode/vs/base/browser/iframe';
import { mainWindow } from 'vscode/vscode/vs/base/browser/window';
import { Barrier } from 'vscode/vscode/vs/base/common/async';
import { VSBuffer } from 'vscode/vscode/vs/base/common/buffer';
import { onUnexpectedError, canceled } from 'vscode/vscode/vs/base/common/errors';
import { Emitter, Event } from 'vscode/vscode/vs/base/common/event';
import { Disposable, toDisposable } from 'vscode/vscode/vs/base/common/lifecycle';
import { COI, FileAccess } from 'vscode/vscode/vs/base/common/network';
import { isWeb, Language, language } from 'vscode/vscode/vs/base/common/platform';
import { joinPath } from 'vscode/vscode/vs/base/common/resources';
import { URI } from 'vscode/vscode/vs/base/common/uri';
import { generateUuid } from 'vscode/vscode/vs/base/common/uuid';
import { ILabelService } from 'vscode/vscode/vs/platform/label/common/label.service';
import { ILayoutService } from 'vscode/vscode/vs/platform/layout/browser/layoutService.service';
import { ILogService, ILoggerService } from 'vscode/vscode/vs/platform/log/common/log.service';
import { IProductService } from 'vscode/vscode/vs/platform/product/common/productService.service';
import { StorageScope, StorageTarget } from 'vscode/vscode/vs/platform/storage/common/storage';
import { IStorageService } from 'vscode/vscode/vs/platform/storage/common/storage.service';
import { ITelemetryService } from 'vscode/vscode/vs/platform/telemetry/common/telemetry.service';
import { isLoggingOnly } from 'vscode/vscode/vs/platform/telemetry/common/telemetryUtils';
import { IUserDataProfilesService } from 'vscode/vscode/vs/platform/userDataProfile/common/userDataProfile.service';
import { WorkbenchState } from 'vscode/vscode/vs/platform/workspace/common/workspace';
import { IWorkspaceContextService } from 'vscode/vscode/vs/platform/workspace/common/workspace.service';
import { IBrowserWorkbenchEnvironmentService } from 'vscode/vscode/vs/workbench/services/environment/browser/environmentService.service';
import { ExtensionHostExitCode, isMessageOfType, MessageType, createMessageOfType, UIKind } from 'vscode/vscode/vs/workbench/services/extensions/common/extensionHostProtocol';
import { ExtensionHostStartup } from 'vscode/vscode/vs/workbench/services/extensions/common/extensions';
let WebWorkerExtensionHost = class WebWorkerExtensionHost extends Disposable {
constructor(runningLocation, startup, _initDataProvider, _telemetryService, _contextService, _labelService, _logService, _loggerService, _environmentService, _userDataProfilesService, _productService, _layoutService, _storageService) {
super();
this.runningLocation = runningLocation;
this.startup = startup;
this._initDataProvider = _initDataProvider;
this._telemetryService = _telemetryService;
this._contextService = _contextService;
this._labelService = _labelService;
this._logService = _logService;
this._loggerService = _loggerService;
this._environmentService = _environmentService;
this._userDataProfilesService = _userDataProfilesService;
this._productService = _productService;
this._layoutService = _layoutService;
this._storageService = _storageService;
this.pid = null;
this.remoteAuthority = null;
this.extensions = null;
this._onDidExit = this._register(( new Emitter()));
this.onExit = this._onDidExit.event;
this._isTerminating = false;
this._protocolPromise = null;
this._protocol = null;
this._extensionHostLogsLocation = joinPath(this._environmentService.extHostLogsPath, 'webWorker');
}
async _getWebWorkerExtensionHostIframeSrc() {
const suffixSearchParams = ( new URLSearchParams());
if (this._environmentService.debugExtensionHost && this._environmentService.debugRenderer) {
suffixSearchParams.set('debugged', '1');
}
COI.addSearchParam(suffixSearchParams, true, true);
const suffix = `?${( suffixSearchParams.toString())}`;
const iframeModulePath = 'vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html';
if (isWeb) {
const webEndpointUrlTemplate = this._productService.webEndpointUrlTemplate;
const commit = this._productService.commit;
const quality = this._productService.quality;
if (webEndpointUrlTemplate && commit && quality) {
const key = 'webWorkerExtensionHostIframeStableOriginUUID';
let stableOriginUUID = this._storageService.get(key, StorageScope.WORKSPACE);
if (typeof stableOriginUUID === 'undefined') {
stableOriginUUID = generateUuid();
this._storageService.store(key, stableOriginUUID, StorageScope.WORKSPACE, StorageTarget.MACHINE);
}
const hash = await parentOriginHash(mainWindow.origin, stableOriginUUID);
const baseUrl = (webEndpointUrlTemplate
.replace('{{uuid}}', `v--${hash}`)
.replace('{{commit}}', commit)
.replace('{{quality}}', quality));
const res = ( new URL(`${baseUrl}/out/${iframeModulePath}${suffix}`));
res.searchParams.set('parentOrigin', mainWindow.origin);
res.searchParams.set('salt', stableOriginUUID);
return ( res.toString());
}
}
const relativeExtensionHostIframeSrc = ( FileAccess.asBrowserUri(iframeModulePath));
return `${( relativeExtensionHostIframeSrc.toString(true))}${suffix}`;
}
async start() {
if (!this._protocolPromise) {
this._protocolPromise = this._startInsideIframe();
this._protocolPromise.then(protocol => this._protocol = protocol);
}
return this._protocolPromise;
}
async _startInsideIframe() {
const webWorkerExtensionHostIframeSrc = await this._getWebWorkerExtensionHostIframeSrc();
const emitter = this._register(( new Emitter()));
const iframe = document.createElement('iframe');
iframe.setAttribute('class', 'web-worker-ext-host-iframe');
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
iframe.setAttribute('allow', 'usb; serial; hid; cross-origin-isolated;');
iframe.setAttribute('aria-hidden', 'true');
iframe.style.display = 'none';
const vscodeWebWorkerExtHostId = generateUuid();
iframe.setAttribute('src', `${webWorkerExtensionHostIframeSrc}&vscodeWebWorkerExtHostId=${vscodeWebWorkerExtHostId}`);
const barrier = ( new Barrier());
let port;
let barrierError = null;
let barrierHasError = false;
let startTimeout = null;
const rejectBarrier = (exitCode, error) => {
barrierError = error;
barrierHasError = true;
onUnexpectedError(barrierError);
clearTimeout(startTimeout);
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, barrierError.message]);
barrier.open();
};
const resolveBarrier = (messagePort) => {
port = messagePort;
clearTimeout(startTimeout);
barrier.open();
};
startTimeout = setTimeout(() => {
console.warn(`The Web Worker Extension Host did not start in 60s, that might be a problem.`);
}, 60000);
this._register(addDisposableListener(mainWindow, 'message', (event) => {
if (event.source !== iframe.contentWindow) {
return;
}
if (event.data.vscodeWebWorkerExtHostId !== vscodeWebWorkerExtHostId) {
return;
}
if (event.data.error) {
const { name, message, stack } = event.data.error;
const err = ( new Error());
err.message = message;
err.name = name;
err.stack = stack;
return rejectBarrier(ExtensionHostExitCode.UnexpectedError, err);
}
if (event.data.type === 'vscode.bootstrap.nls') {
const factoryModuleId = 'vs/base/worker/workerMain.js';
const baseUrl = require.toUrl(factoryModuleId).slice(0, -factoryModuleId.length);
iframe.contentWindow.postMessage({
type: event.data.type,
data: {
baseUrl,
workerUrl: require.toUrl(factoryModuleId),
nls: {
messages: globalThis._VSCODE_NLS_MESSAGES,
language: globalThis._VSCODE_NLS_LANGUAGE
}
}
}, '*');
return;
}
const { data } = event.data;
if (barrier.isOpen() || !(data instanceof MessagePort)) {
console.warn('UNEXPECTED message', event);
const err = ( new Error('UNEXPECTED message'));
return rejectBarrier(ExtensionHostExitCode.UnexpectedError, err);
}
resolveBarrier(data);
}));
this._layoutService.mainContainer.appendChild(iframe);
this._register(toDisposable(() => iframe.remove()));
await barrier.wait();
if (barrierHasError) {
throw barrierError;
}
const messagePorts = this._environmentService.options?.messagePorts ?? ( new Map());
iframe.contentWindow.postMessage({ type: 'vscode.init', data: messagePorts }, '*', [...( messagePorts.values())]);
port.onmessage = (event) => {
const { data } = event;
if (!(data instanceof ArrayBuffer)) {
console.warn('UNKNOWN data received', data);
this._onDidExit.fire([77, 'UNKNOWN data received']);
return;
}
emitter.fire(VSBuffer.wrap(( new Uint8Array(data, 0, data.byteLength))));
};
const protocol = {
onMessage: emitter.event,
send: vsbuf => {
const data = vsbuf.buffer.buffer.slice(vsbuf.buffer.byteOffset, vsbuf.buffer.byteOffset + vsbuf.buffer.byteLength);
port.postMessage(data, [data]);
}
};
return this._performHandshake(protocol);
}
async _performHandshake(protocol) {
await Event.toPromise(Event.filter(protocol.onMessage, msg => isMessageOfType(msg, MessageType.Ready)));
if (this._isTerminating) {
throw canceled();
}
protocol.send(VSBuffer.fromString(JSON.stringify(await this._createExtHostInitData())));
if (this._isTerminating) {
throw canceled();
}
await Event.toPromise(Event.filter(protocol.onMessage, msg => isMessageOfType(msg, MessageType.Initialized)));
if (this._isTerminating) {
throw canceled();
}
return protocol;
}
dispose() {
if (this._isTerminating) {
return;
}
this._isTerminating = true;
this._protocol?.send(createMessageOfType(MessageType.Terminate));
super.dispose();
}
getInspectPort() {
return undefined;
}
enableInspectPort() {
return Promise.resolve(false);
}
async _createExtHostInitData() {
const initData = await this._initDataProvider.getInitData();
this.extensions = initData.extensions;
const workspace = this._contextService.getWorkspace();
const nlsBaseUrl = this._productService.extensionsGallery?.nlsBaseUrl;
let nlsUrlWithDetails = undefined;
if (nlsBaseUrl && this._productService.commit && !Language.isDefaultVariant()) {
nlsUrlWithDetails = URI.joinPath(( URI.parse(nlsBaseUrl)), this._productService.commit, this._productService.version, Language.value());
}
return {
commit: this._productService.commit,
version: this._productService.version,
quality: this._productService.quality,
parentPid: 0,
environment: {
isExtensionDevelopmentDebug: this._environmentService.debugRenderer,
appName: this._productService.nameLong,
appHost: this._productService.embedderIdentifier ?? (isWeb ? 'web' : 'desktop'),
appUriScheme: this._productService.urlProtocol,
appLanguage: language,
extensionTelemetryLogResource: this._environmentService.extHostTelemetryLogFile,
isExtensionTelemetryLoggingOnly: isLoggingOnly(this._productService, this._environmentService),
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,
extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI,
globalStorageHome: this._userDataProfilesService.defaultProfile.globalStorageHome,
workspaceStorageHome: this._environmentService.workspaceStorageHome,
extensionLogLevel: this._environmentService.extensionLogLevel
},
workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? undefined : {
configuration: workspace.configuration || undefined,
id: workspace.id,
name: this._labelService.getWorkspaceLabel(workspace),
transient: workspace.transient
},
consoleForward: {
includeStack: false,
logNative: this._environmentService.debugRenderer
},
extensions: this.extensions.toSnapshot(),
nlsBaseUrl: nlsUrlWithDetails,
telemetryInfo: {
sessionId: this._telemetryService.sessionId,
machineId: this._telemetryService.machineId,
sqmId: this._telemetryService.sqmId,
devDeviceId: this._telemetryService.devDeviceId,
firstSessionDate: this._telemetryService.firstSessionDate,
msftInternal: this._telemetryService.msftInternal
},
logLevel: this._logService.getLevel(),
loggers: [...this._loggerService.getRegisteredLoggers()],
logsLocation: this._extensionHostLogsLocation,
autoStart: (this.startup === ExtensionHostStartup.EagerAutoStart),
remote: {
authority: this._environmentService.remoteAuthority,
connectionData: null,
isRemote: false
},
uiKind: isWeb ? UIKind.Web : UIKind.Desktop
};
}
};
WebWorkerExtensionHost = ( __decorate([
( __param(3, ITelemetryService)),
( __param(4, IWorkspaceContextService)),
( __param(5, ILabelService)),
( __param(6, ILogService)),
( __param(7, ILoggerService)),
( __param(8, IBrowserWorkbenchEnvironmentService)),
( __param(9, IUserDataProfilesService)),
( __param(10, IProductService)),
( __param(11, ILayoutService)),
( __param(12, IStorageService))
], WebWorkerExtensionHost));
export { WebWorkerExtensionHost };