@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
JavaScript
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 };