Wait for shell to bring up prompt before sending commands (#3337)

This commit is contained in:
Sebastian Malton authored and GitHub committed 2021-07-20 15:25:18 -04:00
1 parent aeae2dcf98
commit 27f2bd7181
2 files changed
+70 -30

No files matched your search

+43 -22
View File
@@ -19,11 +19,13 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import { stringify } from "querystring";
import { boundMethod, base64, EventEmitter } from "../utils";
import { WebSocketApi } from "./websocket-api";
import isEqual from "lodash/isEqual";
import { isDevelopment } from "../../common/vars";
import url from "url";
import { makeObservable, observable } from "mobx";
import type { ParsedUrlQueryInput } from "querystring";
export enum TerminalChannels {
STDIN = 0,
@@ -55,7 +57,9 @@ export class TerminalApi extends WebSocketApi {
protected size: { Width: number; Height: number };
public onReady = new EventEmitter<[]>();
public isReady = false;
@observable public isReady = false;
@observable public shellRunCommandsFinished = false;
public readonly url: string;
constructor(protected options: TerminalApiQuery) {
super({
@@ -63,34 +67,33 @@ export class TerminalApi extends WebSocketApi {
flushOnOpen: false,
pingIntervalSeconds: 30,
});
}
makeObservable(this);
async getUrl() {
let { port } = location;
const { hostname, protocol } = location;
const { id, node } = this.options;
const wss = `ws${protocol === "https:" ? "s" : ""}://`;
const query: TerminalApiQuery = { id };
const { hostname, protocol, port } = location;
const query: ParsedUrlQueryInput = {
id: options.id,
};
if (port) {
port = `:${port}`;
if (options.node) {
query.node = options.node;
query.type = options.type || "node";
}
if (node) {
query.node = node;
query.type = "node";
}
return `${wss}${hostname}${port}/api?${stringify(query)}`;
this.url = url.format({
protocol: protocol.includes("https") ? "wss" : "ws",
hostname,
port,
pathname: "/api",
query,
slashes: true,
});
}
async connect() {
const apiUrl = await this.getUrl();
connect() {
this.emitStatus("Connecting ...");
this.onData.addListener(this._onReady, { prepend: true });
return super.connect(apiUrl);
this.onData.addListener(this._onShellRunCommandsFinished);
super.connect(this.url);
}
destroy() {
@@ -106,6 +109,24 @@ export class TerminalApi extends WebSocketApi {
this.onReady.removeAllListeners();
}
_onShellRunCommandsFinished = (data: string) => {
if (!data) {
return;
}
/**
* This is a heuistic for ditermining when a shell has finished executing
* its own rc file (or RunCommands file) such as `.bashrc` or `.zshrc`.
*
* This heuistic assumes that the prompt line of a terminal is a single line
* and ends with a whitespace character.
*/
if (data.match(/\r?\n/) === null && data.match(/\s$/)) {
this.shellRunCommandsFinished = true;
this.onData.removeListener(this._onShellRunCommandsFinished);
}
};
@boundMethod
protected _onReady(data: string) {
if (!data) return true;