diff --git a/src/common/terminal/channels.ts b/src/common/terminal/channels.ts new file mode 100644 index 0000000000..f958c9c696 --- /dev/null +++ b/src/common/terminal/channels.ts @@ -0,0 +1,31 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + + +export enum TerminalChannels { + STDIN = "stdin", + STDOUT = "stdout", + CONNECTED = "connected", + RESIZE = "resize", + PING = "ping", +} + +export type TerminalMessage = { + type: TerminalChannels.STDIN; + data: string; +} | { + type: TerminalChannels.STDOUT; + data: string; +} | { + type: TerminalChannels.CONNECTED; +} | { + type: TerminalChannels.RESIZE; + data: { + width: number; + height: number; + }; +} | { + type: TerminalChannels.PING; +}; diff --git a/src/main/helm/helm-chart-manager.ts b/src/main/helm/helm-chart-manager.ts index 5c15bfc6b8..9159c6868a 100644 --- a/src/main/helm/helm-chart-manager.ts +++ b/src/main/helm/helm-chart-manager.ts @@ -4,7 +4,6 @@ */ import fs from "fs"; -import v8 from "v8"; import * as yaml from "js-yaml"; import type { HelmRepo } from "./helm-repo-manager"; import logger from "../logger"; @@ -13,7 +12,7 @@ import { iter, sortCharts } from "../../common/utils"; import { execHelm } from "./exec"; interface ChartCacheEntry { - data: Buffer; + data: string; // serialized JSON mtimeMs: number; } @@ -77,7 +76,7 @@ export class HelmChartManager { const normalized = normalizeHelmCharts(this.repo.name, data.entries); HelmChartManager.#cache.set(this.repo.name, { - data: v8.serialize(normalized), + data: JSON.stringify(normalized), mtimeMs: cacheFileStats.mtimeMs, }); } @@ -94,7 +93,7 @@ export class HelmChartManager { } } - return v8.deserialize(HelmChartManager.#cache.get(this.repo.name).data); + return JSON.parse(HelmChartManager.#cache.get(this.repo.name).data); } } diff --git a/src/main/shell-session/node-shell-session/node-shell-session.ts b/src/main/shell-session/node-shell-session/node-shell-session.ts index 8c5861bff5..7b929865b9 100644 --- a/src/main/shell-session/node-shell-session/node-shell-session.ts +++ b/src/main/shell-session/node-shell-session/node-shell-session.ts @@ -13,8 +13,8 @@ import { get } from "lodash"; import { Node, NodesApi } from "../../../common/k8s-api/endpoints"; import { KubeJsonApi } from "../../../common/k8s-api/kube-json-api"; import logger from "../../logger"; -import { TerminalChannels } from "../../../renderer/api/terminal-api"; import type { Kubectl } from "../../kubectl/kubectl"; +import { TerminalChannels } from "../../../common/terminal/channels"; export class NodeShellSession extends ShellSession { ShellType = "node-shell"; diff --git a/src/main/shell-session/shell-session.ts b/src/main/shell-session/shell-session.ts index 1cc8cd8cce..257c620a18 100644 --- a/src/main/shell-session/shell-session.ts +++ b/src/main/shell-session/shell-session.ts @@ -16,10 +16,8 @@ import { UserStore } from "../../common/user-store"; import * as pty from "node-pty"; import { appEventBus } from "../../common/app-event-bus/event-bus"; import logger from "../logger"; -import type { TerminalMessage } from "../../renderer/api/terminal-api"; -import { TerminalChannels } from "../../renderer/api/terminal-api"; -import { deserialize, serialize } from "v8"; import { stat } from "fs/promises"; +import { type TerminalMessage, TerminalChannels } from "../../common/terminal/channels"; export class ShellOpenError extends Error { constructor(message: string, public cause: Error) { @@ -163,7 +161,7 @@ export abstract class ShellSession { } protected send(message: TerminalMessage): void { - this.websocket.send(serialize(message)); + this.websocket.send(JSON.stringify(message)); } protected async getCwd(env: Record): Promise { @@ -234,17 +232,19 @@ export abstract class ShellSession { }); this.websocket - .on("message", (data: string | Uint8Array) => { + .on("message", (rawData: unknown): void => { if (!this.running) { return void logger.debug(`[SHELL-SESSION]: received message from ${this.terminalId}, but shellProcess isn't running`); } - if (typeof data === "string") { - return void logger.silly(`[SHELL-SESSION]: Received message from ${this.terminalId}`, { data }); + if (!(rawData instanceof Buffer)) { + return void logger.error(`[SHELL-SESSION]: Received message non-buffer message.`, { rawData }); } + const data = rawData.toString(); + try { - const message: TerminalMessage = deserialize(data); + const message: TerminalMessage = JSON.parse(data); switch (message.type) { case TerminalChannels.STDIN: @@ -253,6 +253,9 @@ export abstract class ShellSession { case TerminalChannels.RESIZE: shellProcess.resize(message.data.width, message.data.height); break; + case TerminalChannels.PING: + logger.silly(`[SHELL-SESSION]: ${this.terminalId} ping!`); + break; default: logger.warn(`[SHELL-SESSION]: unknown or unhandleable message type for ${this.terminalId}`, message); break; diff --git a/src/renderer/api/terminal-api.ts b/src/renderer/api/terminal-api.ts index 1e8c86a77c..022f42bf84 100644 --- a/src/renderer/api/terminal-api.ts +++ b/src/renderer/api/terminal-api.ts @@ -11,31 +11,8 @@ import url from "url"; import { makeObservable, observable } from "mobx"; import { ipcRenderer } from "electron"; import logger from "../../common/logger"; -import { deserialize, serialize } from "v8"; import { once } from "lodash"; - -export enum TerminalChannels { - STDIN = "stdin", - STDOUT = "stdout", - CONNECTED = "connected", - RESIZE = "resize", -} - -export type TerminalMessage = { - type: TerminalChannels.STDIN; - data: string; -} | { - type: TerminalChannels.STDOUT; - data: string; -} | { - type: TerminalChannels.CONNECTED; -} | { - type: TerminalChannels.RESIZE; - data: { - width: number; - height: number; - }; -}; +import { type TerminalMessage, TerminalChannels } from "../../common/terminal/channels"; enum TerminalColor { RED = "\u001b[31m", @@ -126,11 +103,10 @@ export class TerminalApi extends WebSocketApi { this.prependListener("connected", onReady); super.connect(socketUrl); - this.socket.binaryType = "arraybuffer"; } sendMessage(message: TerminalMessage) { - return this.send(serialize(message)); + return this.send(JSON.stringify(message)); } sendTerminalSize(cols: number, rows: number) { @@ -145,9 +121,9 @@ export class TerminalApi extends WebSocketApi { } } - protected _onMessage({ data, ...evt }: MessageEvent): void { + protected _onMessage({ data, ...evt }: MessageEvent): void { try { - const message: TerminalMessage = deserialize(new Uint8Array(data)); + const message = JSON.parse(data) as TerminalMessage; switch (message.type) { case TerminalChannels.STDOUT: diff --git a/src/renderer/api/websocket-api.ts b/src/renderer/api/websocket-api.ts index 72ebc2d059..e4d51858f7 100644 --- a/src/renderer/api/websocket-api.ts +++ b/src/renderer/api/websocket-api.ts @@ -8,6 +8,7 @@ import EventEmitter from "events"; import type TypedEventEmitter from "typed-emitter"; import type { Arguments } from "typed-emitter"; import { isDevelopment } from "../../common/vars"; +import { TerminalChannels, type TerminalMessage } from "../../common/terminal/channels"; interface WebsocketApiParams { /** @@ -29,9 +30,9 @@ interface WebsocketApiParams { /** * The message for pinging the websocket * - * @default "PING" + * @default "{type: \"ping\"}" */ - pingMessage?: string | ArrayBufferLike | Blob | ArrayBufferView; + pingMessage?: string; /** * If set to a number > 0, then the API will ping the socket on that interval. @@ -65,10 +66,10 @@ export interface WebSocketEvents { type Defaulted = Required> & Omit; export class WebSocketApi extends (EventEmitter as { new(): TypedEventEmitter }) { - protected socket?: WebSocket | null; - protected pendingCommands: (string | ArrayBufferLike | Blob | ArrayBufferView)[] = []; - protected reconnectTimer?: any; - protected pingTimer?: any; + protected socket: WebSocket | null = null; + protected pendingCommands: string[] = []; + protected reconnectTimer?: number; + protected pingTimer?: number; protected params: Defaulted; @observable readyState = WebSocketApiState.PENDING; @@ -77,7 +78,7 @@ export class WebSocketApi extends (EventEmitter logging: isDevelopment, reconnectDelay: 10, flushOnOpen: true, - pingMessage: "PING", + pingMessage: JSON.stringify({ type: TerminalChannels.PING } as TerminalMessage), }; constructor(params: WebsocketApiParams) { @@ -87,7 +88,7 @@ export class WebSocketApi extends (EventEmitter const { pingInterval } = this.params; if (pingInterval) { - this.pingTimer = setInterval(() => this.ping(), pingInterval * 1000); + this.pingTimer = window.setInterval(() => this.ping(), pingInterval * 1000); } } @@ -143,7 +144,7 @@ export class WebSocketApi extends (EventEmitter } } - send(command: string | ArrayBufferLike | Blob | ArrayBufferView) { + send(command: string) { if (this.isConnected) { this.socket.send(command); } else { @@ -186,7 +187,7 @@ export class WebSocketApi extends (EventEmitter this.writeLog("will reconnect in", `${reconnectDelay}s`); - this.reconnectTimer = setTimeout(() => this.connect(url), reconnectDelay * 1000); + this.reconnectTimer = window.setTimeout(() => this.connect(url), reconnectDelay * 1000); this.readyState = WebSocketApiState.RECONNECTING; } } else { diff --git a/src/renderer/components/dock/terminal/send-command.injectable.ts b/src/renderer/components/dock/terminal/send-command.injectable.ts index edc0a2b7ed..f220b90255 100644 --- a/src/renderer/components/dock/terminal/send-command.injectable.ts +++ b/src/renderer/components/dock/terminal/send-command.injectable.ts @@ -4,8 +4,8 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { when } from "mobx"; +import { TerminalChannels } from "../../../../common/terminal/channels"; import type { TerminalApi } from "../../../api/terminal-api"; -import { TerminalChannels } from "../../../api/terminal-api"; import { noop } from "../../../utils"; import { Notifications } from "../../notifications"; import selectDockTabInjectable from "../dock/select-dock-tab.injectable"; diff --git a/src/renderer/components/dock/terminal/terminal.ts b/src/renderer/components/dock/terminal/terminal.ts index d6f1701028..3742b9de3e 100644 --- a/src/renderer/components/dock/terminal/terminal.ts +++ b/src/renderer/components/dock/terminal/terminal.ts @@ -9,7 +9,6 @@ import { Terminal as XTerm } from "xterm"; import { FitAddon } from "xterm-addon-fit"; import type { TabId } from "../dock/store"; import type { TerminalApi } from "../../../api/terminal-api"; -import { TerminalChannels } from "../../../api/terminal-api"; import { ThemeStore } from "../../../theme.store"; import { disposer } from "../../../utils"; import { isMac } from "../../../../common/vars"; @@ -18,6 +17,7 @@ import { UserStore } from "../../../../common/user-store"; import { clipboard } from "electron"; import logger from "../../../../common/logger"; import type { TerminalConfig } from "../../../../common/user-store/preferences-helpers"; +import { TerminalChannels } from "../../../../common/terminal/channels"; export class Terminal { private terminalConfig: TerminalConfig = UserStore.getInstance().terminalConfig;