camera_draw / server.js
VISHAL18for4's picture
Update server.js
28a1b9f verified
Raw
History Blame Contribute Delete
7.63 kB
const express = require('express');
const fs = require('fs');
const path = require('path');
const cors = require('cors');
const app = express();
const PORT = process.env.PORT || 7860;
// ============================================================
// 1. Middleware
// ============================================================
app.use(cors());
app.use(express.json({ limit: '10mb' }));
// Force correct MIME type for MediaPipe .task files
app.use((req, res, next) => {
if (req.url.endsWith('.task')) {
res.setHeader('Content-Type', 'application/octet-stream');
res.setHeader('Content-Disposition', 'attachment; filename="hand_landmarker.task"');
}
next();
});
// ============================================================
// 2. Snapshots Directory Setup
// ============================================================
const SNAPSHOT_DIR = path.join(__dirname, 'snapshots');
if (!fs.existsSync(SNAPSHOT_DIR)) {
fs.mkdirSync(SNAPSHOT_DIR, { recursive: true });
console.log(`[SERVER] Created snapshots directory at ${SNAPSHOT_DIR}`);
}
// ============================================================
// 3. Serve Static Frontend Files
// ============================================================
app.use(express.static(path.join(__dirname, 'public')));
// ============================================================
// 4. Explicit route for admin.html (case-insensitive fallback)
// ============================================================
app.get('/admin.html', (req, res) => {
const adminPath = path.join(__dirname, 'public', 'admin.html');
const altPath = path.join(__dirname, 'public', 'Admin.html');
if (fs.existsSync(adminPath)) {
res.sendFile(adminPath);
} else if (fs.existsSync(altPath)) {
console.log('[SERVER] Serving Admin.html (uppercase) as admin.html');
res.sendFile(altPath);
} else {
res.status(404).send('admin.html not found. Please create the file in the public folder.');
}
});
// ============================================================
// 5. Snapshot Binary Endpoint
// ============================================================
app.get('/snapshots/:filename', (req, res) => {
const filename = req.params.filename;
if (filename.includes('..') || filename.includes('/') || filename.includes('\\')) {
console.warn(`[SERVER] Blocked malicious filename: ${filename}`);
return res.status(400).send('Invalid filename');
}
const filePath = path.join(SNAPSHOT_DIR, filename);
if (fs.existsSync(filePath)) {
try {
const data = fs.readFileSync(filePath);
res.setHeader('Content-Type', 'image/png');
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
res.send(data);
console.log(`[SERVER] Served snapshot: ${filename} (${data.length} bytes)`);
} catch (err) {
console.error(`[SERVER] Error reading snapshot ${filename}:`, err);
res.status(500).send('Error reading file');
}
} else {
console.log(`[SERVER] Snapshot not found: ${filename}`);
res.status(404).send('Snapshot not found');
}
});
// ============================================================
// 6. POST /api/log – Receive frontend logs
// ============================================================
app.post('/api/log', (req, res) => {
try {
const { message, level = 'info', timestamp } = req.body;
const logMsg = `[Frontend ${level}] ${timestamp || new Date().toISOString()} ${message || ''}`;
console.log(logMsg);
res.status(200).json({ success: true });
} catch (err) {
console.error('[SERVER] Log error:', err);
res.status(500).json({ success: false, error: err.message });
}
});
// ============================================================
// 7. POST /api/snapshot – Save New Snapshot
// ============================================================
app.post('/api/snapshot', (req, res) => {
try {
const { image } = req.body;
if (!image) {
return res.status(400).json({ success: false, error: 'No image data provided' });
}
if (typeof image !== 'string' || image.length < 100) {
return res.status(400).json({ success: false, error: 'Invalid image data format' });
}
const buffer = Buffer.from(image, 'base64');
const now = new Date();
const dateStr =
now.getFullYear() + '-' +
String(now.getMonth() + 1).padStart(2, '0') + '-' +
String(now.getDate()).padStart(2, '0') + '_' +
String(now.getHours()).padStart(2, '0') + '-' +
String(now.getMinutes()).padStart(2, '0') + '-' +
String(now.getSeconds()).padStart(2, '0') + '_' +
String(now.getMilliseconds()).padStart(3, '0');
const filename = `snapshot_${dateStr}.png`;
const filePath = path.join(SNAPSHOT_DIR, filename);
fs.writeFileSync(filePath, buffer);
console.log(`[SERVER] Snapshot saved: ${filename} (${buffer.length} bytes) at ${filePath}`);
if (fs.existsSync(filePath)) {
const stats = fs.statSync(filePath);
console.log(`[SERVER] Verification: file exists, size ${stats.size} bytes`);
} else {
console.error(`[SERVER] Verification FAILED: file not found after write`);
return res.status(500).json({ success: false, error: 'Write verification failed' });
}
res.json({
success: true,
path: `/snapshots/${filename}`,
filename: filename
});
} catch (err) {
console.error('[SERVER] Save error:', err);
res.status(500).json({ success: false, error: 'Internal server error: ' + err.message });
}
});
// ============================================================
// 8. GET /api/snapshots/list – List All Snapshots
// ============================================================
app.get('/api/snapshots/list', (req, res) => {
try {
const files = fs.readdirSync(SNAPSHOT_DIR)
.filter(f => f.endsWith('.png'))
.sort();
console.log(`[SERVER] Listed ${files.length} snapshots`);
res.json({ success: true, files });
} catch (err) {
console.error('[SERVER] List error:', err);
res.status(500).json({ success: false, error: err.message });
}
});
// ============================================================
// 9. DELETE /api/snapshots/:filename – Delete a Snapshot
// ============================================================
app.delete('/api/snapshots/:filename', (req, res) => {
const filename = req.params.filename;
if (filename.includes('..') || filename.includes('/') || filename.includes('\\')) {
return res.status(400).json({ success: false, error: 'Invalid filename' });
}
const filePath = path.join(SNAPSHOT_DIR, filename);
if (fs.existsSync(filePath)) {
try {
fs.unlinkSync(filePath);
console.log(`[SERVER] Deleted snapshot: ${filename}`);
res.json({ success: true, message: 'Deleted' });
} catch (err) {
res.status(500).json({ success: false, error: err.message });
}
} else {
res.status(404).json({ success: false, error: 'File not found' });
}
});
// ============================================================
// 10. Health Check
// ============================================================
app.get('/health', (req, res) => {
res.status(200).send('OK');
});
// ============================================================
// 11. Start Server
// ============================================================
app.listen(PORT, () => {
console.log(`[SERVER] Running on port ${PORT}`);
console.log(`[SERVER] Snapshots directory: ${SNAPSHOT_DIR}`);
console.log(`[SERVER] Serving static files from: ${path.join(__dirname, 'public')}`);
});