diff --git a/BACKEND/app/services/line_connection.ts b/BACKEND/app/services/line_connection.ts index 6253983..032f9d1 100644 --- a/BACKEND/app/services/line_connection.ts +++ b/BACKEND/app/services/line_connection.ts @@ -6,6 +6,7 @@ import { cleanData, getLogWithTimeScenario, isValidJson, + mapToLineFormat, sleep, } from '../ultils/helper.js' import Scenario from '#models/scenario' @@ -15,6 +16,15 @@ import path from 'node:path' import axios from 'axios' import redis from '@adonisjs/redis/services/main' +type Inventory = { + pid: string + vid: string + sn: string + licenseLevel: string + licenseType: string + nextLicenseLevel: string +} + interface LineConfig { id: number port: number @@ -84,7 +94,7 @@ export default class LineConnection { private outputInventory: string private outputScenario: string private bufferCommand: string - private retryConnect: number + public dataDPELP: string constructor(config: LineConfig, socketIO: any) { this.config = config @@ -97,7 +107,7 @@ export default class LineConnection { this.outputInventory = '' this.outputScenario = '' this.bufferCommand = '' - this.retryConnect = 0 + this.dataDPELP = 'No data' } connect(timeoutMs = 5000) { @@ -160,7 +170,7 @@ export default class LineConnection { if (!this.config.inventory) { setTimeout(() => { this.getInventory() - }, 3000) + }, 5000) } appendLog( cleanData(message), @@ -227,13 +237,7 @@ export default class LineConnection { this.disconnect() await sleep(2000) await this.connect() - // await this.writeCommand(cmd) - // if (this.retryConnect <= 3) { - // console.log('Retry connect times', this.retryConnect) - // this.retryConnect += 1 - // await this.connect() - // await this.writeCommand(cmd) - // } + return } @@ -293,7 +297,7 @@ export default class LineConnection { console.log( `Run scenario "${script?.title}" to line ${this.config.lineNumber} of ${this.config.stationName}` ) - + if (script?.title === 'DPELP') this.dataDPELP = '' this.isRunningScript = true const now = Date.now() this.outputScenario += `\n\n---start-scenarios---${now}---${userName}---${script?.title}---\n---scenario---${script?.title}---${now}---\n` @@ -378,6 +382,15 @@ export default class LineConnection { } }) const detectLog = await this.detectLogWithAI(logScenarios) + const result = mapToLineFormat({ + lineNumber: this.config.lineNumber, + inventory: this.config.inventory, + latestScenario: { + detectAI: detectLog, + }, + data, + }) + if (script?.title === 'DPELP') this.dataDPELP = result if (this.config.latestScenario) this.config.latestScenario = { ...this.config.latestScenario, detectAI: detectLog } this.config.data = data @@ -398,14 +411,6 @@ export default class LineConnection { } const step = steps[index] - this.outputScenario += `\n---send-command---"${step?.send ?? ''}"---${now}---\n` - appendLog( - `\n---send-command---"${step?.send ?? ''}"---${now}---\n`, - this.config.stationId, - this.config.stationName, - this.config.stationIp, - this.config.lineNumber - ) let repeatCount = Number(step.repeat) || 1 const sendCommand = async () => { if (repeatCount <= 0) { @@ -415,6 +420,14 @@ export default class LineConnection { } if (step.send) { + this.outputScenario += `\n---send-command---"${step?.send ?? ''}"---${now}---\n` + appendLog( + `\n---send-command---"${step?.send ?? ''}"---${now}---\n`, + this.config.stationId, + this.config.stationName, + this.config.stationIp, + this.config.lineNumber + ) this.writeCommand(step?.send + '\r\n') } diff --git a/BACKEND/app/ultils/helper.ts b/BACKEND/app/ultils/helper.ts index cebae53..9aa43b7 100644 --- a/BACKEND/app/ultils/helper.ts +++ b/BACKEND/app/ultils/helper.ts @@ -1,6 +1,20 @@ import fs from 'node:fs' import path from 'node:path' +type DetectAI = { + status: string[] + issue: string[] +} + +type InputData = { + lineNumber: number + inventory: any + latestScenario?: { + detectAI?: DetectAI + } + data?: any[] +} + /** * Function to clean up unwanted characters from the output data. * @param {string} data - The raw data to be cleaned. @@ -122,3 +136,54 @@ export function isValidJson(string: string) { return false // Chuỗi không phải là định dạng JSON hợp lệ } } + +export function mapToLineFormat(input: InputData): string { + const line = input.lineNumber + + // Inventory info + const pid = input.inventory?.pid || '' + const vid = input.inventory?.vid || '' + const sn = input.inventory?.sn || '' + + if (!pid || !sn) return `Line ${line}: No data` + + // Find MAC address from "show version" or other sources + let mac = '' + const showVersion = input.data?.find((d) => d.command === 'show version') + if (showVersion?.textfsm?.[0]?.MAC_ADDRESS) { + mac = showVersion.textfsm[0].MAC_ADDRESS + } + + // Get data license + const dataLicense = input.data?.find((comm: any) => comm.command?.trim() === 'show license') + const listLicense = + dataLicense?.textfsm && Array.isArray(dataLicense?.textfsm) + ? dataLicense?.textfsm?.map((val: any) => val.FEATURE).join(', ') + : '' + const dataPlatform = input.data?.find((el) => el.command?.trim() === 'show platform') + const DPELP = dataPlatform && !dataPlatform?.output?.includes('Incomplete') ? true : false + + // Detect AI issues + const issues = input.latestScenario?.detectAI?.issue || [] + + // Build output + let output = `Line ${line}: ` + output += `PID: ${pid}, ` + output += `VID: ${vid}, ` + output += `SN: ${sn}, ` + output += `Tested mode: ${DPELP ? 'DPELP' : 'DPEL'}, ` + output += `${mac ? 'MAC Address:' + mac + `, ` : ''} ` + + output += `${listLicense ? 'License: ' + listLicense : ''}` + + if (Array.isArray(issues) && issues.length > 0) { + output += `\n Issues:\n` + for (const issue of issues) { + output += ` - ${issue}\n` + } + } else if (typeof issues === 'string') { + output += `\n Issues: ${issues}` + } + + return output.trim() +} diff --git a/BACKEND/app/ultils/templates/index.ts b/BACKEND/app/ultils/templates/index.ts index 31fa249..ffc0920 100644 --- a/BACKEND/app/ultils/templates/index.ts +++ b/BACKEND/app/ultils/templates/index.ts @@ -53,8 +53,26 @@ export const textfsmResults = (logContent: string, cmd: string) => { // Parse commands and outputs const matches = [...logContent.matchAll(regexPattern)] + const mergedMatches = [] + + for (let match of matches) { + const m = match + const command = m.groups?.command?.trim() || '' + + if (command?.toLowerCase() === 'show version | include license') { + // Gộp vào phần tử trước + if (mergedMatches.length > 1) { + const lastMatch = mergedMatches[mergedMatches.length - 1] + if (lastMatch?.groups?.output) lastMatch.groups.output += '\n' + m?.groups?.output + } + continue + } + + mergedMatches.push(m) + } + // Process matches - results = matches + results = mergedMatches .map((match) => { const command = match.groups?.command.trim() || '' const output = match.groups?.output.trim() || '' diff --git a/BACKEND/providers/socket_io_provider.ts b/BACKEND/providers/socket_io_provider.ts index 0198bc6..7b16984 100644 --- a/BACKEND/providers/socket_io_provider.ts +++ b/BACKEND/providers/socket_io_provider.ts @@ -12,6 +12,7 @@ import APCController from '#services/apc_connection' import { appendLog, cleanData, sleep } from '../app/ultils/helper.js' import SwitchController from '#services/switch_connection' import redis from '@adonisjs/redis/services/main' +import axios from 'axios' interface HandleOptions { command?: string @@ -531,6 +532,26 @@ export class WebSocketIo { io.to(socket.id).emit('list_histories', result) }) + + socket.on('run_all_dpelp', async (data) => { + const lineIds = data.lineIds + console.log('[DPELP] Received run all dpelp') + + const results = await this.waitUntilAllReady(lineIds) + + const d = new Date(Date.now()) + const pad = (n: number) => String(n).padStart(2, '0') + + const dataFormat = + `${d.getFullYear()}/${pad(d.getMonth() + 1)}/${pad(d.getDate())}, ` + + `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}` + const linkWiki = + process.env.LINK_WIKI || 'https://logs.danielvu.com/api/wiki/page/insert?title=Dev_test' + await axios.post(linkWiki, { + data: `
${results.join('\n\n')}\n`,
+ titleAuto: 'AUTO - ' + dataFormat,
+ })
+ })
})
socketServer.listen(SOCKET_IO_PORT, () => {
@@ -1003,4 +1024,27 @@ export class WebSocketIo {
const items = await redis.zrange(key, 0, -1)
return items.map((i) => JSON.parse(i))
}
+
+ async waitUntilAllReady(lineIds: number[]) {
+ return new Promise