XNSim/XNSimHtml/routes/filesystem.js

163 lines
4.6 KiB
JavaScript
Raw Normal View History

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;