This commit is contained in:
nguyentrungthat 2025-11-03 11:19:15 +07:00
parent 1682a28029
commit 01485bf1d9
5 changed files with 130 additions and 59 deletions

View File

@ -18,6 +18,7 @@ interface LineConfig {
ip: string
stationId: number
apcName?: string
outlet: number
output: string
status: string
openCLI: boolean
@ -47,6 +48,7 @@ export default class LineConnection {
private outputBuffer: string
private isRunningScript: boolean
private connecting: boolean
private isSendPlatform: boolean
constructor(config: LineConfig, socketIO: any) {
this.config = config
@ -55,6 +57,7 @@ export default class LineConnection {
this.outputBuffer = ''
this.isRunningScript = false
this.connecting = false
this.isSendPlatform = false
}
connect(timeoutMs = 5000) {
@ -63,7 +66,7 @@ export default class LineConnection {
let resolvedOrRejected = false
// Set timeout
this.client.setTimeout(timeoutMs)
console.log(`🔌 Connecting to line ${lineNumber} (${ip}:${port})...`)
this.client.connect(port, ip, () => {
if (resolvedOrRejected) return
resolvedOrRejected = true
@ -139,9 +142,22 @@ export default class LineConnection {
this.client.on('timeout', () => {
if (resolvedOrRejected) return
resolvedOrRejected = true
const message = 'Connection timeout!!\r\n'
this.config.output += message
this.socketIO.emit('line_output', {
stationId,
lineId: id,
data: message,
})
appendLog(
cleanData(message),
this.config.stationId,
this.config.lineNumber,
this.config.port
)
console.log(`⏳ Connection timeout line ${lineNumber}`)
this.client.destroy()
resolve()
// reject(new Error('Connection timeout'))
})
})
@ -152,6 +168,9 @@ export default class LineConnection {
console.log(`⚠️ Cannot send, line ${this.config.lineNumber} is closed`)
return
}
if (cmd.includes('show platform') || cmd.includes('sh platform')) {
this.isSendPlatform = true
} else this.isSendPlatform = false
this.client.write(`${cmd}`)
}
@ -297,13 +316,16 @@ export default class LineConnection {
return
}
while (this.outputBuffer) {
await sleep(200)
if (this.outputBuffer.includes(step.expect)) {
this.outputBuffer = ''
setTimeout(() => sendCommand(), Number(step?.delay) || 500)
}
}
// while (this.outputBuffer) {
// await sleep(200)
// if (this.outputBuffer.includes(step.expect)) {
// this.outputBuffer = ''
// setTimeout(() => sendCommand(), Number(step?.delay) || 500)
// }
// }
const matched = await this.waitForExpect(step.expect, Number(step?.timeout) || 60000)
if (matched) setTimeout(() => sendCommand(), Number(step?.delay) || 500)
}
runStep(stepIndex)
@ -332,4 +354,16 @@ export default class LineConnection {
userEmailOpenCLI: '',
})
}
waitForExpect = async (expect: string, timeout = 60000) => {
const start = Date.now()
while (Date.now() - start < timeout) {
if (this.outputBuffer.includes(expect)) {
this.outputBuffer = ''
return true
}
await sleep(200)
}
return false
}
}

View File

@ -121,9 +121,9 @@ export class WebSocketIo {
if (linesData && stationData) {
this.lineConnecting.push(lineId)
await this.connectLine(io, [linesData], stationData)
this.lineConnecting = this.lineConnecting.filter((el) => el !== lineId)
const lineReconnect = this.lineMap.get(lineId)
if (lineReconnect) {
this.lineConnecting = this.lineConnecting.filter((el) => el !== lineId)
this.setTimeoutConnect(lineId, lineReconnect)
lineReconnect.writeCommand(command)
}
@ -282,6 +282,7 @@ export class WebSocketIo {
lineNumber: line.lineNumber,
stationId: station.id,
apcName: line.apcName,
outlet: line.outlet,
output: '',
status: '',
openCLI: false,
@ -291,9 +292,9 @@ export class WebSocketIo {
},
socket
)
this.lineMap.set(line.id, lineConn)
await lineConn.connect()
lineConn.writeCommand('\r\n\r\n')
this.lineMap.set(line.id, lineConn)
this.setTimeoutConnect(line.id, lineConn)
}
} catch (error) {

View File

@ -18,7 +18,6 @@ import {
import type {
IDataTakeOver,
IScenario,
LineConfig,
ReceivedFile,
ResponseData,
TLine,
@ -122,23 +121,38 @@ function App() {
useEffect(() => {
if (!socket || !stations?.length) return;
socket.on("line_connected", updateStatus);
socket.on("line_connected", (data) =>
updateValueLineStation(data?.id, { status: data.status }, data?.stationId)
);
socket.on("line_disconnected", updateStatus);
socket.on("line_disconnected", (data) =>
updateValueLineStation(data?.id, { status: data.status }, data?.stationId)
);
socket?.on("line_output", (data) => {
updateValueLineStation(data?.lineId, { netOutput: data.data });
updateValueLineStation(
data?.lineId,
{ netOutput: data.data },
data?.stationId
);
});
socket?.on("line_error", (data) => {
updateValueLineStation(data?.lineId, { netOutput: data.error });
updateValueLineStation(
data?.lineId,
{ netOutput: data.error },
data?.stationId
);
});
socket?.on("init", (data) => {
if (Array.isArray(data)) {
data.forEach((value) => {
updateValueLineStation(value?.id, { netOutput: value.output });
updateStatus({ ...value, lineId: value.id });
updateValueLineStation(
value?.id,
{ ...value, netOutput: value.output },
value?.stationId
);
});
}
});
@ -151,21 +165,29 @@ function App() {
socket?.on("user_open_cli", (data) => {
setTimeout(() => {
updateValueLineStation(data.lineId, {
updateValueLineStation(
data.lineId,
{
cliOpened: true,
userEmailOpenCLI: data.userEmailOpenCLI,
userOpenCLI: data.userOpenCLI,
});
},
data?.stationId
);
}, 100);
});
socket?.on("user_close_cli", (data) => {
setTimeout(() => {
updateValueLineStation(data.lineId, {
updateValueLineStation(
data.lineId,
{
cliOpened: false,
userEmailOpenCLI: undefined,
userOpenCLI: undefined,
});
},
data?.stationId
);
}, 100);
});
@ -232,11 +254,15 @@ function App() {
socket?.on("data_textfsm", (data) => {
setTimeout(() => {
updateValueLineStation(data.lineId, {
updateValueLineStation(
data.lineId,
{
data: data.data,
inventory: data.inventory,
latestScenario: data.latestScenario,
});
},
data?.stationId
);
}, 100);
});
@ -255,18 +281,11 @@ function App() {
};
}, [socket, stations, selectedLine]);
const updateStatus = (data: LineConfig) => {
const line = getLine(data.lineId, data.stationId);
if (line?.id) {
updateValueLineStation(line.id, { status: data.status });
}
};
const updateValueLineStation = useCallback(
(lineId: number, updates: Partial<TLine>) => {
(lineId: number, updates: Partial<TLine>, stationId?: number) => {
setStations((prevStations) =>
prevStations?.map((station: TStation) =>
station.id.toString() === activeTab
station.id === stationId
? {
...station,
lines: station.lines?.map((lineItem: TLine) => {
@ -311,13 +330,13 @@ function App() {
[activeTab]
);
const getLine = (lineId: number, stationId: number) => {
const station = stations?.find((sta) => sta.id === stationId);
if (station) {
const line = station.lines?.find((li) => li.id === lineId);
return line;
} else return null;
};
// const getLine = (lineId: number, stationId: number) => {
// const station = stations?.find((sta) => sta.id === stationId);
// if (station) {
// const line = station.lines?.find((li) => li.id === lineId);
// return line;
// } else return null;
// };
const openTerminal = (line: TLine) => {
setOpenModalTerminal(true);

View File

@ -27,6 +27,20 @@ export const ButtonDPELP = ({
onClick();
selectedLines?.forEach((el) => {
const body = [
{
expect: "",
send: " terminal length 0",
delay: "1000",
repeat: "1",
note: "",
},
{
expect: "",
send: "enable",
delay: "1000",
repeat: "1",
note: "",
},
{
expect: "",
send: " show inventory",
@ -101,7 +115,7 @@ export const ButtonDPELP = ({
expect: "",
send: " ",
delay: "1000",
repeat: "2",
repeat: "1",
note: "",
},
{
@ -111,13 +125,13 @@ export const ButtonDPELP = ({
repeat: "1",
note: "",
},
{
expect: "",
send: " ",
delay: "7000",
repeat: "15",
note: "",
},
// {
// expect: "",
// send: " ",
// delay: "7000",
// repeat: "15",
// note: "",
// },
];
socket?.emit(
"run_scenario",

View File

@ -45,6 +45,7 @@ const TerminalCLI: React.FC<TerminalCLIProps> = ({
const terminal = useRef<Terminal>(null);
const fitRef = useRef<FitAddon>(null);
const [loading, setLoading] = useState<boolean>(true);
const [isInit, setIsInit] = useState<boolean>(false);
useEffect(() => {
if (!cliOpened || fitRef.current) return;
@ -134,14 +135,15 @@ const TerminalCLI: React.FC<TerminalCLIProps> = ({
if (cliOpened) {
setTimeout(() => {
setLoading(false);
}, 200);
}, 500);
}
}, [cliOpened]);
useEffect(() => {
if (!loading) {
if (!loading && !isInit) {
if (terminal.current) {
terminal.current?.write(initContent);
setIsInit(true);
if (!miniSize && !isDisabled) terminal.current?.focus();
terminal.current.scrollToBottom();
}
@ -159,6 +161,7 @@ const TerminalCLI: React.FC<TerminalCLIProps> = ({
useEffect(() => {
return () => {
setLoading(true);
setIsInit(false);
// if (terminal.current) {
// terminal?.current.clear();
// terminal?.current.dispose();