Update
This commit is contained in:
parent
077a2ddc35
commit
ef1d585b61
|
|
@ -1,5 +1,6 @@
|
||||||
import net from 'node:net'
|
import net from 'node:net'
|
||||||
import { cleanData } from '../ultils/helper.js'
|
import { cleanData } from '../ultils/helper.js'
|
||||||
|
import Scenario from '#models/scenario'
|
||||||
|
|
||||||
interface LineConfig {
|
interface LineConfig {
|
||||||
id: number
|
id: number
|
||||||
|
|
@ -16,11 +17,17 @@ export default class LineConnection {
|
||||||
public client: net.Socket
|
public client: net.Socket
|
||||||
public readonly config: LineConfig
|
public readonly config: LineConfig
|
||||||
public readonly socketIO: any
|
public readonly socketIO: any
|
||||||
|
private outputBuffer: string
|
||||||
|
private isRunningScript: boolean
|
||||||
|
private connecting: boolean
|
||||||
|
|
||||||
constructor(config: LineConfig, socketIO: any) {
|
constructor(config: LineConfig, socketIO: any) {
|
||||||
this.config = config
|
this.config = config
|
||||||
this.socketIO = socketIO
|
this.socketIO = socketIO
|
||||||
this.client = new net.Socket()
|
this.client = new net.Socket()
|
||||||
|
this.outputBuffer = ''
|
||||||
|
this.isRunningScript = false
|
||||||
|
this.connecting = false
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(timeoutMs = 5000) {
|
connect(timeoutMs = 5000) {
|
||||||
|
|
@ -35,18 +42,24 @@ export default class LineConnection {
|
||||||
resolvedOrRejected = true
|
resolvedOrRejected = true
|
||||||
|
|
||||||
console.log(`✅ Connected to line ${lineNumber} (${ip}:${port})`)
|
console.log(`✅ Connected to line ${lineNumber} (${ip}:${port})`)
|
||||||
this.config.status = 'connected'
|
this.connecting = true
|
||||||
this.socketIO.emit('line_connected', {
|
setTimeout(() => {
|
||||||
stationId,
|
this.config.status = 'connected'
|
||||||
lineId: id,
|
this.connecting = false
|
||||||
lineNumber,
|
this.socketIO.emit('line_connected', {
|
||||||
status: 'connected',
|
stationId,
|
||||||
})
|
lineId: id,
|
||||||
resolve()
|
lineNumber,
|
||||||
|
status: 'connected',
|
||||||
|
})
|
||||||
|
resolve()
|
||||||
|
}, 1000)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.client.on('data', (data) => {
|
this.client.on('data', (data) => {
|
||||||
|
if (this.connecting) return
|
||||||
let message = data.toString()
|
let message = data.toString()
|
||||||
|
this.outputBuffer += message
|
||||||
// let output = cleanData(message)
|
// let output = cleanData(message)
|
||||||
// console.log(`📨 [${this.config.port}] ${message}`)
|
// console.log(`📨 [${this.config.port}] ${message}`)
|
||||||
// Handle netOutput with backspace support
|
// Handle netOutput with backspace support
|
||||||
|
|
@ -74,7 +87,7 @@ export default class LineConnection {
|
||||||
this.socketIO.emit('line_error', {
|
this.socketIO.emit('line_error', {
|
||||||
stationId,
|
stationId,
|
||||||
lineId: id,
|
lineId: id,
|
||||||
error: err.message,
|
error: err.message + '\r\n',
|
||||||
})
|
})
|
||||||
reject(err)
|
reject(err)
|
||||||
})
|
})
|
||||||
|
|
@ -101,15 +114,6 @@ export default class LineConnection {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
sendCommand(cmd: string) {
|
|
||||||
if (this.client.destroyed) {
|
|
||||||
console.log(`⚠️ Cannot send, line ${this.config.lineNumber} is closed`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// console.log(`➡️ [${this.config.apcName}] SEND:`, cmd)
|
|
||||||
this.client.write(`${cmd}\r\n`)
|
|
||||||
}
|
|
||||||
|
|
||||||
writeCommand(cmd: string) {
|
writeCommand(cmd: string) {
|
||||||
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`)
|
||||||
|
|
@ -131,4 +135,75 @@ export default class LineConnection {
|
||||||
console.error('Error closing line:', e)
|
console.error('Error closing line:', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async runScript(script: Scenario) {
|
||||||
|
if (!this.client || this.client.destroyed) {
|
||||||
|
throw new Error('Not connected')
|
||||||
|
}
|
||||||
|
if (this.isRunningScript) {
|
||||||
|
throw new Error('Script already running')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isRunningScript = true
|
||||||
|
const steps = typeof script?.body === 'string' ? JSON.parse(script?.body) : []
|
||||||
|
let stepIndex = 0
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const timeoutTimer = setTimeout(() => {
|
||||||
|
this.isRunningScript = false
|
||||||
|
this.outputBuffer = ''
|
||||||
|
reject(new Error('Script timeout'))
|
||||||
|
}, script.timeout || 300000)
|
||||||
|
|
||||||
|
const runStep = (index: number) => {
|
||||||
|
if (index >= steps.length) {
|
||||||
|
clearTimeout(timeoutTimer)
|
||||||
|
this.isRunningScript = false
|
||||||
|
this.outputBuffer = ''
|
||||||
|
resolve(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const step = steps[index]
|
||||||
|
let repeatCount = Number(step.repeat) || 1
|
||||||
|
|
||||||
|
const sendCommand = () => {
|
||||||
|
if (repeatCount <= 0) {
|
||||||
|
// Done → next step
|
||||||
|
this.client.off('data', onOutput)
|
||||||
|
stepIndex++
|
||||||
|
return runStep(stepIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step.send) {
|
||||||
|
this.writeCommand(step?.send + '\r\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
repeatCount--
|
||||||
|
setTimeout(() => sendCommand(), Number(step?.delay) || 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lắng nghe output cho expect
|
||||||
|
const onOutput = (data: string) => {
|
||||||
|
const output = data.toString()
|
||||||
|
this.outputBuffer += output
|
||||||
|
|
||||||
|
if (output.includes(step.expect)) {
|
||||||
|
this.client.off('data', onOutput)
|
||||||
|
setTimeout(() => sendCommand(), Number(step?.delay) || 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nếu expect rỗng → gửi ngay
|
||||||
|
if (!step?.expect || step?.expect.trim() === '') {
|
||||||
|
setTimeout(() => sendCommand(), Number(step?.delay) || 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.client.on('data', onOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
runStep(stepIndex)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* @param {string} data - The raw data to be cleaned.
|
* @param {string} data - The raw data to be cleaned.
|
||||||
* @returns {string} - The cleaned data.
|
* @returns {string} - The cleaned data.
|
||||||
*/
|
*/
|
||||||
export const cleanData = (data) => {
|
export const cleanData = (data: string) => {
|
||||||
return data
|
return data
|
||||||
.replace(/--More--\s*BS\s*BS\s*BS\s*BS\s*BS\s*BS/g, '')
|
.replace(/--More--\s*BS\s*BS\s*BS\s*BS\s*BS\s*BS/g, '')
|
||||||
.replace(/\s*--More--\s*/g, '')
|
.replace(/\s*--More--\s*/g, '')
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,7 @@ import { ApplicationService } from '@adonisjs/core/types'
|
||||||
import env from '#start/env'
|
import env from '#start/env'
|
||||||
import { CustomServer, CustomSocket } from '../app/ultils/types.js'
|
import { CustomServer, CustomSocket } from '../app/ultils/types.js'
|
||||||
import Line from '#models/line'
|
import Line from '#models/line'
|
||||||
|
import Station from '#models/station'
|
||||||
interface Station {
|
|
||||||
id: number
|
|
||||||
name: string
|
|
||||||
ip: string
|
|
||||||
lines: any[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class SocketIoProvider {
|
export default class SocketIoProvider {
|
||||||
private static _io: CustomServer
|
private static _io: CustomServer
|
||||||
|
|
@ -78,11 +72,12 @@ export class WebSocketIo {
|
||||||
console.log('Socket connected:', socket.id)
|
console.log('Socket connected:', socket.id)
|
||||||
socket.connectionTime = new Date()
|
socket.connectionTime = new Date()
|
||||||
|
|
||||||
const lineConnectionArray: LineConnection[] = Array.from(this.lineMap.values())
|
setTimeout(() => {
|
||||||
io.to(socket.id).emit(
|
io.to(socket.id).emit(
|
||||||
'init',
|
'init',
|
||||||
lineConnectionArray.map((el) => el.config)
|
Array.from(this.lineMap.values()).map((el) => el.config)
|
||||||
)
|
)
|
||||||
|
}, 200)
|
||||||
|
|
||||||
socket.on('disconnect', () => {
|
socket.on('disconnect', () => {
|
||||||
console.log(`FE disconnected: ${socket.id}`)
|
console.log(`FE disconnected: ${socket.id}`)
|
||||||
|
|
@ -94,16 +89,59 @@ export class WebSocketIo {
|
||||||
await this.connectLine(io, linesData, stationData)
|
await this.connectLine(io, linesData, stationData)
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on('write_command_line_from_web', (data) => {
|
socket.on('write_command_line_from_web', async (data) => {
|
||||||
const { lineIds, stationId, command } = data
|
const { lineIds, stationId, command } = data
|
||||||
for (const lineId of lineIds) {
|
for (const lineId of lineIds) {
|
||||||
const line = this.lineMap.get(lineId)
|
const line = this.lineMap.get(lineId)
|
||||||
if (line) {
|
if (line) {
|
||||||
this.setTimeoutConnect(lineId, line)
|
this.setTimeoutConnect(lineId, line)
|
||||||
line.writeCommand(command)
|
line.writeCommand(command)
|
||||||
|
} else {
|
||||||
|
const linesData = await Line.findBy('id', lineId)
|
||||||
|
const stationData = await Station.findBy('id', stationId)
|
||||||
|
if (linesData && stationData) {
|
||||||
|
await this.connectLine(io, [linesData], stationData)
|
||||||
|
const lineReconnect = this.lineMap.get(lineId)
|
||||||
|
if (lineReconnect) {
|
||||||
|
this.setTimeoutConnect(lineId, lineReconnect)
|
||||||
|
lineReconnect.writeCommand(command)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
io.emit('line_disconnected', {
|
||||||
|
stationId,
|
||||||
|
lineId,
|
||||||
|
status: 'disconnected',
|
||||||
|
})
|
||||||
|
io.emit('line_error', { lineId, error: 'Line not connected\r\n' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
socket.on('run_scenario', async (data) => {
|
||||||
|
const lineId = data.id
|
||||||
|
const scenario = data.scenario
|
||||||
|
const line = this.lineMap.get(lineId)
|
||||||
|
if (line) {
|
||||||
|
this.setTimeoutConnect(
|
||||||
|
lineId,
|
||||||
|
line,
|
||||||
|
scenario?.timeout ? Number(scenario?.timeout) + 120000 : 300000
|
||||||
|
)
|
||||||
|
line.runScript(scenario)
|
||||||
|
} else {
|
||||||
|
const linesData = await Line.findBy('id', lineId)
|
||||||
|
const stationData = await Station.findBy('id', data.stationId)
|
||||||
|
if (linesData && stationData) {
|
||||||
|
await this.connectLine(io, [linesData], stationData)
|
||||||
|
const lineReconnect = this.lineMap.get(lineId)
|
||||||
|
if (lineReconnect) {
|
||||||
|
this.setTimeoutConnect(lineId, lineReconnect, 300000)
|
||||||
|
lineReconnect.runScript(scenario)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
io.emit('line_disconnected', {
|
io.emit('line_disconnected', {
|
||||||
stationId,
|
stationId: data.stationId,
|
||||||
lineId,
|
lineId,
|
||||||
status: 'disconnected',
|
status: 'disconnected',
|
||||||
})
|
})
|
||||||
|
|
@ -168,7 +206,7 @@ export class WebSocketIo {
|
||||||
console.log(`🔻 Station ${station.name} disconnected`)
|
console.log(`🔻 Station ${station.name} disconnected`)
|
||||||
}
|
}
|
||||||
|
|
||||||
private setTimeoutConnect = (lineId: number, lineConn: LineConnection) => {
|
private setTimeoutConnect = (lineId: number, lineConn: LineConnection, timeout = 120000) => {
|
||||||
if (this.intervalMap[`${lineId}`]) {
|
if (this.intervalMap[`${lineId}`]) {
|
||||||
clearInterval(this.intervalMap[`${lineId}`])
|
clearInterval(this.intervalMap[`${lineId}`])
|
||||||
delete this.intervalMap[`${lineId}`]
|
delete this.intervalMap[`${lineId}`]
|
||||||
|
|
@ -176,7 +214,11 @@ export class WebSocketIo {
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
lineConn.disconnect()
|
lineConn.disconnect()
|
||||||
this.lineMap.delete(lineId)
|
this.lineMap.delete(lineId)
|
||||||
}, 120000)
|
if (this.intervalMap[`${lineId}`]) {
|
||||||
|
clearInterval(this.intervalMap[`${lineId}`])
|
||||||
|
delete this.intervalMap[`${lineId}`]
|
||||||
|
}
|
||||||
|
}, timeout)
|
||||||
|
|
||||||
this.intervalMap[`${lineId}`] = interval
|
this.intervalMap[`${lineId}`] = interval
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,12 @@ import {
|
||||||
Button,
|
Button,
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import type { TLine, TStation } from "./untils/types";
|
import type { LineConfig, TLine, TStation } from "./untils/types";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import CardLine from "./components/CardLine";
|
import CardLine from "./components/CardLine";
|
||||||
import { IconEdit, IconSettingsPlus } from "@tabler/icons-react";
|
import { IconEdit, IconSettingsPlus } from "@tabler/icons-react";
|
||||||
import { SocketProvider, useSocket } from "./context/SocketContext";
|
import { SocketProvider, useSocket } from "./context/SocketContext";
|
||||||
|
import { ButtonDPELP } from "./components/ButtonAction";
|
||||||
|
|
||||||
const apiUrl = import.meta.env.VITE_BACKEND_URL;
|
const apiUrl = import.meta.env.VITE_BACKEND_URL;
|
||||||
|
|
||||||
|
|
@ -43,6 +44,7 @@ export function App() {
|
||||||
setControlsRefs(controlsRefs);
|
setControlsRefs(controlsRefs);
|
||||||
};
|
};
|
||||||
const [showBottomShadow, setShowBottomShadow] = useState(false);
|
const [showBottomShadow, setShowBottomShadow] = useState(false);
|
||||||
|
const [isDisable, setIsDisable] = useState(false);
|
||||||
|
|
||||||
// function get list station
|
// function get list station
|
||||||
const getStation = async () => {
|
const getStation = async () => {
|
||||||
|
|
@ -67,35 +69,27 @@ export function App() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!socket || !stations?.length) return;
|
if (!socket || !stations?.length) return;
|
||||||
|
|
||||||
const updateStatus = (data: any) => {
|
|
||||||
const line = getLine(data.lineId, data.stationId);
|
|
||||||
if (line) {
|
|
||||||
updateValueLineStation(line, "status", data.status);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.on("line_connected", updateStatus);
|
socket.on("line_connected", updateStatus);
|
||||||
socket.on("line_disconnected", updateStatus);
|
socket.on("line_disconnected", updateStatus);
|
||||||
socket?.on("init", (data) => {
|
|
||||||
if (Array.isArray(data)) {
|
|
||||||
data.forEach((value) => {
|
|
||||||
updateStatus(value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// ✅ cleanup on unmount or when socket changes
|
// ✅ cleanup on unmount or when socket changes
|
||||||
return () => {
|
return () => {
|
||||||
socket.off("line_connected");
|
socket.off("line_connected");
|
||||||
socket.off("line_disconnected");
|
socket.off("line_disconnected");
|
||||||
socket.off("line_disconnected");
|
|
||||||
};
|
};
|
||||||
}, [socket, stations]);
|
}, [socket, stations]);
|
||||||
|
|
||||||
const updateValueLineStation = (
|
const updateStatus = (data: LineConfig) => {
|
||||||
|
const line = getLine(data.lineId, data.stationId);
|
||||||
|
if (line) {
|
||||||
|
updateValueLineStation(line, "status", data.status);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateValueLineStation = <K extends keyof TLine>(
|
||||||
currentLine: TLine,
|
currentLine: TLine,
|
||||||
field: string,
|
field: K,
|
||||||
value: any
|
value: TLine[K]
|
||||||
) => {
|
) => {
|
||||||
setStations((el) =>
|
setStations((el) =>
|
||||||
el?.map((station: TStation) =>
|
el?.map((station: TStation) =>
|
||||||
|
|
@ -201,6 +195,7 @@ export function App() {
|
||||||
line={line}
|
line={line}
|
||||||
selectedLines={selectedLines}
|
selectedLines={selectedLines}
|
||||||
setSelectedLines={setSelectedLines}
|
setSelectedLines={setSelectedLines}
|
||||||
|
updateStatus={updateStatus}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
@ -223,7 +218,7 @@ export function App() {
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
variant="filled"
|
variant="filled"
|
||||||
style={{ height: "30px", width: "120px" }}
|
style={{ height: "30px", width: "100px" }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (selectedLines.length !== station.lines.length)
|
if (selectedLines.length !== station.lines.length)
|
||||||
setSelectedLines(station.lines);
|
setSelectedLines(station.lines);
|
||||||
|
|
@ -240,7 +235,7 @@ export function App() {
|
||||||
.length === 0
|
.length === 0
|
||||||
}
|
}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
style={{ height: "30px", width: "120px" }}
|
style={{ height: "30px", width: "100px" }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const lines = selectedLines.filter(
|
const lines = selectedLines.filter(
|
||||||
(el) => el.status !== "connected"
|
(el) => el.status !== "connected"
|
||||||
|
|
@ -254,6 +249,18 @@ export function App() {
|
||||||
>
|
>
|
||||||
Connect
|
Connect
|
||||||
</Button>
|
</Button>
|
||||||
|
<ButtonDPELP
|
||||||
|
socket={socket}
|
||||||
|
selectedLines={selectedLines}
|
||||||
|
isDisable={isDisable || selectedLines.length === 0}
|
||||||
|
onClick={() => {
|
||||||
|
setSelectedLines([]);
|
||||||
|
setIsDisable(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsDisable(false);
|
||||||
|
}, 10000);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
import type { Socket } from "socket.io-client";
|
||||||
|
import type { TLine } from "../untils/types";
|
||||||
|
import { Button } from "@mantine/core";
|
||||||
|
|
||||||
|
export const ButtonDPELP = ({
|
||||||
|
socket,
|
||||||
|
isDisable,
|
||||||
|
onClick,
|
||||||
|
selectedLines,
|
||||||
|
}: {
|
||||||
|
socket: Socket | null;
|
||||||
|
isDisable: boolean;
|
||||||
|
onClick: () => void;
|
||||||
|
selectedLines: TLine[];
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
disabled={isDisable}
|
||||||
|
miw={"100px"}
|
||||||
|
// radius="lg"
|
||||||
|
h={"24px"}
|
||||||
|
mr={"5px"}
|
||||||
|
variant="filled"
|
||||||
|
color="#00a164"
|
||||||
|
onClick={async () => {
|
||||||
|
onClick();
|
||||||
|
selectedLines?.forEach((el) => {
|
||||||
|
const body = [
|
||||||
|
{
|
||||||
|
expect: "",
|
||||||
|
send: " show diag",
|
||||||
|
delay: "1000",
|
||||||
|
repeat: "1",
|
||||||
|
note: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expect: "",
|
||||||
|
send: " ",
|
||||||
|
delay: "1000",
|
||||||
|
repeat: "1",
|
||||||
|
note: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expect: "",
|
||||||
|
send: " show post",
|
||||||
|
delay: "1000",
|
||||||
|
repeat: "1",
|
||||||
|
note: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expect: "",
|
||||||
|
send: " ",
|
||||||
|
delay: "1000",
|
||||||
|
repeat: "1",
|
||||||
|
note: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expect: "",
|
||||||
|
send: " show env",
|
||||||
|
delay: "1000",
|
||||||
|
repeat: "1",
|
||||||
|
note: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expect: "",
|
||||||
|
send: " ",
|
||||||
|
delay: "1000",
|
||||||
|
repeat: "1",
|
||||||
|
note: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expect: "",
|
||||||
|
send: " show license",
|
||||||
|
delay: "1000",
|
||||||
|
repeat: "1",
|
||||||
|
note: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expect: "",
|
||||||
|
send: " ",
|
||||||
|
delay: "1000",
|
||||||
|
repeat: "1",
|
||||||
|
note: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expect: "",
|
||||||
|
send: " show log",
|
||||||
|
delay: "1000",
|
||||||
|
repeat: "1",
|
||||||
|
note: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expect: "",
|
||||||
|
send: " ",
|
||||||
|
delay: "1000",
|
||||||
|
repeat: "2",
|
||||||
|
note: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expect: "",
|
||||||
|
send: " show platform",
|
||||||
|
delay: "1000",
|
||||||
|
repeat: "1",
|
||||||
|
note: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expect: "",
|
||||||
|
send: " ",
|
||||||
|
delay: "7000",
|
||||||
|
repeat: "15",
|
||||||
|
note: "",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
socket?.emit(
|
||||||
|
"run_scenario",
|
||||||
|
Object.assign(el, {
|
||||||
|
scenario: {
|
||||||
|
id: 0,
|
||||||
|
is_reboot: 0,
|
||||||
|
title: "DPELP",
|
||||||
|
timeout: 300000,
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
DPELP
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Card, Text, Box, Flex } from "@mantine/core";
|
import { Card, Text, Box, Flex } from "@mantine/core";
|
||||||
import type { TLine, TStation } from "../untils/types";
|
import type { LineConfig, TLine, TStation } from "../untils/types";
|
||||||
import classes from "./Component.module.css";
|
import classes from "./Component.module.css";
|
||||||
import TerminalCLI from "./TerminalXTerm";
|
import TerminalCLI from "./TerminalXTerm";
|
||||||
import type { Socket } from "socket.io-client";
|
import type { Socket } from "socket.io-client";
|
||||||
|
|
@ -12,12 +12,14 @@ const CardLine = ({
|
||||||
setSelectedLines,
|
setSelectedLines,
|
||||||
socket,
|
socket,
|
||||||
stationItem,
|
stationItem,
|
||||||
|
updateStatus,
|
||||||
}: {
|
}: {
|
||||||
line: TLine;
|
line: TLine;
|
||||||
selectedLines: TLine[];
|
selectedLines: TLine[];
|
||||||
setSelectedLines: (lines: React.SetStateAction<TLine[]>) => void;
|
setSelectedLines: (lines: React.SetStateAction<TLine[]>) => void;
|
||||||
socket: Socket | null;
|
socket: Socket | null;
|
||||||
stationItem: TStation;
|
stationItem: TStation;
|
||||||
|
updateStatus: (value: LineConfig) => void;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
|
|
@ -81,6 +83,7 @@ const CardLine = ({
|
||||||
paddingBottom: "0px",
|
paddingBottom: "0px",
|
||||||
}}
|
}}
|
||||||
onDoubleClick={() => {}}
|
onDoubleClick={() => {}}
|
||||||
|
updateStatus={updateStatus}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import "xterm/css/xterm.css";
|
||||||
import { FitAddon } from "@xterm/addon-fit";
|
import { FitAddon } from "@xterm/addon-fit";
|
||||||
import { SOCKET_EVENTS } from "../untils/constanst";
|
import { SOCKET_EVENTS } from "../untils/constanst";
|
||||||
import type { Socket } from "socket.io-client";
|
import type { Socket } from "socket.io-client";
|
||||||
|
import type { LineConfig } from "../untils/types";
|
||||||
|
|
||||||
interface TerminalCLIProps {
|
interface TerminalCLIProps {
|
||||||
socket: Socket | null;
|
socket: Socket | null;
|
||||||
|
|
@ -24,6 +25,7 @@ interface TerminalCLIProps {
|
||||||
onDoubleClick?: () => void;
|
onDoubleClick?: () => void;
|
||||||
fontSize?: number;
|
fontSize?: number;
|
||||||
miniSize?: boolean;
|
miniSize?: boolean;
|
||||||
|
updateStatus: (value: LineConfig) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TerminalCLI: React.FC<TerminalCLIProps> = ({
|
const TerminalCLI: React.FC<TerminalCLIProps> = ({
|
||||||
|
|
@ -33,11 +35,11 @@ const TerminalCLI: React.FC<TerminalCLIProps> = ({
|
||||||
station_id,
|
station_id,
|
||||||
cliOpened = false,
|
cliOpened = false,
|
||||||
isDisabled = false,
|
isDisabled = false,
|
||||||
line_status = "",
|
|
||||||
customStyle = {},
|
customStyle = {},
|
||||||
onDoubleClick = () => {},
|
onDoubleClick = () => {},
|
||||||
fontSize = 14,
|
fontSize = 14,
|
||||||
miniSize = false,
|
miniSize = false,
|
||||||
|
updateStatus,
|
||||||
}) => {
|
}) => {
|
||||||
const xtermRef = useRef<HTMLDivElement>(null);
|
const xtermRef = useRef<HTMLDivElement>(null);
|
||||||
const terminal = useRef<Terminal>(null);
|
const terminal = useRef<Terminal>(null);
|
||||||
|
|
@ -148,6 +150,7 @@ const TerminalCLI: React.FC<TerminalCLIProps> = ({
|
||||||
data.forEach((value) => {
|
data.forEach((value) => {
|
||||||
if (value?.id === line_id && terminal.current) {
|
if (value?.id === line_id && terminal.current) {
|
||||||
terminal.current?.write(value.output);
|
terminal.current?.write(value.output);
|
||||||
|
updateStatus({ ...value, lineId: value.id });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,3 +126,15 @@ export type SwitchPortsProps = {
|
||||||
status: string;
|
status: string;
|
||||||
poe: string;
|
poe: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type LineConfig = {
|
||||||
|
id: number;
|
||||||
|
lineId: number;
|
||||||
|
port: number;
|
||||||
|
lineNumber: number;
|
||||||
|
ip: string;
|
||||||
|
stationId: number;
|
||||||
|
apcName?: string;
|
||||||
|
output: string;
|
||||||
|
status: string;
|
||||||
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue