Skip to content

Commit 64156c6

Browse files
authored
Fixes #993: Add dispose state that disallows restarting the client (#994)
1 parent 95e411d commit 64156c6

2 files changed

Lines changed: 25 additions & 0 deletions

File tree

client-node-tests/src/integration.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,6 +1769,15 @@ suite('Server activation', () => {
17691769
await client.stop();
17701770
});
17711771

1772+
test('Starting disposed server fails', async () => {
1773+
const client = createClient();
1774+
await client.start();
1775+
await client.dispose();
1776+
await assert.rejects(async () => {
1777+
await client.start();
1778+
}, /Client got disposed and can't be restarted./);
1779+
});
1780+
17721781
async function checkServerStart(client: LanguageClient, disposable: vscode.Disposable): Promise<void> {
17731782
return new Promise((resolve, reject) => {
17741783
const timeout = setTimeout(() => {

client/src/common/client.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
440440
private readonly _ignoredRegistrations: Set<string>;
441441
// private _idleStart: number | undefined;
442442
private readonly _listeners: Disposable[];
443+
private _disposed: 'disposing' | 'disposed' | undefined;
443444

444445
private readonly _notificationHandlers: Map<string, GenericNotificationHandler>;
445446
private readonly _notificationDisposables: Map<string, Disposable>;
@@ -769,6 +770,9 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
769770
}
770771

771772
public async sendProgress<P>(type: ProgressType<P>, token: string | number, value: P): Promise<void> {
773+
if (this.$state === ClientState.StartFailed || this.$state === ClientState.Stopping || this.$state === ClientState.Stopped) {
774+
return Promise.reject(new ResponseError(ErrorCodes.ConnectionInactive, `Client is not running`));
775+
}
772776
try {
773777
// Ensure we have a connection before we force the document sync.
774778
const connection = await this.$start();
@@ -935,6 +939,9 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
935939
}
936940

937941
public async start(): Promise<void> {
942+
if (this._disposed === 'disposing' || this._disposed === 'disposed') {
943+
throw new Error(`Client got disposed and can't be restarted.`);
944+
}
938945
if (this.$state === ClientState.Stopping) {
939946
throw new Error(`Client is currently stopping. Can only restart a full stopped client`);
940947
}
@@ -1226,6 +1233,15 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
12261233
return this.shutdown('stop', timeout);
12271234
}
12281235

1236+
public dispose(timeout: number = 2000): Promise<void> {
1237+
try {
1238+
this._disposed = 'disposing';
1239+
return this.stop(timeout);
1240+
} finally {
1241+
this._disposed = 'disposed';
1242+
}
1243+
}
1244+
12291245
private async shutdown(mode: 'suspend' | 'stop', timeout: number): Promise<void> {
12301246
// If the client is stopped or in its initial state return.
12311247
if (this.$state === ClientState.Stopped || this.$state === ClientState.Initial) {

0 commit comments

Comments
 (0)