ensureNoDisposablesAreLeakedInTestSuite: ipc (#192570)

* ensureNoDisposablesAreLeakedInTestSuite: ipc

related to #190503

* debt - proxy services need to ask for disposables

---------

Co-authored-by: Benjamin Pasero <benjamin.pasero@microsoft.com>
This commit is contained in:
João Moreno
2023-09-11 21:01:46 +02:00
committed by GitHub
parent be6c6b7d3c
commit 39de20e8a3
7 changed files with 118 additions and 84 deletions
+12 -1
View File
@@ -394,7 +394,7 @@ export namespace Event {
* this.onInstallExtension = Event.buffer(service.onInstallExtension, true);
* ```
*/
export function buffer<T>(event: Event<T>, flushAfterTimeout = false, _buffer: T[] = []): Event<T> {
export function buffer<T>(event: Event<T>, flushAfterTimeout = false, _buffer: T[] = [], disposable?: DisposableStore): Event<T> {
let buffer: T[] | null = _buffer.slice();
let listener: IDisposable | null = event(e => {
@@ -405,6 +405,10 @@ export namespace Event {
}
});
if (disposable) {
disposable.add(listener);
}
const flush = () => {
buffer?.forEach(e => emitter.fire(e));
buffer = null;
@@ -414,6 +418,9 @@ export namespace Event {
onWillAddFirstListener() {
if (!listener) {
listener = event(e => emitter.fire(e));
if (disposable) {
disposable.add(listener);
}
}
},
@@ -435,6 +442,10 @@ export namespace Event {
}
});
if (disposable) {
disposable.add(emitter);
}
return emitter.event;
}
/**
+29 -16
View File
@@ -427,7 +427,6 @@ export class ChannelServer<TContext = string> implements IChannelServer<TContext
promise.then(data => {
this.sendResponse(<IRawResponse>{ id, data, type: ResponseType.PromiseSuccess });
this.activeRequests.delete(request.id);
}, err => {
if (err instanceof Error) {
this.sendResponse(<IRawResponse>{
@@ -440,7 +439,8 @@ export class ChannelServer<TContext = string> implements IChannelServer<TContext
} else {
this.sendResponse(<IRawResponse>{ id, data: err, type: ResponseType.PromiseErrorObj });
}
}).finally(() => {
disposable.dispose();
this.activeRequests.delete(request.id);
});
@@ -639,7 +639,10 @@ export class ChannelClient implements IChannelClient, IDisposable {
this.activeRequests.add(disposable);
});
return result.finally(() => { this.activeRequests.delete(disposable); });
return result.finally(() => {
disposable.dispose();
this.activeRequests.delete(disposable);
});
}
private requestEvent(channelName: string, name: string, arg?: any): Event<any> {
@@ -795,6 +798,8 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
private readonly _onDidRemoveConnection = new Emitter<Connection<TContext>>();
readonly onDidRemoveConnection: Event<Connection<TContext>> = this._onDidRemoveConnection.event;
private disposables = new DisposableStore();
get connections(): Connection<TContext>[] {
const result: Connection<TContext>[] = [];
this._connections.forEach(ctx => result.push(ctx));
@@ -802,10 +807,10 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
}
constructor(onDidClientConnect: Event<ClientConnectionEvent>) {
onDidClientConnect(({ protocol, onDidClientDisconnect }) => {
this.disposables.add(onDidClientConnect(({ protocol, onDidClientDisconnect }) => {
const onFirstMessage = Event.once(protocol.onMessage);
onFirstMessage(msg => {
this.disposables.add(onFirstMessage(msg => {
const reader = new BufferReader(msg);
const ctx = deserialize(reader) as TContext;
@@ -818,14 +823,14 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
this._connections.add(connection);
this._onDidAddConnection.fire(connection);
onDidClientDisconnect(() => {
this.disposables.add(onDidClientDisconnect(() => {
channelServer.dispose();
channelClient.dispose();
this._connections.delete(connection);
this._onDidRemoveConnection.fire(connection);
});
});
});
}));
}));
}));
}
/**
@@ -879,7 +884,7 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
private getMulticastEvent<T extends IChannel>(channelName: string, clientFilter: (client: Client<TContext>) => boolean, eventName: string, arg: any): Event<T> {
const that = this;
let disposables = new DisposableStore();
let disposables: DisposableStore | undefined;
// Create an emitter which hooks up to all clients
// as soon as first listener is added. It also
@@ -922,7 +927,8 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
disposables.add(eventMultiplexer);
},
onDidRemoveLastListener: () => {
disposables.dispose();
disposables?.dispose();
disposables = undefined;
}
});
@@ -932,14 +938,21 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
registerChannel(channelName: string, channel: IServerChannel<TContext>): void {
this.channels.set(channelName, channel);
this._connections.forEach(connection => {
for (const connection of this._connections) {
connection.channelServer.registerChannel(channelName, channel);
});
}
}
dispose(): void {
this.channels.clear();
this.disposables.dispose();
for (const connection of this._connections) {
connection.channelClient.dispose();
connection.channelServer.dispose();
}
this._connections.clear();
this.channels.clear();
this._onDidAddConnection.dispose();
this._onDidRemoveConnection.dispose();
}
@@ -1074,7 +1087,7 @@ export namespace ProxyChannel {
export interface ICreateServiceChannelOptions extends IProxyOptions { }
export function fromService<TContext>(service: unknown, options?: ICreateServiceChannelOptions): IServerChannel<TContext> {
export function fromService<TContext>(service: unknown, disposables: DisposableStore, options?: ICreateServiceChannelOptions): IServerChannel<TContext> {
const handler = service as { [key: string]: unknown };
const disableMarshalling = options && options.disableMarshalling;
@@ -1083,7 +1096,7 @@ export namespace ProxyChannel {
const mapEventNameToEvent = new Map<string, Event<unknown>>();
for (const key in handler) {
if (propertyIsEvent(key)) {
mapEventNameToEvent.set(key, Event.buffer(handler[key] as Event<unknown>, true));
mapEventNameToEvent.set(key, Event.buffer(handler[key] as Event<unknown>, true, undefined, disposables));
}
}
+40 -38
View File
@@ -9,9 +9,11 @@ import { VSBuffer } from 'vs/base/common/buffer';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { canceled } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { isEqual } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { BufferReader, BufferWriter, ClientConnectionEvent, deserialize, IChannel, IMessagePassingProtocol, IPCClient, IPCServer, IServerChannel, ProxyChannel, serialize } from 'vs/base/parts/ipc/common/ipc';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
class QueueProtocol implements IMessagePassingProtocol {
@@ -111,6 +113,8 @@ interface ITestService {
class TestService implements ITestService {
private disposables = new DisposableStore();
private readonly _onPong = new Emitter<string>();
readonly onPong = this._onPong.event;
@@ -131,7 +135,7 @@ class TestService implements ITestService {
return Promise.reject(canceled());
}
return new Promise((_, e) => cancellationToken.onCancellationRequested(() => e(canceled())));
return new Promise((_, e) => this.disposables.add(cancellationToken.onCancellationRequested(() => e(canceled()))));
}
buffersLength(buffers: VSBuffer[]): Promise<number> {
@@ -149,6 +153,10 @@ class TestService implements ITestService {
context(context?: unknown): Promise<unknown> {
return Promise.resolve(context);
}
dispose() {
this.disposables.dispose();
}
}
class TestChannel implements IServerChannel {
@@ -213,6 +221,8 @@ class TestChannelClient implements ITestService {
suite('Base IPC', function () {
const store = ensureNoDisposablesAreLeakedInTestSuite();
test('createProtocolPair', async function () {
const [clientProtocol, serverProtocol] = createProtocolPair();
@@ -236,21 +246,16 @@ suite('Base IPC', function () {
let ipcService: ITestService;
setup(function () {
service = new TestService();
const testServer = new TestIPCServer();
service = store.add(new TestService());
const testServer = store.add(new TestIPCServer());
server = testServer;
server.registerChannel(TestChannelId, new TestChannel(service));
client = testServer.createConnection('client1');
client = store.add(testServer.createConnection('client1'));
ipcService = new TestChannelClient(client.getChannel(TestChannelId));
});
teardown(function () {
client.dispose();
server.dispose();
});
test('call success', async function () {
const r = await ipcService.marco();
return assert.strictEqual(r, 'polo');
@@ -301,7 +306,7 @@ suite('Base IPC', function () {
test('listen to events', async function () {
const messages: string[] = [];
ipcService.onPong(msg => messages.push(msg));
store.add(ipcService.onPong(msg => messages.push(msg)));
await timeout(0);
assert.deepStrictEqual(messages, []);
@@ -343,20 +348,21 @@ suite('Base IPC', function () {
let service: TestService;
let ipcService: ITestService;
const disposables = new DisposableStore();
setup(function () {
service = new TestService();
const testServer = new TestIPCServer();
service = store.add(new TestService());
const testServer = disposables.add(new TestIPCServer());
server = testServer;
server.registerChannel(TestChannelId, ProxyChannel.fromService(service));
server.registerChannel(TestChannelId, ProxyChannel.fromService(service, disposables));
client = testServer.createConnection('client1');
client = disposables.add(testServer.createConnection('client1'));
ipcService = ProxyChannel.toService(client.getChannel(TestChannelId));
});
teardown(function () {
client.dispose();
server.dispose();
disposables.clear();
});
test('call success', async function () {
@@ -376,7 +382,7 @@ suite('Base IPC', function () {
test('listen to events', async function () {
const messages: string[] = [];
ipcService.onPong(msg => messages.push(msg));
disposables.add(ipcService.onPong(msg => messages.push(msg)));
await timeout(0);
assert.deepStrictEqual(messages, []);
@@ -409,20 +415,21 @@ suite('Base IPC', function () {
let service: TestService;
let ipcService: ITestService;
const disposables = new DisposableStore();
setup(function () {
service = new TestService();
const testServer = new TestIPCServer();
service = store.add(new TestService());
const testServer = disposables.add(new TestIPCServer());
server = testServer;
server.registerChannel(TestChannelId, ProxyChannel.fromService(service));
server.registerChannel(TestChannelId, ProxyChannel.fromService(service, disposables));
client = testServer.createConnection('client1');
client = disposables.add(testServer.createConnection('client1'));
ipcService = ProxyChannel.toService(client.getChannel(TestChannelId), { context: 'Super Context' });
});
teardown(function () {
client.dispose();
server.dispose();
disposables.clear();
});
test('call extra context', async function () {
@@ -433,20 +440,20 @@ suite('Base IPC', function () {
suite('one to many', function () {
test('all clients get pinged', async function () {
const service = new TestService();
const service = store.add(new TestService());
const channel = new TestChannel(service);
const server = new TestIPCServer();
const server = store.add(new TestIPCServer());
server.registerChannel('channel', channel);
let client1GotPinged = false;
const client1 = server.createConnection('client1');
const client1 = store.add(server.createConnection('client1'));
const ipcService1 = new TestChannelClient(client1.getChannel('channel'));
ipcService1.onPong(() => client1GotPinged = true);
store.add(ipcService1.onPong(() => client1GotPinged = true));
let client2GotPinged = false;
const client2 = server.createConnection('client2');
const client2 = store.add(server.createConnection('client2'));
const ipcService2 = new TestChannelClient(client2.getChannel('channel'));
ipcService2.onPong(() => client2GotPinged = true);
store.add(ipcService2.onPong(() => client2GotPinged = true));
await timeout(1);
service.ping('hello');
@@ -454,24 +461,20 @@ suite('Base IPC', function () {
await timeout(1);
assert(client1GotPinged, 'client 1 got pinged');
assert(client2GotPinged, 'client 2 got pinged');
client1.dispose();
client2.dispose();
server.dispose();
});
test('server gets pings from all clients (broadcast channel)', async function () {
const server = new TestIPCServer();
const server = store.add(new TestIPCServer());
const client1 = server.createConnection('client1');
const clientService1 = new TestService();
const clientService1 = store.add(new TestService());
const clientChannel1 = new TestChannel(clientService1);
client1.registerChannel('channel', clientChannel1);
const pings: string[] = [];
const channel = server.getChannel('channel', () => true);
const service = new TestChannelClient(channel);
service.onPong(msg => pings.push(msg));
store.add(service.onPong(msg => pings.push(msg)));
await timeout(1);
clientService1.ping('hello 1');
@@ -480,7 +483,7 @@ suite('Base IPC', function () {
assert.deepStrictEqual(pings, ['hello 1']);
const client2 = server.createConnection('client2');
const clientService2 = new TestService();
const clientService2 = store.add(new TestService());
const clientChannel2 = new TestChannel(clientService2);
client2.registerChannel('channel', clientChannel2);
@@ -503,7 +506,6 @@ suite('Base IPC', function () {
assert.deepStrictEqual(pings, ['hello 1', 'hello 2', 'hello again 2']);
client2.dispose();
server.dispose();
});
});
});
+20 -18
View File
@@ -14,7 +14,7 @@ import { isEqualOrParent } from 'vs/base/common/extpath';
import { once } from 'vs/base/common/functional';
import { stripComments } from 'vs/base/common/json';
import { getPathLabel } from 'vs/base/common/labels';
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { isAbsolute, join, posix } from 'vs/base/common/path';
import { IProcessEnvironment, isLinux, isLinuxSnap, isMacintosh, isWindows, OS } from 'vs/base/common/platform';
@@ -1051,10 +1051,12 @@ export class CodeApplication extends Disposable {
// can talk to the first instance. Electron IPC does not work
// across apps until `requestSingleInstance` APIs are adopted.
const launchChannel = ProxyChannel.fromService(accessor.get(ILaunchMainService), { disableMarshalling: true });
const disposables = this._register(new DisposableStore());
const launchChannel = ProxyChannel.fromService(accessor.get(ILaunchMainService), disposables, { disableMarshalling: true });
this.mainProcessNodeIpcServer.registerChannel('launch', launchChannel);
const diagnosticsChannel = ProxyChannel.fromService(accessor.get(IDiagnosticsMainService), { disableMarshalling: true });
const diagnosticsChannel = ProxyChannel.fromService(accessor.get(IDiagnosticsMainService), disposables, { disableMarshalling: true });
this.mainProcessNodeIpcServer.registerChannel('diagnostics', diagnosticsChannel);
// Policies (main & shared process)
@@ -1070,7 +1072,7 @@ export class CodeApplication extends Disposable {
sharedProcessClient.then(client => client.registerChannel(LOCAL_FILE_SYSTEM_CHANNEL_NAME, fileSystemProviderChannel));
// User Data Profiles
const userDataProfilesService = ProxyChannel.fromService(accessor.get(IUserDataProfilesMainService));
const userDataProfilesService = ProxyChannel.fromService(accessor.get(IUserDataProfilesMainService), disposables);
mainProcessElectronServer.registerChannel('userDataProfiles', userDataProfilesService);
sharedProcessClient.then(client => client.registerChannel('userDataProfiles', userDataProfilesService));
@@ -1083,45 +1085,45 @@ export class CodeApplication extends Disposable {
mainProcessElectronServer.registerChannel('update', updateChannel);
// Issues
const issueChannel = ProxyChannel.fromService(accessor.get(IIssueMainService));
const issueChannel = ProxyChannel.fromService(accessor.get(IIssueMainService), disposables);
mainProcessElectronServer.registerChannel('issue', issueChannel);
// Encryption
const encryptionChannel = ProxyChannel.fromService(accessor.get(IEncryptionMainService));
const encryptionChannel = ProxyChannel.fromService(accessor.get(IEncryptionMainService), disposables);
mainProcessElectronServer.registerChannel('encryption', encryptionChannel);
// Signing
const signChannel = ProxyChannel.fromService(accessor.get(ISignService));
const signChannel = ProxyChannel.fromService(accessor.get(ISignService), disposables);
mainProcessElectronServer.registerChannel('sign', signChannel);
// Keyboard Layout
const keyboardLayoutChannel = ProxyChannel.fromService(accessor.get(IKeyboardLayoutMainService));
const keyboardLayoutChannel = ProxyChannel.fromService(accessor.get(IKeyboardLayoutMainService), disposables);
mainProcessElectronServer.registerChannel('keyboardLayout', keyboardLayoutChannel);
// Native host (main & shared process)
this.nativeHostMainService = accessor.get(INativeHostMainService);
const nativeHostChannel = ProxyChannel.fromService(this.nativeHostMainService);
const nativeHostChannel = ProxyChannel.fromService(this.nativeHostMainService, disposables);
mainProcessElectronServer.registerChannel('nativeHost', nativeHostChannel);
sharedProcessClient.then(client => client.registerChannel('nativeHost', nativeHostChannel));
// Workspaces
const workspacesChannel = ProxyChannel.fromService(accessor.get(IWorkspacesService));
const workspacesChannel = ProxyChannel.fromService(accessor.get(IWorkspacesService), disposables);
mainProcessElectronServer.registerChannel('workspaces', workspacesChannel);
// Menubar
const menubarChannel = ProxyChannel.fromService(accessor.get(IMenubarMainService));
const menubarChannel = ProxyChannel.fromService(accessor.get(IMenubarMainService), disposables);
mainProcessElectronServer.registerChannel('menubar', menubarChannel);
// URL handling
const urlChannel = ProxyChannel.fromService(accessor.get(IURLService));
const urlChannel = ProxyChannel.fromService(accessor.get(IURLService), disposables);
mainProcessElectronServer.registerChannel('url', urlChannel);
// Extension URL Trust
const extensionUrlTrustChannel = ProxyChannel.fromService(accessor.get(IExtensionUrlTrustService));
const extensionUrlTrustChannel = ProxyChannel.fromService(accessor.get(IExtensionUrlTrustService), disposables);
mainProcessElectronServer.registerChannel('extensionUrlTrust', extensionUrlTrustChannel);
// Webview Manager
const webviewChannel = ProxyChannel.fromService(accessor.get(IWebviewManagerService));
const webviewChannel = ProxyChannel.fromService(accessor.get(IWebviewManagerService), disposables);
mainProcessElectronServer.registerChannel('webview', webviewChannel);
// Storage (main & shared process)
@@ -1134,11 +1136,11 @@ export class CodeApplication extends Disposable {
sharedProcessClient.then(client => client.registerChannel('profileStorageListener', profileStorageListener));
// Terminal
const ptyHostChannel = ProxyChannel.fromService(accessor.get(ILocalPtyService));
const ptyHostChannel = ProxyChannel.fromService(accessor.get(ILocalPtyService), disposables);
mainProcessElectronServer.registerChannel(TerminalIpcChannels.LocalPty, ptyHostChannel);
// External Terminal
const externalTerminalChannel = ProxyChannel.fromService(accessor.get(IExternalTerminalMainService));
const externalTerminalChannel = ProxyChannel.fromService(accessor.get(IExternalTerminalMainService), disposables);
mainProcessElectronServer.registerChannel('externalTerminal', externalTerminalChannel);
// Logger
@@ -1151,11 +1153,11 @@ export class CodeApplication extends Disposable {
mainProcessElectronServer.registerChannel('extensionhostdebugservice', electronExtensionHostDebugBroadcastChannel);
// Extension Host Starter
const extensionHostStarterChannel = ProxyChannel.fromService(accessor.get(IExtensionHostStarter));
const extensionHostStarterChannel = ProxyChannel.fromService(accessor.get(IExtensionHostStarter), disposables);
mainProcessElectronServer.registerChannel(ipcExtensionHostStarterChannelName, extensionHostStarterChannel);
// Utility Process Worker
const utilityProcessWorkerChannel = ProxyChannel.fromService(accessor.get(IUtilityProcessWorkerMainService));
const utilityProcessWorkerChannel = ProxyChannel.fromService(accessor.get(IUtilityProcessWorkerMainService), disposables);
mainProcessElectronServer.registerChannel(ipcUtilityProcessWorkerChannelName, utilityProcessWorkerChannel);
}
@@ -7,7 +7,7 @@ import { hostname, release } from 'os';
import { MessagePortMain, MessageEvent } from 'vs/base/parts/sandbox/node/electronTypes';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { onUnexpectedError, setUnexpectedErrorHandler } from 'vs/base/common/errors';
import { combinedDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { combinedDisposable, Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import { firstOrDefault } from 'vs/base/common/arrays';
@@ -367,16 +367,18 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter {
private initChannels(accessor: ServicesAccessor): void {
const disposables = this._register(new DisposableStore());
// Extensions Management
const channel = new ExtensionManagementChannel(accessor.get(IExtensionManagementService), () => null);
this.server.registerChannel('extensions', channel);
// Language Packs
const languagePacksChannel = ProxyChannel.fromService(accessor.get(ILanguagePackService));
const languagePacksChannel = ProxyChannel.fromService(accessor.get(ILanguagePackService), disposables);
this.server.registerChannel('languagePacks', languagePacksChannel);
// Diagnostics
const diagnosticsChannel = ProxyChannel.fromService(accessor.get(IDiagnosticsService));
const diagnosticsChannel = ProxyChannel.fromService(accessor.get(IDiagnosticsService), disposables);
this.server.registerChannel('diagnostics', diagnosticsChannel);
// Extension Tips
@@ -384,11 +386,11 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter {
this.server.registerChannel('extensionTipsService', extensionTipsChannel);
// Checksum
const checksumChannel = ProxyChannel.fromService(accessor.get(IChecksumService));
const checksumChannel = ProxyChannel.fromService(accessor.get(IChecksumService), disposables);
this.server.registerChannel('checksum', checksumChannel);
// Profiling
const profilingChannel = ProxyChannel.fromService(accessor.get(IV8InspectProfilingService));
const profilingChannel = ProxyChannel.fromService(accessor.get(IV8InspectProfilingService), disposables);
this.server.registerChannel('v8InspectProfiling', profilingChannel);
// Settings Sync
@@ -396,7 +398,7 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter {
this.server.registerChannel('userDataSyncMachines', userDataSyncMachineChannel);
// Custom Endpoint Telemetry
const customEndpointTelemetryChannel = ProxyChannel.fromService(accessor.get(ICustomEndpointTelemetryService));
const customEndpointTelemetryChannel = ProxyChannel.fromService(accessor.get(ICustomEndpointTelemetryService), disposables);
this.server.registerChannel('customEndpointTelemetry', customEndpointTelemetryChannel);
const userDataSyncAccountChannel = new UserDataSyncAccountServiceChannel(accessor.get(IUserDataSyncAccountService));
@@ -413,11 +415,11 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter {
this.server.registerChannel('userDataAutoSync', userDataAutoSyncChannel);
// Tunnel
const sharedProcessTunnelChannel = ProxyChannel.fromService(accessor.get(ISharedProcessTunnelService));
const sharedProcessTunnelChannel = ProxyChannel.fromService(accessor.get(ISharedProcessTunnelService), disposables);
this.server.registerChannel(ipcSharedProcessTunnelChannelName, sharedProcessTunnelChannel);
// Remote Tunnel
const remoteTunnelChannel = ProxyChannel.fromService(accessor.get(IRemoteTunnelService));
const remoteTunnelChannel = ProxyChannel.fromService(accessor.get(IRemoteTunnelService), disposables);
this.server.registerChannel('remoteTunnel', remoteTunnelChannel);
}
@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DisposableStore } from 'vs/base/common/lifecycle';
import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc';
import { Server as ChildProcessServer } from 'vs/base/parts/ipc/node/ipc.cp';
import { Server as UtilityProcessServer } from 'vs/base/parts/ipc/node/ipc.mp';
@@ -17,4 +18,4 @@ if (isUtilityProcess(process)) {
}
const service = new UniversalWatcher();
server.registerChannel('watcher', ProxyChannel.fromService(service));
server.registerChannel('watcher', ProxyChannel.fromService(service, new DisposableStore()));
+5 -2
View File
@@ -21,6 +21,7 @@ import { HeartbeatService } from 'vs/platform/terminal/node/heartbeatService';
import { PtyService } from 'vs/platform/terminal/node/ptyService';
import { isUtilityProcess } from 'vs/base/parts/sandbox/node/electronTypes';
import { timeout } from 'vs/base/common/async';
import { DisposableStore } from 'vs/base/common/lifecycle';
startPtyHost();
@@ -72,13 +73,15 @@ async function startPtyHost() {
logService.warn(`Pty host is simulating ${simulatedLatency}ms latency`);
}
const disposables = new DisposableStore();
// Heartbeat responsiveness tracking
const heartbeatService = new HeartbeatService();
server.registerChannel(TerminalIpcChannels.Heartbeat, ProxyChannel.fromService(heartbeatService));
server.registerChannel(TerminalIpcChannels.Heartbeat, ProxyChannel.fromService(heartbeatService, disposables));
// Init pty service
const ptyService = new PtyService(logService, productService, reconnectConstants, simulatedLatency);
const ptyServiceChannel = ProxyChannel.fromService(ptyService);
const ptyServiceChannel = ProxyChannel.fromService(ptyService, disposables);
server.registerChannel(TerminalIpcChannels.PtyHost, ptyServiceChannel);
// Register a channel for direct communication via Message Port