2025-04-28 12:25:20 +08:00
|
|
|
|
const express = require('express');
|
|
|
|
|
const router = express.Router();
|
|
|
|
|
const fs = require('fs').promises;
|
|
|
|
|
const { getActualLogPath } = require('../utils/file-utils');
|
|
|
|
|
|
|
|
|
|
// 读取目录内容
|
|
|
|
|
router.get('/readdir', async (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const dirPath = req.query.path;
|
|
|
|
|
|
|
|
|
|
if (!dirPath) {
|
|
|
|
|
return res.status(400).json({ error: '缺少路径参数' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取实际的文件系统路径
|
2025-05-28 16:20:01 +08:00
|
|
|
|
const actualPath = await getActualLogPath(dirPath);
|
2025-04-28 12:25:20 +08:00
|
|
|
|
|
|
|
|
|
// 安全检查
|
|
|
|
|
if (!actualPath) {
|
|
|
|
|
return res.status(403).json({ error: '无权访问该目录' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查目录是否存在
|
|
|
|
|
try {
|
|
|
|
|
const stats = await fs.stat(actualPath);
|
|
|
|
|
if (!stats.isDirectory()) {
|
|
|
|
|
return res.status(400).json({ error: '指定的路径不是目录' });
|
|
|
|
|
}
|
|
|
|
|
} catch (statError) {
|
|
|
|
|
// 如果目录不存在但是请求的是/log,尝试创建它
|
|
|
|
|
if (statError.code === 'ENOENT' && dirPath === '/log') {
|
|
|
|
|
try {
|
|
|
|
|
// 确保XNCore下有log目录
|
|
|
|
|
await fs.mkdir(actualPath, { recursive: true });
|
|
|
|
|
} catch (mkdirError) {
|
|
|
|
|
console.error('创建日志目录失败:', mkdirError);
|
|
|
|
|
return res.status(500).json({ error: '创建日志目录失败' });
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
throw statError;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 读取目录内容
|
|
|
|
|
const files = await fs.readdir(actualPath);
|
|
|
|
|
|
|
|
|
|
// 返回文件列表
|
|
|
|
|
res.json({ files });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('读取目录失败:', error);
|
|
|
|
|
|
|
|
|
|
// 处理特定错误
|
|
|
|
|
if (error.code === 'ENOENT') {
|
|
|
|
|
return res.status(404).json({ error: '目录不存在' });
|
|
|
|
|
}
|
|
|
|
|
if (error.code === 'EACCES') {
|
|
|
|
|
return res.status(403).json({ error: '没有权限访问目录' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.status(500).json({ error: '读取目录失败', message: error.message });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 获取文件状态信息
|
|
|
|
|
router.get('/stat', async (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const filePath = req.query.path;
|
|
|
|
|
|
|
|
|
|
if (!filePath) {
|
|
|
|
|
return res.status(400).json({ error: '缺少路径参数' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取实际的文件系统路径
|
2025-05-28 16:20:01 +08:00
|
|
|
|
const actualPath = await getActualLogPath(filePath);
|
2025-04-28 12:25:20 +08:00
|
|
|
|
|
|
|
|
|
// 安全检查
|
|
|
|
|
if (!actualPath) {
|
|
|
|
|
return res.status(403).json({ error: '无权访问该文件' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取文件状态
|
|
|
|
|
const stats = await fs.stat(actualPath);
|
|
|
|
|
|
|
|
|
|
// 返回文件信息
|
|
|
|
|
res.json({
|
|
|
|
|
size: stats.size,
|
|
|
|
|
isFile: stats.isFile(),
|
|
|
|
|
isDirectory: stats.isDirectory(),
|
|
|
|
|
created: stats.birthtime,
|
|
|
|
|
modified: stats.mtime,
|
|
|
|
|
accessed: stats.atime,
|
|
|
|
|
mtime: stats.mtime.toISOString()
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取文件状态失败:', error);
|
|
|
|
|
|
|
|
|
|
// 处理特定错误
|
|
|
|
|
if (error.code === 'ENOENT') {
|
|
|
|
|
return res.status(404).json({ error: '文件不存在' });
|
|
|
|
|
}
|
|
|
|
|
if (error.code === 'EACCES') {
|
|
|
|
|
return res.status(403).json({ error: '没有权限访问文件' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.status(500).json({ error: '获取文件状态失败', message: error.message });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 读取文件内容
|
|
|
|
|
router.get('/readFile', async (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const filePath = req.query.path;
|
|
|
|
|
|
|
|
|
|
if (!filePath) {
|
|
|
|
|
return res.status(400).json({ error: '缺少路径参数' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取实际的文件系统路径
|
2025-05-28 16:20:01 +08:00
|
|
|
|
const actualPath = await getActualLogPath(filePath);
|
2025-04-28 12:25:20 +08:00
|
|
|
|
|
|
|
|
|
// 安全检查
|
|
|
|
|
if (!actualPath) {
|
|
|
|
|
return res.status(403).json({ error: '无权访问该文件' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 只允许访问.log文件
|
|
|
|
|
if (!actualPath.endsWith('.log')) {
|
|
|
|
|
return res.status(403).json({ error: '只能访问日志文件' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取文件状态
|
|
|
|
|
const stats = await fs.stat(actualPath);
|
|
|
|
|
|
|
|
|
|
// 检查文件大小,限制读取过大的文件
|
|
|
|
|
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
|
|
|
|
|
if (stats.size > MAX_FILE_SIZE) {
|
|
|
|
|
return res.status(413).json({ error: '文件过大,无法读取' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 读取文件内容
|
|
|
|
|
const content = await fs.readFile(actualPath, 'utf-8');
|
|
|
|
|
|
|
|
|
|
// 设置响应头
|
|
|
|
|
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
|
|
|
|
|
|
|
|
|
// 返回文件内容
|
|
|
|
|
res.send(content);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('读取文件内容失败:', error);
|
|
|
|
|
|
|
|
|
|
// 处理特定错误
|
|
|
|
|
if (error.code === 'ENOENT') {
|
|
|
|
|
return res.status(404).json({ error: '文件不存在' });
|
|
|
|
|
}
|
|
|
|
|
if (error.code === 'EACCES') {
|
|
|
|
|
return res.status(403).json({ error: '没有权限访问文件' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.status(500).json({ error: '读取文件内容失败', message: error.message });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
module.exports = router;
|