Skip to content

Commit 7b0c984

Browse files
committed
Connect to a new terminal instance on disconnect
1 parent 79fc062 commit 7b0c984

File tree

3 files changed

+50
-14
lines changed

3 files changed

+50
-14
lines changed

packages/protocol/src/browser/client.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ export class Client {
143143
clearTimeout(this.pingTimeout as any);
144144
this.pingTimeout = undefined;
145145
handleDisconnect();
146+
this.dispose();
146147
});
147148
connection.onUp(() => this.disconnected = false);
148149

@@ -158,6 +159,12 @@ export class Client {
158159
*/
159160
public dispose(): void {
160161
this.connection.close();
162+
this.proxies.clear();
163+
this.successEmitter.dispose();
164+
this.failEmitter.dispose();
165+
this.eventEmitter.dispose();
166+
this.initDataEmitter.dispose();
167+
this.sharedProcessActiveEmitter.dispose();
161168
}
162169

163170
public get initData(): Promise<InitData> {
@@ -167,9 +174,11 @@ export class Client {
167174
/**
168175
* Make a remote call for a proxy's method using proto.
169176
*/
170-
private remoteCall(proxyId: number | Module, method: string, args: any[]): Promise<any> {
171-
if (this.disconnected) {
172-
return Promise.reject(new Error("disconnected"));
177+
private async remoteCall(proxyId: number | Module, method: string, args: any[]): Promise<any> {
178+
if (this.disconnected && typeof proxyId === "number") {
179+
return Promise.reject(
180+
new Error(`Unable to call "${method}" on proxy ${proxyId}: disconnected`),
181+
);
173182
}
174183

175184
const message = new MethodMessage();
@@ -217,7 +226,7 @@ export class Client {
217226

218227
// The server will send back a fail or success message when the method
219228
// has completed, so we listen for that based on the message's unique ID.
220-
const promise = new Promise((resolve, reject): void => {
229+
const promise = new Promise((resolve, reject): void => {
221230
const dispose = (): void => {
222231
d1.dispose();
223232
d2.dispose();

packages/protocol/src/browser/modules/node-pty.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,20 @@ export class NodePtyProcess extends ClientProxy<NodePtyProcessProxy> implements
66
private _pid = -1;
77
private _process = "";
88

9-
public constructor(proxyPromise: Promise<NodePtyProcessProxy>) {
10-
super(proxyPromise);
9+
public constructor(
10+
private readonly moduleProxy: NodePtyModuleProxy,
11+
private readonly file: string,
12+
private readonly args: string[] | string,
13+
private readonly options: pty.IPtyForkOptions,
14+
) {
15+
super(moduleProxy.spawn(file, args, options));
16+
this.on("process", (process) => this._process = process);
17+
}
18+
19+
protected initialize(proxyPromise: Promise<NodePtyProcessProxy>) {
20+
super.initialize(proxyPromise);
1121
this.proxy.getPid().then((pid) => this._pid = pid);
1222
this.proxy.getProcess().then((process) => this._process = process);
13-
this.on("process", (process) => this._process = process);
1423
}
1524

1625
public get pid(): number {
@@ -35,7 +44,8 @@ export class NodePtyProcess extends ClientProxy<NodePtyProcessProxy> implements
3544

3645
protected handleDisconnect(): void {
3746
this._process += " (disconnected)";
38-
this.emit("data", "\r\n\nLost connection...");
47+
this.emit("data", "\r\n\nLost connection...\r\n\n");
48+
this.initialize(this.moduleProxy.spawn(this.file, this.args, this.options));
3949
}
4050
}
4151

@@ -45,6 +55,6 @@ export class NodePtyModule implements NodePty {
4555
public constructor(private readonly proxy: NodePtyModuleProxy) {}
4656

4757
public spawn = (file: string, args: string[] | string, options: pty.IPtyForkOptions): pty.IPty => {
48-
return new NodePtyProcess(this.proxy.spawn(file, args, options));
58+
return new NodePtyProcess(this.proxy, file, args, options);
4959
}
5060
}

packages/protocol/src/common/proxy.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,37 @@ const unpromisify = <T extends ServerProxy>(proxyPromise: Promise<T>): T => {
2929
* need a bunch of `then` calls everywhere.
3030
*/
3131
export abstract class ClientProxy<T extends ServerProxy> extends EventEmitter {
32-
protected readonly proxy: T;
32+
private _proxy: T | undefined;
3333

3434
/**
3535
* You can specify not to bind events in order to avoid emitting twice for
3636
* duplex streams.
3737
*/
38-
public constructor(proxyPromise: Promise<T> | T, bindEvents: boolean = true) {
38+
public constructor(
39+
proxyPromise: Promise<T> | T,
40+
private readonly bindEvents: boolean = true,
41+
) {
3942
super();
40-
this.proxy = isPromise(proxyPromise) ? unpromisify(proxyPromise) : proxyPromise;
41-
if (bindEvents) {
43+
this.initialize(proxyPromise);
44+
if (this.bindEvents) {
45+
this.on("disconnected", (error) => this.handleDisconnect(error));
46+
}
47+
}
48+
49+
protected get proxy(): T {
50+
if (!this._proxy) {
51+
throw new Error("not initialized");
52+
}
53+
54+
return this._proxy;
55+
}
56+
57+
protected initialize(proxyPromise: Promise<T> | T): void {
58+
this._proxy = isPromise(proxyPromise) ? unpromisify(proxyPromise) : proxyPromise;
59+
if (this.bindEvents) {
4260
this.proxy.onEvent((event, ...args): void => {
4361
this.emit(event, ...args);
4462
});
45-
this.on("disconnected", (error) => this.handleDisconnect(error));
4663
}
4764
}
4865

0 commit comments

Comments
 (0)