optimized

This commit is contained in:
proddy
2025-10-20 22:18:43 +02:00
parent 87bcd4598a
commit 812c6ac475

View File

@@ -1,33 +1,24 @@
// used to simulate // Mock server for development
// - file uploads // Simulates file uploads and EventSource (SSE) for log messages
// - EventSource (SSE) for log messages
import formidable from 'formidable'; import formidable from 'formidable';
function pad(number) { // Optimized padding function
let r = String(number); const pad = (number) => String(number).padStart(2, '0');
if (r.length === 1) {
r = '0' + r;
}
return r;
}
// e.g. 2024-03-29 07:02:37.856 // Cached date formatter to avoid prototype pollution
Date.prototype.toISOString = function () { const formatDate = (date) => {
return ( const year = date.getUTCFullYear();
this.getUTCFullYear() + const month = pad(date.getUTCMonth() + 1);
'-' + const day = pad(date.getUTCDate());
pad(this.getUTCMonth() + 1) + const hours = pad(date.getUTCHours());
'-' + const minutes = pad(date.getUTCMinutes());
pad(this.getUTCDate()) + const seconds = pad(date.getUTCSeconds());
' ' + const milliseconds = String((date.getUTCMilliseconds() / 1000).toFixed(3)).slice(
pad(this.getUTCHours()) + 2,
':' + 5
pad(this.getUTCMinutes()) +
':' +
pad(this.getUTCSeconds()) +
'.' +
String((this.getUTCMilliseconds() / 1000).toFixed(3)).slice(2, 5)
); );
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`;
}; };
export default () => { export default () => {
@@ -35,97 +26,129 @@ export default () => {
name: 'vite:mockserver', name: 'vite:mockserver',
configureServer: async (server) => { configureServer: async (server) => {
server.middlewares.use(async (req, res, next) => { server.middlewares.use(async (req, res, next) => {
// catch any file uploads // Handle file uploads
if (req.url.startsWith('/rest/uploadFile')) { if (req.url.startsWith('/rest/uploadFile')) {
// show progress const fileSize = parseInt(req.headers['content-length'] || '0', 10);
let progress = 0; let progress = 0;
const file_size = req.headers['content-length'];
console.log('File size: ' + file_size); // Track upload progress
req.on('data', async (chunk) => { req.on('data', (chunk) => {
progress += chunk.length; progress += chunk.length;
const percentage = (progress / file_size) * 100; if (fileSize > 0) {
console.log(`Progress: ${Math.round(percentage)}%`); const percentage = Math.round((progress / fileSize) * 100);
// await new Promise((resolve) => setTimeout(() => resolve(), 3000)); // slow it down console.log(`Upload progress: ${percentage}%`);
}
}); });
const form = formidable({});
let fields;
let files;
try { try {
[fields, files] = await form.parse(req); const form = formidable({
} catch (err) { maxFileSize: 50 * 1024 * 1024, // 50MB limit
console.error('Not json form content'); keepExtensions: true
res.writeHead(err.httpCode || 400, {
'Content-Type': 'text/plain'
}); });
res.end(String(err));
return;
}
// only process when we have a file const [fields, files] = await form.parse(req);
if (Object.keys(files).length > 0) {
const uploaded_file = files.file[0]; if (Object.keys(files).length === 0) {
const file_name = uploaded_file.originalFilename; res.statusCode = 400;
const file_extension = file_name.substring( res.end('No file uploaded');
file_name.lastIndexOf('.') + 1 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)`
); );
console.log('Filename: ' + file_name); // Validate file extension
console.log('Extension: ' + file_extension); const validExtensions = new Set(['bin', 'json', 'md5']);
console.log('File size: ' + file_size); if (!validExtensions.has(fileExtension)) {
res.statusCode = 406;
res.end('Invalid file extension');
return;
}
if (file_extension === 'bin' || file_extension === 'json') { // Handle different file types
console.log('File uploaded successfully!'); if (fileExtension === 'md5') {
} else if (file_extension === 'md5') { res.setHeader('Content-Type', 'application/json');
console.log('MD5 hash generated successfully!');
res.end( res.end(
JSON.stringify({ JSON.stringify({
md5: 'ef4304fc4d9025a58dcf25d71c882d2c' md5: 'ef4304fc4d9025a58dcf25d71c882d2c'
}) })
); );
} else { } else {
res.statusCode = 406; console.log('File uploaded successfully!');
console.log('Invalid file extension!'); 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);
} }
res.end();
} }
// SSE Eventsource // Handle Server-Sent Events (SSE) for log streaming
else if (req.url.startsWith('/es/log')) { else if (req.url.startsWith('/es/log')) {
// Set SSE headers
res.writeHead(200, { res.writeHead(200, {
Connection: 'keep-alive', Connection: 'keep-alive',
'Cache-Control': 'no-cache', 'Cache-Control': 'no-cache',
'Content-Type': 'text/event-stream' 'Content-Type': 'text/event-stream',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Cache-Control'
}); });
let count = 0; let messageCount = 0;
const interval = setInterval(() => { const logLevels = [3, 4, 5, 6, 7, 8]; // Different log levels
let message = 'message #' + count; const logNames = ['system', 'ems', 'wifi', 'mqtt', 'ntp', 'api'];
if (count % 6 === 1) {
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 += message +=
' that is a long message that will be wrapped, to test if it gets truncated'; ' - This is a longer message to test text wrapping and truncation behavior in the UI';
} }
const data = {
t: new Date().toISOString(), const logData = {
l: 3 + (count % 6), t: formatDate(new Date()),
i: count, l: level,
n: 'system', i: messageCount,
n: name,
m: message m: message
}; };
count++;
res.write(`data: ${JSON.stringify(data)}\n\n`);
}, 1000);
// if client closes connection res.write(`data: ${JSON.stringify(logData)}\n\n`);
res.on('close', () => { messageCount++;
console.log('Closing ES connection'); };
// 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); clearInterval(interval);
res.end(); if (!res.destroyed) {
}); res.end();
}
};
res.on('close', cleanup);
res.on('error', cleanup);
} else { } else {
next(); // move on to the next middleware function in chain next(); // Continue to next middleware
} }
}); });
} }