This commit is contained in:
nguyentrungthat 2025-11-11 16:12:11 +07:00
parent f9e685fcbd
commit 00c91f1e69
8 changed files with 75 additions and 11 deletions

View File

@ -35,6 +35,7 @@ interface LineConfig {
output: string
textfsm: string
}[]
commands: string[]
}
interface User {
@ -52,6 +53,7 @@ export default class LineConnection {
private waitingScenario: boolean
private outputInventory: string
private outputScenario: string
private bufferCommand: string
constructor(config: LineConfig, socketIO: any) {
this.config = config
@ -63,6 +65,7 @@ export default class LineConnection {
this.waitingScenario = false
this.outputInventory = ''
this.outputScenario = ''
this.bufferCommand = ''
}
connect(timeoutMs = 5000) {
@ -120,6 +123,7 @@ export default class LineConnection {
stationId,
lineId: id,
data: message,
commands: this.config.commands,
})
if (!this.config.inventory) {
setTimeout(() => {
@ -183,13 +187,26 @@ export default class LineConnection {
})
}
writeCommand(cmd: string) {
writeCommand(cmd: string, isWrite = false) {
if (this.client.destroyed) {
console.log(`⚠️ Cannot send, line ${this.config.lineNumber} is closed`)
return
}
this.client.write(`${cmd}`)
if (isWrite) {
const command = cmd.toString()
for (const char of command) {
if (char === '\x7F') this.bufferCommand = this.bufferCommand.slice(0, -1)
else if (char === '\r' && cleanData(this.bufferCommand).length > 0) {
this.config.commands = [
cleanData(this.bufferCommand),
...this.config.commands.filter((el) => el !== cleanData(this.bufferCommand)),
].slice(0, 10)
this.bufferCommand = ''
} else this.bufferCommand += char
}
}
}
disconnect() {

View File

@ -115,7 +115,7 @@ export class WebSocketIo {
listLineS.forEach((el) => {
if (el?.userOpenCLI === userName) {
const line = this.lineMap.get(el.id)
if (line) line.userCloseCLI()
if (line && line?.userCloseCLI()) line?.userCloseCLI()
}
})
setTimeout(() => {
@ -136,7 +136,7 @@ export class WebSocketIo {
io,
stationId,
lineIds,
async (line) => line.writeCommand(command),
async (line) => line.writeCommand(command, true),
{ command, timeout: 120000 }
)
})
@ -167,7 +167,13 @@ export class WebSocketIo {
const stationData = await Station.findBy('id', stationId)
if (linesData && stationData) {
this.lineConnecting.push(lineId)
await this.connectLine(io, [linesData], stationData, line?.config?.output || '')
await this.connectLine(
io,
[linesData],
stationData,
line?.config?.output || '',
line?.config?.commands || []
)
const lineReconnect = this.lineMap.get(lineId)
if (lineReconnect) {
lineReconnect.userOpenCLI({ userEmail, userName: name })
@ -187,7 +193,13 @@ export class WebSocketIo {
const stationData = await Station.findBy('id', stationId)
if (linesData && stationData) {
this.lineConnecting.push(lineId)
await this.connectLine(io, [linesData], stationData, line?.config?.output || '')
await this.connectLine(
io,
[linesData],
stationData,
line?.config?.output || '',
line?.config?.commands || []
)
const lineReconnect = this.lineMap.get(lineId)
if (lineReconnect) {
lineReconnect.userCloseCLI()
@ -422,7 +434,13 @@ export class WebSocketIo {
return io
}
private async connectLine(socket: any, lines: Line[], station: Station, output = '') {
private async connectLine(
socket: any,
lines: Line[],
station: Station,
output = '',
commands: string[] = []
) {
try {
this.stationMap.set(station.id, station)
for (const line of lines) {
@ -441,6 +459,7 @@ export class WebSocketIo {
userEmailOpenCLI: '',
userOpenCLI: '',
data: [],
commands: commands,
},
socket
)
@ -505,7 +524,13 @@ export class WebSocketIo {
if (linesData && stationData) {
this.lineConnecting.push(lineId)
await this.connectLine(io, [linesData], stationData, line?.config?.output || '')
await this.connectLine(
io,
[linesData],
stationData,
line?.config?.output || '',
line?.config?.commands || []
)
this.lineConnecting = this.lineConnecting.filter((el) => el !== lineId)
const lineReconnect = this.lineMap.get(lineId)

View File

@ -91,8 +91,6 @@ function App() {
if (response.status) {
if (Array.isArray(response.data)) {
setStations(response.data);
// if (response.data?.length > 0)
// setActiveTab(response.data[0]?.id.toString());
}
}
} catch (error) {
@ -141,7 +139,7 @@ function App() {
socket?.on("line_output", (data) => {
updateValueLineStation(
data?.lineId,
{ netOutput: data.data },
{ netOutput: data.data, commands: data.commands || [] },
data?.stationId
);
});

View File

@ -118,6 +118,7 @@ const CardLine = ({
initContent={line?.netOutput ?? ""}
loadingContent={line?.loadingOutput}
line_id={Number(line?.id)}
line={line}
station_id={Number(stationItem.id)}
isDisabled={
typeof line?.userOpenCLI !== "undefined" &&

View File

@ -170,6 +170,7 @@ const ModalTerminal = ({
initContent={line?.netOutput ?? ""}
loadingContent={line?.loadingOutput}
line_id={Number(line?.id)}
line={line}
station_id={Number(stationItem?.id)}
isDisabled={
typeof line?.userOpenCLI !== "undefined" &&

View File

@ -3,12 +3,14 @@ import { Terminal } from "xterm";
import "xterm/css/xterm.css";
import { FitAddon } from "@xterm/addon-fit";
import type { Socket } from "socket.io-client";
import type { TLine } from "../untils/types";
interface TerminalCLIProps {
socket: Socket | null;
content?: string;
initContent?: string;
line_id: number;
line: TLine | undefined;
line_status: string;
station_id: number;
cliOpened: boolean;
@ -44,6 +46,7 @@ const TerminalCLI: React.FC<TerminalCLIProps> = ({
loadingContent = false,
onFocus,
onBlur,
line,
}) => {
const xtermRef = useRef<HTMLDivElement>(null);
const terminal = useRef<Terminal>(null);
@ -103,7 +106,8 @@ const TerminalCLI: React.FC<TerminalCLIProps> = ({
if (e.ctrlKey && e.key.toLowerCase() === "v") return false;
// Handle Esc
if (e.key === "Escape") return false;
// Handle Enter
// if (e.key === "ArrowUp") handleArrowUp();
return true; // allow all other keys through
}
);

View File

@ -62,3 +62,20 @@ export const useDebounce = <T extends (...args: any[]) => void>(
return debouncedFn;
};
export const handleStorageCommand = (command: string, lineId: number) => {
const storage = localStorage.getItem("history_commands");
const history: Record<number, string[]> = storage ? JSON.parse(storage) : {};
let commands = history[lineId] || [];
commands = [command, ...commands.filter((cmd) => cmd !== command)];
commands = commands.slice(0, 10);
history[lineId] = commands;
localStorage.setItem("history_commands", JSON.stringify(history));
};
export const handleGetStorageCommand = (lineId: number): string[] => {
const storage = localStorage.getItem("history_commands");
const history: Record<number, string[]> = storage ? JSON.parse(storage) : {};
return history[lineId] || [];
};

View File

@ -92,6 +92,7 @@ export type TLine = {
name: string;
time: number;
};
commands?: string[];
};
export type TUser = {