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 output: string
textfsm: string textfsm: string
}[] }[]
commands: string[]
} }
interface User { interface User {
@ -52,6 +53,7 @@ export default class LineConnection {
private waitingScenario: boolean private waitingScenario: boolean
private outputInventory: string private outputInventory: string
private outputScenario: string private outputScenario: string
private bufferCommand: string
constructor(config: LineConfig, socketIO: any) { constructor(config: LineConfig, socketIO: any) {
this.config = config this.config = config
@ -63,6 +65,7 @@ export default class LineConnection {
this.waitingScenario = false this.waitingScenario = false
this.outputInventory = '' this.outputInventory = ''
this.outputScenario = '' this.outputScenario = ''
this.bufferCommand = ''
} }
connect(timeoutMs = 5000) { connect(timeoutMs = 5000) {
@ -120,6 +123,7 @@ export default class LineConnection {
stationId, stationId,
lineId: id, lineId: id,
data: message, data: message,
commands: this.config.commands,
}) })
if (!this.config.inventory) { if (!this.config.inventory) {
setTimeout(() => { setTimeout(() => {
@ -183,13 +187,26 @@ export default class LineConnection {
}) })
} }
writeCommand(cmd: string) { writeCommand(cmd: string, isWrite = false) {
if (this.client.destroyed) { if (this.client.destroyed) {
console.log(`⚠️ Cannot send, line ${this.config.lineNumber} is closed`) console.log(`⚠️ Cannot send, line ${this.config.lineNumber} is closed`)
return return
} }
this.client.write(`${cmd}`) 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() { disconnect() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -62,3 +62,20 @@ export const useDebounce = <T extends (...args: any[]) => void>(
return debouncedFn; 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; name: string;
time: number; time: number;
}; };
commands?: string[];
}; };
export type TUser = { export type TUser = {