UNPKG

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

Version:

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

514 lines (511 loc) 20.7 kB
import { __decorate, __param } from 'vscode/external/tslib/tslib.es6.js'; import { IntervalTimer } from 'vscode/vscode/vs/base/common/async'; import { VSBuffer } from 'vscode/vscode/vs/base/common/buffer'; import { onUnexpectedError } from 'vscode/vscode/vs/base/common/errors'; import { Emitter } from 'vscode/vscode/vs/base/common/event'; import { Disposable } from 'vscode/vscode/vs/base/common/lifecycle'; import { StopWatch } from 'vscode/vscode/vs/base/common/stopwatch'; import { localize2 } from 'vscode/vscode/vs/nls'; import { Categories } from 'vscode/vscode/vs/platform/action/common/actionCommonCategories'; import { registerAction2, Action2 } from 'vscode/vscode/vs/platform/actions/common/actions'; import { IInstantiationService } from 'vscode/vscode/vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vscode/vscode/vs/platform/log/common/log.service'; import { getRemoteAuthorityPrefix, RemoteAuthorityResolverErrorCode } from 'vscode/vscode/vs/platform/remote/common/remoteAuthorityResolver'; import { ITelemetryService } from 'vscode/vscode/vs/platform/telemetry/common/telemetry.service'; import { IEditorService } from 'vscode/vscode/vs/workbench/services/editor/common/editorService.service'; import { IWorkbenchEnvironmentService } from 'vscode/vscode/vs/workbench/services/environment/common/environmentService.service'; import { ExtHostCustomersRegistry } from './extHostCustomers.js'; import { extensionHostKindToString } from 'vscode/vscode/vs/workbench/services/extensions/common/extensionHostKind'; import { ActivationKind } from 'vscode/vscode/vs/workbench/services/extensions/common/extensions'; import { RPCProtocol, RequestInitiator } from 'vscode/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) => { this._hasStarted = true; 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(() => { initialActivationEvents.forEach((activationEvent) => this.activateByEvent(activationEvent, ActivationKind.Normal)); this._register(registerLatencyTestProvider({ measure: () => this.measure() })); }); } dispose() { if (this._extensionHost) { this._extensionHost.dispose(); } if (this._rpcProtocol) { 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 }; } 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 (activationKind === ActivationKind.Immediate && !this._hasStarted) { return Promise.resolve(); } 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 \u2192 Win', this._totalIncoming, msgLength, req, initiator, str, data); } logOutgoing(msgLength, req, initiator, str, data) { this._totalOutgoing += msgLength; this._log('Win \u2192 Ext', this._totalOutgoing, msgLength, req, initiator, str, data); } } let TelemetryRPCLogger = class TelemetryRPCLogger { static isEnabled() { return Math.trunc(Math.random() * 1000) < 0.5; } 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(4824, "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 };