mirror of
https://github.com/MCSManager/MCSManager.git
synced 2025-04-06 17:10:29 +08:00
Feat: Terminal size sync
This commit is contained in:
parent
50a7a5cb9e
commit
70019f8701
@ -15,9 +15,10 @@ export default class DockerResizeCommand extends InstanceCommand {
|
||||
async exec(instance: Instance, size?: IResizeOptions): Promise<any> {
|
||||
const dockerProcess = instance?.process as Partial<DockerProcessAdapter>;
|
||||
if (typeof dockerProcess?.container?.resize === "function") {
|
||||
const { w, h } = instance.computeTerminalSize();
|
||||
await dockerProcess?.container?.resize({
|
||||
h: size.h,
|
||||
w: size.w
|
||||
h,
|
||||
w
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2,20 +2,16 @@ import Instance from "../../instance/instance";
|
||||
import InstanceCommand from "../base/command";
|
||||
import { GoPtyProcessAdapter } from "./pty_start";
|
||||
|
||||
interface IResizeOptions {
|
||||
h: number;
|
||||
w: number;
|
||||
}
|
||||
|
||||
export default class PtyResizeCommand extends InstanceCommand {
|
||||
constructor() {
|
||||
super("ResizeTTY");
|
||||
}
|
||||
|
||||
async exec(instance: Instance, size?: IResizeOptions): Promise<any> {
|
||||
async exec(instance: Instance): Promise<any> {
|
||||
const pty = instance.process as Partial<GoPtyProcessAdapter>;
|
||||
if (typeof pty?.resize === "function") {
|
||||
pty?.resize(size.w, size.h);
|
||||
const { w, h } = instance.computeTerminalSize();
|
||||
pty?.resize(w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import FunctionDispatcher from "../commands/dispatcher";
|
||||
import { IInstanceProcess } from "./interface";
|
||||
import StartCommand from "../commands/start";
|
||||
import { configureEntityParams } from "common";
|
||||
import { PTY_PATH } from "../../const";
|
||||
import { OpenFrp } from "../commands/task/openfrp";
|
||||
|
||||
// The instance does not need to store additional information persistently
|
||||
@ -26,6 +25,13 @@ interface IInstanceInfo {
|
||||
openFrpStatus: boolean;
|
||||
}
|
||||
|
||||
interface IWatcherInfo {
|
||||
terminalSize: {
|
||||
w: number;
|
||||
h: number;
|
||||
};
|
||||
}
|
||||
|
||||
// instance class
|
||||
export default class Instance extends EventEmitter {
|
||||
public static readonly STATUS_BUSY = -1;
|
||||
@ -60,6 +66,8 @@ export default class Instance extends EventEmitter {
|
||||
openFrpStatus: false
|
||||
};
|
||||
|
||||
public watchers: Map<string, IWatcherInfo> = new Map();
|
||||
|
||||
public process: IInstanceProcess;
|
||||
|
||||
// When initializing an instance, the instance must be initialized through uuid and configuration class, otherwise the instance will be unavailable
|
||||
@ -352,4 +360,20 @@ export default class Instance extends EventEmitter {
|
||||
clearPreset() {
|
||||
this.presetCommandManager.clearPreset();
|
||||
}
|
||||
|
||||
computeTerminalSize() {
|
||||
let minW = this.config.terminalOption.ptyWindowCol;
|
||||
let minH = this.config.terminalOption.ptyWindowRow;
|
||||
for (const iterator of this.watchers.values()) {
|
||||
const { w, h } = iterator.terminalSize;
|
||||
if (w && h) {
|
||||
if (w < minW) minW = w;
|
||||
if (h < minH) minH = h;
|
||||
}
|
||||
}
|
||||
return {
|
||||
w: minW,
|
||||
h: minH
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -125,11 +125,21 @@ routerApp.on("stream/write", async (ctx, data) => {
|
||||
});
|
||||
|
||||
// handle terminal resize
|
||||
// interface IResizeOptions {
|
||||
// h: number;
|
||||
// w: number;
|
||||
// }
|
||||
routerApp.on("stream/resize", async (ctx, data) => {
|
||||
try {
|
||||
const instanceUuid = ctx.session?.stream?.instanceUuid;
|
||||
const instance = InstanceSubsystem.getInstance(instanceUuid);
|
||||
if (instance) await instance.execPreset("resize", data);
|
||||
instance.watchers.set(ctx.socket.id, {
|
||||
terminalSize: {
|
||||
w: Number(data.w) || 0,
|
||||
h: Number(data.h) || 0
|
||||
}
|
||||
});
|
||||
if (instance) await instance.execPreset("resize");
|
||||
} catch (error) {
|
||||
// protocol.responseError(ctx, error);
|
||||
}
|
||||
|
@ -195,6 +195,8 @@ class InstanceSubsystem extends EventEmitter {
|
||||
|
||||
stopForward(targetInstanceUuid: string, socket: Socket) {
|
||||
try {
|
||||
const instance = this.getInstance(targetInstanceUuid);
|
||||
instance.watchers.delete(socket.id);
|
||||
this.instanceStream.cannelForward(socket, targetInstanceUuid);
|
||||
} catch (err) {}
|
||||
}
|
||||
|
@ -150,15 +150,13 @@ export function useTerminal() {
|
||||
};
|
||||
|
||||
const refreshWindowSize = (w: number, h: number) => {
|
||||
if (cachedSize.h !== h || cachedSize.w !== w) {
|
||||
cachedSize = {
|
||||
w,
|
||||
h
|
||||
};
|
||||
socket?.emit("stream/resize", {
|
||||
data: cachedSize
|
||||
});
|
||||
}
|
||||
cachedSize = {
|
||||
w,
|
||||
h
|
||||
};
|
||||
socket?.emit("stream/resize", {
|
||||
data: cachedSize
|
||||
});
|
||||
};
|
||||
|
||||
const initTerminalWindow = (element: HTMLElement) => {
|
||||
@ -183,13 +181,14 @@ export function useTerminal() {
|
||||
const fitAddon = new FitAddon();
|
||||
term.loadAddon(fitAddon);
|
||||
term.open(element);
|
||||
|
||||
// Auto resize pty win size
|
||||
fitAddon.fit();
|
||||
refreshWindowSize(term.cols - 1, term.rows - 1);
|
||||
fitAddonTask = setInterval(() => {
|
||||
fitAddon.fit();
|
||||
refreshWindowSize(term.cols - 1, term.rows - 1);
|
||||
// Auto resize pty win size
|
||||
}, 1000);
|
||||
}, 2000);
|
||||
|
||||
term.onData((data) => {
|
||||
socket?.emit("stream/write", {
|
||||
|
Loading…
x
Reference in New Issue
Block a user