3v324v23's picture
feat: Add Core API demonstration module
cee4ba4
const express = require('express');
const path = require('path');
const fs = require('fs');
const { exec } = require('child_process');
const LargeFileHandler = require('./src/largeFile');
const xmlJsonHandler = require('./src/xmlJson');
const performanceMonitor = require('./src/performance');
const CoreApiDemo = require('./src/coreApiDemo');
const app = express();
const PORT = 7860;
const DATA_DIR = path.join(__dirname, 'data');
// Ensure data directory exists
if (!fs.existsSync(DATA_DIR)) {
fs.mkdirSync(DATA_DIR);
}
const LARGE_FILE_PATH = path.join(DATA_DIR, 'large_data.csv');
const XML_FILE_PATH = path.join(DATA_DIR, 'data.xml');
const LARGE_JSON_PATH = path.join(DATA_DIR, 'large_data.json');
// Global lock to prevent concurrent demos
global.isDemoRunning = false;
// Feature 1: Large File Stream
async function runLargeFileDemo() {
console.log('=== 1. 大文件流式处理演示 ===');
try {
const largeFileHandler = new LargeFileHandler(LARGE_FILE_PATH);
const lineCount = 100000;
console.log(`正在生成测试数据 (${lineCount} 行)...`);
await largeFileHandler.generateTestFile(lineCount);
console.log('开始流式处理...');
await largeFileHandler.processFileStream();
logMemoryUsage();
} catch (err) {
console.error('发生错误:', err);
}
}
// Feature 2: XML Processing
async function runXmlDemo() {
console.log('=== 2. XML 处理演示 ===');
try {
const xmlContent = xmlJsonHandler.generateXml(1000);
fs.writeFileSync(XML_FILE_PATH, xmlContent);
console.log(`XML 文件已保存: ${XML_FILE_PATH}`);
const parsedXml = xmlJsonHandler.parseXml(xmlContent);
console.log('XML 解析完成');
logMemoryUsage();
} catch (err) {
console.error('发生错误:', err);
}
}
// Feature 3: JSON Stream
async function runJsonDemo() {
console.log('=== 3. JSON 大文件流式处理演示 ===');
try {
console.log('正在生成 JSON 数据...');
await xmlJsonHandler.generateLargeJson(LARGE_JSON_PATH, 10000);
console.log('开始流式解析 JSON...');
await xmlJsonHandler.processLargeJsonStream(LARGE_JSON_PATH);
logMemoryUsage();
} catch (err) {
console.error('发生错误:', err);
}
}
// Feature 4: Core APIs Demo
async function runCoreApiDemo() {
const coreDemo = new CoreApiDemo(DATA_DIR);
await coreDemo.run();
}
function logMemoryUsage() {
const used = process.memoryUsage();
console.log('Memory Usage:');
for (let key in used) {
console.log(`${key}: ${Math.round(used[key] / 1024 / 1024 * 100) / 100} MB`);
}
}
// Serve the main page
app.get('/', (req, res) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>Node.js Performance Demo</title>
<meta charset="utf-8">
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; background: #f0f2f5; padding: 40px; color: #333; }
.container { max-width: 900px; margin: 0 auto; background: #fff; padding: 30px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
h1 { color: #2c3e50; margin-bottom: 20px; border-bottom: 2px solid #eee; padding-bottom: 10px; }
.controls { margin-bottom: 20px; display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; }
button { padding: 15px; font-size: 16px; cursor: pointer; background: #007bff; color: white; border: none; border-radius: 5px; transition: background 0.3s; font-weight: bold; }
button:hover { background: #0056b3; }
button:disabled { background: #ccc; cursor: not-allowed; }
.btn-core { background: #6610f2; }
.btn-core:hover { background: #520dc2; }
.btn-system { background: #28a745; }
.btn-system:hover { background: #218838; }
.btn-clear { background: #6c757d; }
.btn-clear:hover { background: #5a6268; }
#output { background: #1e1e1e; color: #d4d4d4; padding: 20px; border-radius: 5px; font-family: "Menlo", "Monaco", "Courier New", monospace; height: 500px; overflow-y: auto; white-space: pre-wrap; font-size: 14px; line-height: 1.5; border: 1px solid #333; }
.status { margin-top: 10px; font-style: italic; color: #666; }
</style>
</head>
<body>
<div class="container">
<h1>Node.js Performance Demo</h1>
<div class="controls">
<button onclick="runDemo('large-file')">📄 1. 大文件流式处理</button>
<button onclick="runDemo('xml')">🏷️ 2. XML 解析处理</button>
<button onclick="runDemo('json')">📦 3. JSON 流式解析</button>
<button onclick="getSystemInfo()" class="btn-system">🖥️ 4. 系统信息 (child_process)</button>
<button onclick="runDemo('core-api')" class="btn-core">🛠️ 5. 核心 API 综合演示</button>
<button onclick="clearOutput()" class="btn-clear">🗑 清空输出</button>
</div>
<div id="output">点击上方按钮开始测试...</div>
<div id="status" class="status"></div>
</div>
<script>
const outputDiv = document.getElementById('output');
const statusDiv = document.getElementById('status');
let isRunning = false;
function log(msg, isError = false) {
if (outputDiv.innerHTML === '点击上方按钮开始测试...') {
outputDiv.innerHTML = '';
}
const span = document.createElement('div');
span.textContent = msg;
if (isError) span.style.color = '#ff6b6b';
outputDiv.appendChild(span);
outputDiv.scrollTop = outputDiv.scrollHeight;
}
function clearOutput() {
outputDiv.innerHTML = '点击上方按钮开始测试...';
statusDiv.textContent = '';
}
function runDemo(type) {
if (isRunning) return;
isRunning = true;
updateButtons(true);
statusDiv.textContent = '正在运行演示...';
const eventSource = new EventSource('/api/run-demo?type=' + type);
eventSource.onmessage = function(event) {
try {
const data = JSON.parse(event.data);
if (data.type === 'log') {
log(data.message);
} else if (data.type === 'error') {
log(data.message, true);
} else if (data.type === 'end') {
eventSource.close();
isRunning = false;
updateButtons(false);
statusDiv.textContent = '演示完成';
}
} catch (e) {
console.error('Error parsing SSE data', e);
}
};
eventSource.onerror = function(err) {
console.error('EventSource failed:', err);
eventSource.close();
isRunning = false;
updateButtons(false);
statusDiv.textContent = '连接中断';
log('Error: Connection to server lost.', true);
};
}
function updateButtons(disabled) {
const btns = document.querySelectorAll('button:not(.btn-clear)');
btns.forEach(btn => btn.disabled = disabled);
}
async function getSystemInfo() {
if (isRunning) return;
statusDiv.textContent = '正在获取系统信息...';
try {
const res = await fetch('/api/system-info');
const text = await res.text();
log('\\n=== 4. 系统信息 ===');
log(text);
statusDiv.textContent = '获取成功';
} catch (e) {
log('Error fetching system info: ' + e.message, true);
}
}
</script>
</body>
</html>
`);
});
// SSE Endpoint for running the demo
app.get('/api/run-demo', async (req, res) => {
const type = req.query.type;
if (global.isDemoRunning) {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
res.write(`data: ${JSON.stringify({ type: 'error', message: 'Demo is already running. Please wait.' })}\n\n`);
res.write(`data: ${JSON.stringify({ type: 'end' })}\n\n`);
return res.end();
}
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
global.isDemoRunning = true;
// Helper to send SSE messages
const send = (type, message) => {
res.write(`data: ${JSON.stringify({ type, message })}\n\n`);
};
// Override console methods
const originalConsoleLog = console.log;
const originalConsoleError = console.error;
console.log = (...args) => {
const msg = args.map(arg => (typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg))).join(' ');
send('log', msg);
originalConsoleLog.apply(console, args);
};
console.error = (...args) => {
const msg = args.map(arg => (typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg))).join(' ');
send('error', msg);
originalConsoleError.apply(console, args);
};
try {
switch (type) {
case 'large-file':
await runLargeFileDemo();
break;
case 'xml':
await runXmlDemo();
break;
case 'json':
await runJsonDemo();
break;
case 'core-api':
await runCoreApiDemo();
break;
default:
console.log('未知的任务类型');
}
} catch (e) {
console.error('Unhandled error:', e);
} finally {
// Restore console
console.log = originalConsoleLog;
console.error = originalConsoleError;
global.isDemoRunning = false;
send('end', 'Done');
res.end();
}
});
// API for system info
app.get('/api/system-info', (req, res) => {
exec('uname -a && echo "\\nDisk Usage:" && df -h | head -n 5', (error, stdout, stderr) => {
if (error) {
res.status(500).send(`Error: ${error.message}`);
return;
}
res.send(stdout);
});
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});