UNPKG

@codingame/monaco-vscode-extensions-service-override

Version:

VSCode public API plugged on the monaco editor - extensions service-override

522 lines (518 loc) 21.1 kB
import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6'; import { IntervalTimer } from '@codingame/monaco-vscode-api/vscode/vs/base/common/async'; import { VSBuffer } from '@codingame/monaco-vscode-api/vscode/vs/base/common/buffer'; import { onUnexpectedError } from '@codingame/monaco-vscode-api/vscode/vs/base/common/errors'; import { Emitter } from '@codingame/monaco-vscode-api/vscode/vs/base/common/event'; import { Disposable } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle'; import { StopWatch } from '@codingame/monaco-vscode-api/vscode/vs/base/common/stopwatch'; import { localize2 } from '@codingame/monaco-vscode-api/vscode/vs/nls'; import { Categories } from '@codingame/monaco-vscode-api/vscode/vs/platform/action/common/actionCommonCategories'; import { registerAction2, Action2 } from '@codingame/monaco-vscode-api/vscode/vs/platform/actions/common/actions'; import { IInstantiationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/instantiation'; import { ILogService } from '@codingame/monaco-vscode-api/vscode/vs/platform/log/common/log.service'; import { getRemoteAuthorityPrefix, RemoteAuthorityResolverErrorCode } from '@codingame/monaco-vscode-api/vscode/vs/platform/remote/common/remoteAuthorityResolver'; import { ITelemetryService } from '@codingame/monaco-vscode-api/vscode/vs/platform/telemetry/common/telemetry.service'; import { IEditorService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/editor/common/editorService.service'; import { IWorkbenchEnvironmentService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/environment/common/environmentService.service'; import { ExtHostCustomersRegistry } from './extHostCustomers.js'; import { extensionHostKindToString } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensions/common/extensionHostKind'; import { ActivationKind } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensions/common/extensions'; import { RPCProtocol, RequestInitiator } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensions/common/rpcProtocol'; var ExtensionHostManager_1; let ExtensionHostManager = ExtensionHostManager_1 = class ExtensionHostManager extends Disposable { get pid() { return this._extensionHost.pid; } get kind() { return this._extensionHost.runningLocation.kind; } get startup() { return this._extensionHost.startup; } get friendyName() { return friendlyExtHostName(this.kind, this.pid); } constructor( extensionHost, initialActivationEvents, _internalExtensionService, _instantiationService, _environmentService, _telemetryService, _logService ) { super(); this._internalExtensionService = _internalExtensionService; this._instantiationService = _instantiationService; this._environmentService = _environmentService; this._telemetryService = _telemetryService; this._logService = _logService; this._onDidChangeResponsiveState = this._register(( new Emitter())); this.onDidChangeResponsiveState = this._onDidChangeResponsiveState.event; this._hasStarted = false; this._cachedActivationEvents = ( new Map()); this._resolvedActivationEvents = ( new Set()); this._rpcProtocol = null; this._customers = []; this._extensionHost = extensionHost; this.onDidExit = this._extensionHost.onExit; const startingTelemetryEvent = { time: Date.now(), action: "starting", kind: extensionHostKindToString(this.kind) }; this._telemetryService.publicLog2("extensionHostStartup", startingTelemetryEvent); this._proxy = this._extensionHost.start().then(protocol => { const successTelemetryEvent = { time: Date.now(), action: "success", kind: extensionHostKindToString(this.kind) }; this._telemetryService.publicLog2("extensionHostStartup", successTelemetryEvent); return this._createExtensionHostCustomers(this.kind, protocol); }, err => { this._logService.error( `Error received from starting extension host (kind: ${extensionHostKindToString(this.kind)})` ); this._logService.error(err); const failureTelemetryEvent = { time: Date.now(), action: "error", kind: extensionHostKindToString(this.kind) }; if (err && err.name) { failureTelemetryEvent.errorName = err.name; } if (err && err.message) { failureTelemetryEvent.errorMessage = err.message; } if (err && err.stack) { failureTelemetryEvent.errorStack = err.stack; } this._telemetryService.publicLog2("extensionHostStartup", failureTelemetryEvent); return null; }); this._proxy.then(() => { this._hasStarted = true; initialActivationEvents.forEach( activationEvent => this.activateByEvent(activationEvent, ActivationKind.Normal) ); this._register(registerLatencyTestProvider({ measure: () => this.measure() })); }); } async disconnect() { await this._extensionHost?.disconnect?.(); } dispose() { this._extensionHost?.dispose(); this._rpcProtocol?.dispose(); for (let i = 0, len = this._customers.length; i < len; i++) { const customer = this._customers[i]; try { customer.dispose(); } catch (err) { onUnexpectedError(err); } } this._proxy = null; super.dispose(); } async measure() { const proxy = await this._proxy; if (!proxy) { return null; } const latency = await this._measureLatency(proxy); const down = await this._measureDown(proxy); const up = await this._measureUp(proxy); return { remoteAuthority: this._extensionHost.remoteAuthority, latency, down, up }; } get isReady() { return this._hasStarted; } async ready() { await this._proxy; } async _measureLatency(proxy) { const COUNT = 10; let sum = 0; for (let i = 0; i < COUNT; i++) { const sw = StopWatch.create(); await proxy.test_latency(i); sw.stop(); sum += sw.elapsed(); } return (sum / COUNT); } static _convert(byteCount, elapsedMillis) { return (byteCount * 1000 * 8) / elapsedMillis; } async _measureUp(proxy) { const SIZE = 10 * 1024 * 1024; const buff = VSBuffer.alloc(SIZE); const value = Math.ceil(Math.random() * 256); for (let i = 0; i < buff.byteLength; i++) { buff.writeUInt8(i, value); } const sw = StopWatch.create(); await proxy.test_up(buff); sw.stop(); return ExtensionHostManager_1._convert(SIZE, sw.elapsed()); } async _measureDown(proxy) { const SIZE = 10 * 1024 * 1024; const sw = StopWatch.create(); await proxy.test_down(SIZE); sw.stop(); return ExtensionHostManager_1._convert(SIZE, sw.elapsed()); } _createExtensionHostCustomers(kind, protocol) { let logger = null; if (this._environmentService.logExtensionHostCommunication) { logger = ( new RPCLogger(kind)); } else if (TelemetryRPCLogger.isEnabled()) { logger = ( new TelemetryRPCLogger(this._telemetryService)); } this._rpcProtocol = ( new RPCProtocol(protocol, logger)); this._register( this._rpcProtocol.onDidChangeResponsiveState(responsiveState => this._onDidChangeResponsiveState.fire(responsiveState)) ); let extensionHostProxy = null; let mainProxyIdentifiers = []; const extHostContext = { remoteAuthority: this._extensionHost.remoteAuthority, extensionHostKind: this.kind, getProxy: identifier => ( this._rpcProtocol.getProxy(identifier)), set: (identifier, instance) => this._rpcProtocol.set(identifier, instance), dispose: () => this._rpcProtocol.dispose(), assertRegistered: identifiers => this._rpcProtocol.assertRegistered(identifiers), drain: () => this._rpcProtocol.drain(), internalExtensionService: this._internalExtensionService, _setExtensionHostProxy: value => { extensionHostProxy = value; }, _setAllMainProxyIdentifiers: value => { mainProxyIdentifiers = value; } }; const namedCustomers = ExtHostCustomersRegistry.getNamedCustomers(); for (let i = 0, len = namedCustomers.length; i < len; i++) { const [id, ctor] = namedCustomers[i]; try { const instance = this._instantiationService.createInstance(ctor, extHostContext); this._customers.push(instance); this._rpcProtocol.set(id, instance); } catch (err) { this._logService.error(`Cannot instantiate named customer: '${id.sid}'`); this._logService.error(err); onUnexpectedError(err); } } const customers = ExtHostCustomersRegistry.getCustomers(); for (const ctor of customers) { try { const instance = this._instantiationService.createInstance(ctor, extHostContext); this._customers.push(instance); } catch (err) { this._logService.error(err); onUnexpectedError(err); } } if (!extensionHostProxy) { throw ( new Error(`Missing IExtensionHostProxy!`)); } this._rpcProtocol.assertRegistered(mainProxyIdentifiers); return extensionHostProxy; } async activate(extension, reason) { const proxy = await this._proxy; if (!proxy) { return false; } return proxy.activate(extension, reason); } activateByEvent(activationEvent, activationKind) { if (!( this._cachedActivationEvents.has(activationEvent))) { this._cachedActivationEvents.set(activationEvent, this._activateByEvent(activationEvent, activationKind)); } return this._cachedActivationEvents.get(activationEvent); } activationEventIsDone(activationEvent) { return ( this._resolvedActivationEvents.has(activationEvent)); } async _activateByEvent(activationEvent, activationKind) { if (!this._proxy) { return; } const proxy = await this._proxy; if (!proxy) { return; } if (!this._extensionHost.extensions.containsActivationEvent(activationEvent)) { this._resolvedActivationEvents.add(activationEvent); return; } await proxy.activateByEvent(activationEvent, activationKind); this._resolvedActivationEvents.add(activationEvent); } async getInspectPort(tryEnableInspector) { if (this._extensionHost) { if (tryEnableInspector) { await this._extensionHost.enableInspectPort(); } const port = this._extensionHost.getInspectPort(); if (port) { return port; } } return undefined; } async resolveAuthority(remoteAuthority, resolveAttempt) { const sw = StopWatch.create(false); const prefix = () => `[${extensionHostKindToString(this._extensionHost.runningLocation.kind)}${this._extensionHost.runningLocation.affinity}][resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)},${resolveAttempt})][${sw.elapsed()}ms] `; const logInfo = msg => this._logService.info(`${prefix()}${msg}`); const logError = (msg, err = undefined) => this._logService.error(`${prefix()}${msg}`, err); logInfo(`obtaining proxy...`); const proxy = await this._proxy; if (!proxy) { logError(`no proxy`); return { type: "error", error: { message: `Cannot resolve authority`, code: RemoteAuthorityResolverErrorCode.Unknown, detail: undefined } }; } logInfo(`invoking...`); const intervalLogger = ( new IntervalTimer()); try { intervalLogger.cancelAndSet(() => logInfo("waiting..."), 1000); const resolverResult = await proxy.resolveAuthority(remoteAuthority, resolveAttempt); intervalLogger.dispose(); if (resolverResult.type === "ok") { logInfo(`returned ${resolverResult.value.authority.connectTo}`); } else { logError(`returned an error`, resolverResult.error); } return resolverResult; } catch (err) { intervalLogger.dispose(); logError(`returned an error`, err); return { type: "error", error: { message: err.message, code: RemoteAuthorityResolverErrorCode.Unknown, detail: err } }; } } async getCanonicalURI(remoteAuthority, uri) { const proxy = await this._proxy; if (!proxy) { throw ( new Error(`Cannot resolve canonical URI`)); } return proxy.getCanonicalURI(remoteAuthority, uri); } async start(extensionRegistryVersionId, allExtensions, myExtensions) { const proxy = await this._proxy; if (!proxy) { return; } const deltaExtensions = this._extensionHost.extensions.set(extensionRegistryVersionId, allExtensions, myExtensions); return proxy.startExtensionHost(deltaExtensions); } async extensionTestsExecute() { const proxy = await this._proxy; if (!proxy) { throw ( new Error("Could not obtain Extension Host Proxy")); } return proxy.extensionTestsExecute(); } representsRunningLocation(runningLocation) { return this._extensionHost.runningLocation.equals(runningLocation); } async deltaExtensions(incomingExtensionsDelta) { const proxy = await this._proxy; if (!proxy) { return; } const outgoingExtensionsDelta = this._extensionHost.extensions.delta(incomingExtensionsDelta); if (!outgoingExtensionsDelta) { return; } return proxy.deltaExtensions(outgoingExtensionsDelta); } containsExtension(extensionId) { return this._extensionHost.extensions?.containsExtension(extensionId) ?? false; } async setRemoteEnvironment(env) { const proxy = await this._proxy; if (!proxy) { return; } return proxy.setRemoteEnvironment(env); } }; ExtensionHostManager = ExtensionHostManager_1 = ( __decorate([( __param(3, IInstantiationService)), ( __param(4, IWorkbenchEnvironmentService)), ( __param(5, ITelemetryService)), ( __param(6, ILogService))], ExtensionHostManager)); function friendlyExtHostName(kind, pid) { if (pid) { return `${extensionHostKindToString(kind)} pid: ${pid}`; } return `${extensionHostKindToString(kind)}`; } const colorTables = [ ["#2977B1", "#FC802D", "#34A13A", "#D3282F", "#9366BA"], ["#8B564C", "#E177C0", "#7F7F7F", "#BBBE3D", "#2EBECD"] ]; function prettyWithoutArrays(data) { if (Array.isArray(data)) { return data; } if (data && typeof data === "object" && typeof data.toString === "function") { const result = ( data.toString()); if (result !== "[object Object]") { return result; } } return data; } function pretty(data) { if (Array.isArray(data)) { return ( data.map(prettyWithoutArrays)); } return prettyWithoutArrays(data); } class RPCLogger { constructor(_kind) { this._kind = _kind; this._totalIncoming = 0; this._totalOutgoing = 0; } _log(direction, totalLength, msgLength, req, initiator, str, data) { data = pretty(data); const colorTable = colorTables[initiator]; const color = colorTable[req % colorTable.length] ; let args = [ `%c[${extensionHostKindToString(this._kind)}][${direction}]%c[${String(totalLength).padStart(7)}]%c[len: ${String(msgLength).padStart(5)}]%c${String(req).padStart(5)} - ${str}`, "color: darkgreen", "color: grey", "color: grey", `color: ${color}` ]; if (/\($/.test(str)) { args = args.concat(data); args.push(")"); } else { args.push(data); } console.log.apply(console, args); } logIncoming(msgLength, req, initiator, str, data) { this._totalIncoming += msgLength; this._log("Ext → Win", this._totalIncoming, msgLength, req, initiator, str, data); } logOutgoing(msgLength, req, initiator, str, data) { this._totalOutgoing += msgLength; this._log("Win → Ext", this._totalOutgoing, msgLength, req, initiator, str, data); } } let TelemetryRPCLogger = class TelemetryRPCLogger { static isEnabled() { return Math.random() < 0.0001; } constructor(_telemetryService) { this._telemetryService = _telemetryService; this._pendingRequests = ( new Map()); } logIncoming(msgLength, req, initiator, str) { if (initiator === RequestInitiator.LocalSide && /^receiveReply(Err)?:/.test(str)) { const requestStr = this._pendingRequests.get(req) ?? "unknown_reply"; this._pendingRequests.delete(req); this._telemetryService.publicLog2("extensionhost.incoming", { type: `${str} ${requestStr}`, length: msgLength }); } if (initiator === RequestInitiator.OtherSide && /^receiveRequest /.test(str)) { this._telemetryService.publicLog2("extensionhost.incoming", { type: `${str}`, length: msgLength }); } } logOutgoing(msgLength, req, initiator, str) { if (initiator === RequestInitiator.LocalSide && str.startsWith("request: ")) { this._pendingRequests.set(req, str); this._telemetryService.publicLog2("extensionhost.outgoing", { type: str, length: msgLength }); } } }; TelemetryRPCLogger = ( __decorate([( __param(0, ITelemetryService))], TelemetryRPCLogger)); const providers = []; function registerLatencyTestProvider(provider) { providers.push(provider); return { dispose: () => { for (let i = 0; i < providers.length; i++) { if (providers[i] === provider) { providers.splice(i, 1); return; } } } }; } function getLatencyTestProviders() { return providers.slice(0); } registerAction2(class MeasureExtHostLatencyAction extends Action2 { constructor() { super({ id: "editor.action.measureExtHostLatency", title: ( localize2(16643, "Measure Extension Host Latency")), category: Categories.Developer, f1: true }); } async run(accessor) { const editorService = accessor.get(IEditorService); const measurements = await Promise.all(( getLatencyTestProviders().map(provider => provider.measure()))); editorService.openEditor({ resource: undefined, contents: ( measurements.map(MeasureExtHostLatencyAction._print)).join("\n\n"), options: { pinned: true } }); } static _print(m) { if (!m) { return ""; } return `${m.remoteAuthority ? `Authority: ${m.remoteAuthority}\n` : ``}Roundtrip latency: ${m.latency.toFixed(3)}ms\nUp: ${MeasureExtHostLatencyAction._printSpeed(m.up)}\nDown: ${MeasureExtHostLatencyAction._printSpeed(m.down)}\n`; } static _printSpeed(n) { if (n <= 1024) { return `${n} bps`; } if (n < 1024 * 1024) { return `${(n / 1024).toFixed(1)} kbps`; } return `${(n / 1024 / 1024).toFixed(1)} Mbps`; } }); export { ExtensionHostManager, friendlyExtHostName };