@codingame/monaco-vscode-extensions-service-override
Version:
VSCode public API plugged on the monaco editor - extensions service-override
337 lines (333 loc) • 17.9 kB
JavaScript
import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6';
import { createElement, addDisposableListener } from '@codingame/monaco-vscode-api/vscode/vs/base/browser/dom';
import { parentOriginHash } from '@codingame/monaco-vscode-api/vscode/vs/base/browser/iframe';
import { mainWindow } from '@codingame/monaco-vscode-api/vscode/vs/base/browser/window';
import { Barrier } from '@codingame/monaco-vscode-api/vscode/vs/base/common/async';
import { VSBuffer } from '@codingame/monaco-vscode-api/vscode/vs/base/common/buffer';
import { onUnexpectedError, canceled } from '@codingame/monaco-vscode-api/vscode/vs/base/common/errors';
import { Emitter, Event } from '@codingame/monaco-vscode-api/vscode/vs/base/common/event';
import { Disposable, toDisposable } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
import { COI, FileAccess } from '@codingame/monaco-vscode-api/vscode/vs/base/common/network';
import { isWeb, Language, language } from '@codingame/monaco-vscode-api/vscode/vs/base/common/platform';
import { joinPath } from '@codingame/monaco-vscode-api/vscode/vs/base/common/resources';
import { URI } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uri';
import { generateUuid } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uuid';
import { getNLSLanguage, getNLSMessages } from '@codingame/monaco-vscode-api/vscode/vs/nls';
import { ILabelService } from '@codingame/monaco-vscode-api/vscode/vs/platform/label/common/label.service';
import { ILayoutService } from '@codingame/monaco-vscode-api/vscode/vs/platform/layout/browser/layoutService.service';
import { ILogService, ILoggerService } from '@codingame/monaco-vscode-api/vscode/vs/platform/log/common/log.service';
import { IProductService } from '@codingame/monaco-vscode-api/vscode/vs/platform/product/common/productService.service';
import { StorageScope, StorageTarget } from '@codingame/monaco-vscode-api/vscode/vs/platform/storage/common/storage';
import { IStorageService } from '@codingame/monaco-vscode-api/vscode/vs/platform/storage/common/storage.service';
import { ITelemetryService } from '@codingame/monaco-vscode-api/vscode/vs/platform/telemetry/common/telemetry.service';
import { isLoggingOnly } from '@codingame/monaco-vscode-api/vscode/vs/platform/telemetry/common/telemetryUtils';
import { IUserDataProfilesService } from '@codingame/monaco-vscode-api/vscode/vs/platform/userDataProfile/common/userDataProfile.service';
import { WebWorkerDescriptor } from '@codingame/monaco-vscode-api/vscode/vs/platform/webWorker/browser/webWorkerDescriptor';
import { IWebWorkerService } from '@codingame/monaco-vscode-api/vscode/vs/platform/webWorker/browser/webWorkerService.service';
import { WorkbenchState } from '@codingame/monaco-vscode-api/vscode/vs/platform/workspace/common/workspace';
import { IWorkspaceContextService } from '@codingame/monaco-vscode-api/vscode/vs/platform/workspace/common/workspace.service';
import { IBrowserWorkbenchEnvironmentService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/environment/browser/environmentService.service';
import { IDefaultLogLevelsService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/log/common/defaultLogLevels.service';
import { ExtensionHostExitCode, isMessageOfType, MessageType, createMessageOfType, UIKind } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensions/common/extensionHostProtocol';
import { ExtensionHostStartup } from '@codingame/monaco-vscode-api/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,
_webWorkerService,
_defaultLogLevelsService
) {
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._webWorkerService = _webWorkerService;
this._defaultLogLevelsService = _defaultLogLevelsService;
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);
suffixSearchParams.set("parentOrigin", mainWindow.origin);
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("salt", stableOriginUUID);
return ( res.toString());
}
}
const relativeExtensionHostIframeSrc = this._webWorkerService.getWorkerUrl(( new WebWorkerDescriptor({
esmModuleLocation: ( FileAccess.asBrowserUri(iframeModulePath)),
esmModuleLocationBundler: ( new URL(`../worker/webWorkerExtensionHostIframe.html`, import.meta.url)),
label: "webWorkerExtensionHostIframe"
})));
return `${relativeExtensionHostIframeSrc}${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 = 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; local-network-access;");
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 = undefined;
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") {
iframe.contentWindow.postMessage({
type: event.data.type,
data: {
workerUrl: this._webWorkerService.getWorkerUrl(extensionHostWorkerMainDescriptor),
workerOptions: this._webWorkerService.getWorkerOptions(extensionHostWorkerMainDescriptor),
fileRoot: globalThis._VSCODE_FILE_ROOT,
nls: {
messages: getNLSMessages(),
language: getNLSLanguage()
}
}
}, "*");
return;
}
const {
data
} = event.data;
if (barrier.isOpen() || !(data instanceof mainWindow.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 mainWindow.ArrayBuffer)) {
console.warn("UNKNOWN data received", data);
this._onDidExit.fire([77, "UNKNOWN data received"]);
return;
}
emitter.fire(VSBuffer.wrap(new mainWindow.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,
date: this._productService.date,
parentPid: 0,
environment: {
isExtensionDevelopmentDebug: this._environmentService.debugRenderer,
appName: this._productService.nameLong,
appHost: this._productService.embedderIdentifier ?? (isWeb ? "web" : "desktop"),
appUriScheme: this._productService.urlProtocol,
appLanguage: language,
isExtensionTelemetryLoggingOnly: isLoggingOnly(this._productService, this._environmentService),
isPortable: false,
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,
extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI,
globalStorageHome: this._userDataProfilesService.defaultProfile.globalStorageHome,
workspaceStorageHome: this._environmentService.workspaceStorageHome,
extensionLogLevel: this._defaultLogLevelsService.defaultLogLevels.extensions,
isSessionsWindow: this._environmentService.isSessionsWindow
},
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 ?? this._telemetryService.machineId,
firstSessionDate: this._telemetryService.firstSessionDate,
msftInternal: this._telemetryService.msftInternal
},
remoteExtensionTips: this._productService.remoteExtensionTips,
virtualWorkspaceExtensionTips: this._productService.virtualWorkspaceExtensionTips,
logLevel: this._logService.getLevel(),
loggers: [...this._loggerService.getRegisteredLoggers()],
logsLocation: this._extensionHostLogsLocation,
autoStart: (this.startup === ExtensionHostStartup.EagerAutoStart || this.startup === ExtensionHostStartup.LazyAutoStart),
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)), ( __param(13, IWebWorkerService)), ( __param(14, IDefaultLogLevelsService))], WebWorkerExtensionHost));
const extensionHostWorkerMainDescriptor = ( new WebWorkerDescriptor({
label: "extensionHostWorkerMain"
}));
export { WebWorkerExtensionHost };