Update line_connection.ts
This commit is contained in:
parent
8580f3c88a
commit
429c570688
|
|
@ -157,7 +157,9 @@ export default class LineConnection {
|
|||
this.outputPhysicalTest = ''
|
||||
this.listDeviceIos = []
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to line with socket
|
||||
*/
|
||||
connect(timeoutMs = 5000) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const { ip, port, lineNumber, id, stationId } = this.config
|
||||
|
|
@ -304,10 +306,16 @@ export default class LineConnection {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Waiting with millisecond
|
||||
*/
|
||||
private sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a command with socket.write
|
||||
*/
|
||||
async writeCommand(cmd: string | Buffer<ArrayBuffer>, userName = '') {
|
||||
if (this.client.destroyed) {
|
||||
console.log(`⚠️ Cannot send, line ${this.config.lineNumber} is closed`)
|
||||
|
|
@ -326,6 +334,9 @@ export default class LineConnection {
|
|||
this.client.write(cmd)
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect socket with line
|
||||
*/
|
||||
async disconnect() {
|
||||
try {
|
||||
console.log('[DISCONNECT] Line', this.config.lineNumber)
|
||||
|
|
@ -342,6 +353,9 @@ export default class LineConnection {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a scenario as DPELP, Breaking password, load ios,...
|
||||
*/
|
||||
async runScript(script: Scenario, userName: string) {
|
||||
if (!this.client || this.client.destroyed) {
|
||||
console.log('Not connected')
|
||||
|
|
@ -575,7 +589,7 @@ export default class LineConnection {
|
|||
// }
|
||||
|
||||
if (typeof step.send !== 'undefined') {
|
||||
// console.log(Date.now() - now, (step?.send ?? '[ENTER]').toString())
|
||||
console.log(Date.now() - now, (step?.send ?? '[ENTER]').toString())
|
||||
this.outputScenario += `\n---send-command---"${(step?.send ?? '[ENTER]').toString().replace(/\r/g, '\\r').replace(/\n/g, '\\n')}"---${now}---\n`
|
||||
appendLog(
|
||||
`\n---send-command---"${(step?.send ?? '[ENTER]').toString().replace(/\r/g, '\\r').replace(/\n/g, '\\n')}"---${now}---\n`,
|
||||
|
|
@ -620,6 +634,9 @@ export default class LineConnection {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconnect socket with line
|
||||
*/
|
||||
public async reconnect(): Promise<boolean> {
|
||||
try {
|
||||
this.disconnect()
|
||||
|
|
@ -632,6 +649,9 @@ export default class LineConnection {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* User open CLI from front-end
|
||||
*/
|
||||
userOpenCLI(user: User) {
|
||||
this.config.openCLI = true
|
||||
this.config.userEmailOpenCLI = user.userEmail
|
||||
|
|
@ -651,6 +671,9 @@ export default class LineConnection {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* User close CLI from front-end
|
||||
*/
|
||||
userCloseCLI() {
|
||||
this.config.openCLI = false
|
||||
this.config.userEmailOpenCLI = ''
|
||||
|
|
@ -662,6 +685,9 @@ export default class LineConnection {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear output buffer
|
||||
*/
|
||||
clearCLI() {
|
||||
this.config.output = ''
|
||||
this.socketIO.emit('user_clear_terminal', {
|
||||
|
|
@ -671,6 +697,9 @@ export default class LineConnection {
|
|||
setTimeout(() => this.writeCommand('\r\n'), 100)
|
||||
}
|
||||
|
||||
/**
|
||||
* Waiting for a expect with until catch it from output
|
||||
*/
|
||||
waitForExpect = async (expect: string, timeout = 60000) => {
|
||||
const start = Date.now()
|
||||
// console.log('[EXPECT]', expect, timeout)
|
||||
|
|
@ -684,6 +713,9 @@ export default class LineConnection {
|
|||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect inventory data from output
|
||||
*/
|
||||
getInventory = () => {
|
||||
const data = textfsmResults(this.outputInventory, 'show inventory')
|
||||
try {
|
||||
|
|
@ -714,7 +746,9 @@ export default class LineConnection {
|
|||
}
|
||||
}
|
||||
|
||||
// Gửi nhiều ký tự ESC để vào ROMMON
|
||||
/**
|
||||
* Gửi nhiều ký tự ESC để vào ROMMON
|
||||
*/
|
||||
breakSpam() {
|
||||
console.log('SPAM Break to line:', this.config.lineNumber)
|
||||
let count = 0
|
||||
|
|
@ -728,6 +762,9 @@ export default class LineConnection {
|
|||
}, 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Baud of line
|
||||
*/
|
||||
async setBaud(baud: number) {
|
||||
this.writeCommand('enable\r\n')
|
||||
await sleep(500)
|
||||
|
|
@ -743,6 +780,9 @@ export default class LineConnection {
|
|||
this.writeCommand('\r\n')
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content's log of line with date
|
||||
*/
|
||||
async getLog(date: string) {
|
||||
const logDir = path.join('storage', 'system_logs')
|
||||
const logFile = path
|
||||
|
|
@ -759,6 +799,9 @@ export default class LineConnection {
|
|||
return await fs.promises.readFile(logFile, 'utf8')
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect log by call api gpt, return summary and issues
|
||||
*/
|
||||
async detectLogWithAI(log: string) {
|
||||
try {
|
||||
const payload = {
|
||||
|
|
@ -812,6 +855,9 @@ export default class LineConnection {
|
|||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
* Add cache to list history devices on this line
|
||||
*/
|
||||
async addHistory(stationId: number, lineId: number, item: HistoryItem) {
|
||||
if (!item.pid || !item.sn) return
|
||||
const key = `station:${stationId}:line:${lineId}:history`
|
||||
|
|
@ -850,12 +896,18 @@ export default class LineConnection {
|
|||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list history devices
|
||||
*/
|
||||
async getHistory(stationId: number, lineId: number) {
|
||||
const key = `station:${stationId}:line:${lineId}:history`
|
||||
const items = await redis.zrange(key, 0, -1)
|
||||
return items.map((i) => JSON.parse(i))
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle raw log to regex error
|
||||
*/
|
||||
handleLogLine = (line: string) => {
|
||||
try {
|
||||
const parsed = classifyLog(line)
|
||||
|
|
@ -865,6 +917,9 @@ export default class LineConnection {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check raw log was regex each 5 minutes, if has error will send email report
|
||||
*/
|
||||
checkLog() {
|
||||
const interval = setInterval(async () => {
|
||||
try {
|
||||
|
|
@ -902,6 +957,9 @@ export default class LineConnection {
|
|||
}, 300000)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render table to view error
|
||||
*/
|
||||
renderErrorTable(rows: ErrorRow[]): string {
|
||||
if (!rows.length) {
|
||||
return `<p style="color: green;">No errors detected</p>`
|
||||
|
|
@ -942,6 +1000,9 @@ export default class LineConnection {
|
|||
`
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a body email
|
||||
*/
|
||||
buildEmailContent(result: TestResult): string {
|
||||
const rows = mapErrorsToRows(result.errors)
|
||||
const table = this.renderErrorTable(rows)
|
||||
|
|
@ -956,6 +1017,9 @@ export default class LineConnection {
|
|||
`
|
||||
}
|
||||
|
||||
/**
|
||||
* Update note of SN to ERP after run DPELP
|
||||
*/
|
||||
async updateNote(sn: string, data: DataDPELP) {
|
||||
const licenses = Array.isArray(data.license)
|
||||
? [...new Set(data.license)]
|
||||
|
|
@ -968,6 +1032,9 @@ export default class LineConnection {
|
|||
await updateNoteToERP(sn, note)
|
||||
}
|
||||
|
||||
/**
|
||||
* Starting physical test (PoE ports testing)
|
||||
*/
|
||||
async runPhysicalTest() {
|
||||
if (this.config.runningPhysical) {
|
||||
console.log('Running physical test')
|
||||
|
|
@ -1002,6 +1069,9 @@ export default class LineConnection {
|
|||
// }, 10000)
|
||||
}
|
||||
|
||||
/**
|
||||
* End all testing
|
||||
*/
|
||||
endTesting() {
|
||||
this.physicalTest.done = true
|
||||
this.physicalTest.resetTestedPorts()
|
||||
|
|
@ -1018,6 +1088,9 @@ export default class LineConnection {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list PoE ports
|
||||
*/
|
||||
async getPorts(): Promise<string[]> {
|
||||
this.writeCommand(' show power inline\r\n')
|
||||
this.writeCommand(' \r\n')
|
||||
|
|
@ -1040,6 +1113,9 @@ export default class LineConnection {
|
|||
return [...new Set(ports)]
|
||||
}
|
||||
|
||||
/**
|
||||
* Send report after done physical test
|
||||
*/
|
||||
async sendReportPhysicalTest() {
|
||||
const formReport = this.physicalTest.getFormReport()
|
||||
await sendMessageToMail(
|
||||
|
|
@ -1048,6 +1124,9 @@ export default class LineConnection {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle load ios for router
|
||||
*/
|
||||
async loadIosRouter(nameIos: string, userName: string) {
|
||||
const station = await Station.find(this.config.stationId)
|
||||
if (!station) return
|
||||
|
|
@ -1193,6 +1272,9 @@ export default class LineConnection {
|
|||
await this.sendEmailLoadIos(nameIos, startTime)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle load ios for switch
|
||||
*/
|
||||
async loadIosSwitch(nameIos: string, userName: string) {
|
||||
const station = await Station.find(this.config.stationId)
|
||||
if (!station) return
|
||||
|
|
@ -1402,6 +1484,9 @@ export default class LineConnection {
|
|||
await this.sendEmailLoadIos(nameIos, startTime)
|
||||
}
|
||||
|
||||
/**
|
||||
* Send mail report after load ios
|
||||
*/
|
||||
async sendEmailLoadIos(nameIos: string, startTime: string) {
|
||||
const timeZone = process.env.TIME_ZONE || 'Australia/Sydney'
|
||||
const dataFormat = momentTZ().tz(timeZone).format('YYYY/MM/DD, HH:mm:ss')
|
||||
|
|
@ -1422,20 +1507,38 @@ export default class LineConnection {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check list ios exist on flash
|
||||
*/
|
||||
async checkDeviceFlash() {
|
||||
this.writeCommand(' enable\r\n')
|
||||
this.writeCommand('show flash:\r\n')
|
||||
await sleep(2000)
|
||||
const ios = []
|
||||
const binRegex = /^\s*\d+\s+-rwx\s+\d+\s+.*?\s+([^\s]+\.bin)\s*$/gim
|
||||
|
||||
const output = this.outputBuffer
|
||||
const ios: string[] = []
|
||||
let match
|
||||
while ((match = binRegex.exec(this.outputBuffer)) !== null) {
|
||||
ios.push(match[1])
|
||||
|
||||
const SWITCH_BIN_REGEX = /^\s*\d+\s+-rwx\s+\d+\s+.*?\s+([^\s]+\.bin)\s*$/gim
|
||||
const ROUTER_BIN_REGEX = /^\s*\d+\s+(\d+)\s+.*?\s+([^\s]+\.bin)\s*$/gim
|
||||
|
||||
// 🔍 Detect device type
|
||||
const isSwitch = output.includes('-rwx')
|
||||
const regex = isSwitch ? SWITCH_BIN_REGEX : ROUTER_BIN_REGEX
|
||||
|
||||
// reset regex state
|
||||
regex.lastIndex = 0
|
||||
|
||||
while ((match = regex.exec(output)) !== null) {
|
||||
ios.push(isSwitch ? match[1] : match[2])
|
||||
}
|
||||
|
||||
return ios
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete File on Flash
|
||||
*/
|
||||
async deleteFileOnFlash(fileName: string) {
|
||||
await this.writeCommand(`delete flash:${fileName}\r\n`)
|
||||
await this.writeCommand(`\r\n`)
|
||||
|
|
@ -1443,6 +1546,9 @@ export default class LineConnection {
|
|||
await sleep(3000)
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload file from flash to TFTP server
|
||||
*/
|
||||
async uploadFileToServerTFTP(fileName: string, server: string) {
|
||||
this.config.runningScenario = 'Upload file'
|
||||
await this.writeCommand(`copy flash: tftp:\r\n`)
|
||||
|
|
@ -1460,7 +1566,9 @@ export default class LineConnection {
|
|||
}
|
||||
}
|
||||
|
||||
// function get list ios
|
||||
/**
|
||||
* Get list ios from TFTP server
|
||||
*/
|
||||
async getListIos() {
|
||||
try {
|
||||
const controller = new IosLicenseController()
|
||||
|
|
@ -1472,6 +1580,9 @@ export default class LineConnection {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current boot ios of device
|
||||
*/
|
||||
async getCurrentBootIos() {
|
||||
this.writeCommand('show version | include System image\r\n')
|
||||
await sleep(2000)
|
||||
|
|
@ -1482,6 +1593,9 @@ export default class LineConnection {
|
|||
return match ? match[1] : null
|
||||
}
|
||||
|
||||
/**
|
||||
* Backup ios to TFTP, after that delete it on flash for free space
|
||||
*/
|
||||
async backupIos(nameIos: string) {
|
||||
const station = await Station.find(this.config.stationId)
|
||||
if (!station) return
|
||||
|
|
|
|||
Loading…
Reference in New Issue