ATC_SIMPLE/BACKEND/app/ultils/helper.ts

190 lines
5.5 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.
* @returns {string} - The cleaned data.
*/
export const cleanData = (data: string) => {
return (
data
// 1⃣ Xóa chuỗi "--More--" (Cisco/Unix pager)
.replace(/--More--[\s\x08\x1b\[K]*/g, '')
// 2⃣ Xóa toàn bộ chuỗi ANSI escape sequences
// Ví dụ: ESC[2J, ESC[K, ESC[?25h, ESC[0m, ...
.replace(/\x1B\[[0-9;?]*[A-Za-z]/g, '')
// 3⃣ Xóa ký tự Backspace (BS) hoặc Delete (DEL)
.replace(/[\x08\x7F]/g, '')
// 4⃣ Xóa ký tự NUL và các control char khác (trừ \r, \n, \t)
.replace(/[^\x09\x0A\x0D\x20-\x7E]/g, '')
)
// 5⃣ Chuẩn hóa xuống dòng nếu cần
// .replace(/\r\n/g, '\n')
}
export function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms))
}
// 20250527-AUTO-Session.Station_1-13-192.168.171.9-2.log
// {DATE}-AUTO-Session.{Station name}-{Station ID}-{Station IP}-{Line number}.log
export function appendLog(
output: string,
stationId: number,
stationName: string,
stationIP: string,
lineNumber: number
) {
const date = new Date().toISOString().slice(0, 10).replace(/-/g, '') // YYYYMMDD
const logDir = path.join('storage', 'system_logs')
const logFile = path
.join(logDir, `${date}-AUTO-Session.${stationName}-${stationId}-${stationIP}-${lineNumber}.log`)
.replaceAll(' ', '_')
// Ensure folder exists
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true })
}
fs.appendFile(logFile, output, (err) => {
if (err) {
console.error('❌ Failed to write log:', err.message)
}
})
}
export const getPathLog = (stationId: number, lineNumber: number, port: number) => {
const date = new Date().toISOString().slice(0, 10).replace(/-/g, '') // YYYYMMDD
const logDir = path.join('storage', 'system_logs')
const logFile = path.join(logDir, `${date}-Station_${stationId}-Line_${lineNumber}_${port}.log`)
// Ensure folder exists
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true })
return null
} else return logFile
}
/**
* Utility function get scope log with timestamp.
* @param {string} text - content log.
* @param {number} time - Timestamp.
*/
export const getLogWithTimeScenario = (text: string, time: number) => {
try {
// Match all start and end blocks
const regex = /---(start|end)-scenarios---(\d+)---/g
let match
const blocks = []
while ((match = regex.exec(text)) !== null) {
blocks.push({
type: match[1],
timestamp: match[2],
index: match.index,
})
}
// Find the matching block for the end timestamp
let result = null
for (let i = 0; i < blocks.length; i++) {
const block = blocks[i]
if (block.type === 'end' && block.timestamp === time.toString()) {
// Find nearest preceding "start"
for (let j = i - 1; j >= 0; j--) {
if (blocks[j].type === 'start') {
const startIndex = blocks[j].index
const endIndex = block.index + text.slice(block.index).indexOf('\n') // or manually offset length of the line
result = text.slice(startIndex, endIndex).trim()
break
}
}
break
}
}
return result
} catch (err) {
console.error('Error get log:', err)
return ''
}
}
export function isValidJson(string: string) {
try {
JSON.parse(string)
return true // Chuỗi là định dạng JSON hợp lệ
} catch (e) {
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()
}