Files
EMS-ESP32/mock-api/mockServer.js
2025-10-20 22:18:43 +02:00

157 lines
5.0 KiB
JavaScript

// Mock server for development
// Simulates file uploads and EventSource (SSE) for log messages
import formidable from 'formidable';
// Optimized padding function
const pad = (number) => String(number).padStart(2, '0');
// Cached date formatter to avoid prototype pollution
const formatDate = (date) => {
const year = date.getUTCFullYear();
const month = pad(date.getUTCMonth() + 1);
const day = pad(date.getUTCDate());
const hours = pad(date.getUTCHours());
const minutes = pad(date.getUTCMinutes());
const seconds = pad(date.getUTCSeconds());
const milliseconds = String((date.getUTCMilliseconds() / 1000).toFixed(3)).slice(
2,
5
);
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`;
};
export default () => {
return {
name: 'vite:mockserver',
configureServer: async (server) => {
server.middlewares.use(async (req, res, next) => {
// Handle file uploads
if (req.url.startsWith('/rest/uploadFile')) {
const fileSize = parseInt(req.headers['content-length'] || '0', 10);
let progress = 0;
// Track upload progress
req.on('data', (chunk) => {
progress += chunk.length;
if (fileSize > 0) {
const percentage = Math.round((progress / fileSize) * 100);
console.log(`Upload progress: ${percentage}%`);
}
});
try {
const form = formidable({
maxFileSize: 50 * 1024 * 1024, // 50MB limit
keepExtensions: true
});
const [fields, files] = await form.parse(req);
if (Object.keys(files).length === 0) {
res.statusCode = 400;
res.end('No file uploaded');
return;
}
const uploadedFile = files.file[0];
const fileName = uploadedFile.originalFilename;
const fileExtension = fileName
.substring(fileName.lastIndexOf('.') + 1)
.toLowerCase();
console.log(
`File uploaded: ${fileName} (${fileExtension}, ${fileSize} bytes)`
);
// Validate file extension
const validExtensions = new Set(['bin', 'json', 'md5']);
if (!validExtensions.has(fileExtension)) {
res.statusCode = 406;
res.end('Invalid file extension');
return;
}
// Handle different file types
if (fileExtension === 'md5') {
res.setHeader('Content-Type', 'application/json');
res.end(
JSON.stringify({
md5: 'ef4304fc4d9025a58dcf25d71c882d2c'
})
);
} else {
console.log('File uploaded successfully!');
res.end();
}
} catch (err) {
console.error('Upload error:', err.message);
res.statusCode = err.httpCode || 400;
res.setHeader('Content-Type', 'text/plain');
res.end(err.message);
}
}
// Handle Server-Sent Events (SSE) for log streaming
else if (req.url.startsWith('/es/log')) {
// Set SSE headers
res.writeHead(200, {
Connection: 'keep-alive',
'Cache-Control': 'no-cache',
'Content-Type': 'text/event-stream',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Cache-Control'
});
let messageCount = 0;
const logLevels = [3, 4, 5, 6, 7, 8]; // Different log levels
const logNames = ['system', 'ems', 'wifi', 'mqtt', 'ntp', 'api'];
const sendLogMessage = () => {
const level = logLevels[messageCount % logLevels.length];
const name = logNames[messageCount % logNames.length];
let message = `Log message #${messageCount}`;
// Add long message every 6th message
if (messageCount % 6 === 1) {
message +=
' - This is a longer message to test text wrapping and truncation behavior in the UI';
}
const logData = {
t: formatDate(new Date()),
l: level,
i: messageCount,
n: name,
m: message
};
res.write(`data: ${JSON.stringify(logData)}\n\n`);
messageCount++;
};
// Send initial message
sendLogMessage();
// Set up interval for periodic messages
const interval = setInterval(sendLogMessage, 1000);
// Clean up on connection close
const cleanup = () => {
console.log('SSE connection closed');
clearInterval(interval);
if (!res.destroyed) {
res.end();
}
};
res.on('close', cleanup);
res.on('error', cleanup);
} else {
next(); // Continue to next middleware
}
});
}
};
};