161 lines
4.6 KiB
TypeScript
161 lines
4.6 KiB
TypeScript
import Log from '#models/log'
|
|
import type { HttpContext } from '@adonisjs/core/http'
|
|
import fs from 'node:fs'
|
|
import path, { dirname } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
const FILENAME = fileURLToPath(import.meta.url)
|
|
const DIRNAME = dirname(FILENAME)
|
|
|
|
export default class LogsController {
|
|
async list({ request, response, auth }: HttpContext) {
|
|
const search = request.input('search', '')
|
|
const perPage = request.input('per_page', 10)
|
|
const page = request.input('page', 1)
|
|
|
|
// Fetch logs that are associated with the user's stations with pagination
|
|
const query = Log.query()
|
|
.select('logs.*')
|
|
.preload('line', (lineQuery) => {
|
|
lineQuery.preload('station')
|
|
})
|
|
|
|
const logs = await query.paginate(page, perPage)
|
|
|
|
return response.ok({
|
|
status: true,
|
|
data: logs,
|
|
})
|
|
}
|
|
|
|
async viewLog({ request, response }: HttpContext) {
|
|
const logFilePath = request.input('path')
|
|
|
|
try {
|
|
const normalizedPath = path.normalize(logFilePath)
|
|
const fullPath = path.join(DIRNAME, '..', '..', normalizedPath)
|
|
|
|
if (!fs.existsSync(fullPath)) {
|
|
return response.notFound({
|
|
status: false,
|
|
message: 'Log file not found',
|
|
})
|
|
}
|
|
|
|
// Đọc file với encoding buffer trước
|
|
const buffer = fs.readFileSync(fullPath)
|
|
|
|
// Thử các encoding khác nhau
|
|
let logContent
|
|
try {
|
|
// Thử với utf-8 trước
|
|
logContent = buffer.toString('utf-8')
|
|
if (logContent.includes('\u0000')) {
|
|
// Nếu có null bytes, thử với encoding khác
|
|
logContent = buffer.toString('ascii')
|
|
}
|
|
} catch {
|
|
// Fallback to ascii if utf-8 fails
|
|
logContent = buffer.toString('ascii')
|
|
}
|
|
|
|
// Loại bỏ các null bytes
|
|
logContent = logContent.replace(/\u0000/g, '')
|
|
|
|
return response.ok({
|
|
status: true,
|
|
data: logContent,
|
|
})
|
|
} catch (error) {
|
|
return response.internalServerError({
|
|
status: false,
|
|
message: 'Failed to read log file',
|
|
error: error.message,
|
|
})
|
|
}
|
|
}
|
|
|
|
async downloadLog({ request, response }: HttpContext) {
|
|
try {
|
|
const logPath = request.input('path')
|
|
const fullPath = path.join(DIRNAME, '..', '..', logPath)
|
|
|
|
if (!fs.existsSync(fullPath)) {
|
|
return response.notFound({
|
|
status: false,
|
|
message: 'Log file not found',
|
|
})
|
|
}
|
|
|
|
// Lấy tên file từ đường dẫn
|
|
const fileName = path.basename(logPath)
|
|
|
|
// Set headers cho download
|
|
response.header('Content-Type', 'application/octet-stream')
|
|
response.header('Content-Disposition', `attachment; filename="${fileName}"`)
|
|
|
|
// Stream file về client
|
|
return response.stream(fs.createReadStream(fullPath))
|
|
} catch (error) {
|
|
return response.internalServerError({
|
|
status: false,
|
|
message: 'Failed to download log file',
|
|
error: error.message,
|
|
})
|
|
}
|
|
}
|
|
|
|
async listSystemLogFiles({ request, response }: HttpContext) {
|
|
try {
|
|
const filename = request.input('filename', '')
|
|
const fromDate = request.input('from_date', '')
|
|
const toDate = request.input('to_date', '')
|
|
|
|
const systemLogsDir = path.join(DIRNAME, '..', '..', 'storage', 'system_logs')
|
|
|
|
// Nếu thư mục không tồn tại, trả về danh sách rỗng
|
|
if (!fs.existsSync(systemLogsDir)) {
|
|
return response.ok({
|
|
status: true,
|
|
data: [],
|
|
})
|
|
}
|
|
|
|
let files = fs.readdirSync(systemLogsDir)
|
|
|
|
// Lọc theo tên file nếu có
|
|
if (filename) {
|
|
files = files.filter((f) => f.includes(filename))
|
|
}
|
|
|
|
// Lọc theo khoảng thời gian nếu có
|
|
if (fromDate || toDate) {
|
|
const fromTime = fromDate ? new Date(fromDate).getTime() : 0
|
|
// Cộng thêm 24h để bao gồm cả ngày cuối cùng (end of day 23:59:59)
|
|
const toTime = toDate ? new Date(toDate).getTime() + 24 * 60 * 60 * 1000 : Date.now()
|
|
|
|
files = files.filter((f) => {
|
|
const filePath = path.join(systemLogsDir, f)
|
|
const stat = fs.statSync(filePath)
|
|
const fileTime = stat.mtime.getTime()
|
|
return fileTime >= fromTime && fileTime < toTime
|
|
})
|
|
}
|
|
|
|
// Lấy 100 tên file đầu tiên từ danh sách lọc được
|
|
const result = files.slice(0, 100)
|
|
|
|
return response.ok({
|
|
status: true,
|
|
data: result,
|
|
})
|
|
} catch (error) {
|
|
return response.internalServerError({
|
|
status: false,
|
|
message: 'Failed to list system log files',
|
|
error: error.message,
|
|
})
|
|
}
|
|
}
|
|
}
|