/** * Image Optimization Middleware * High-performance image serving with streaming and caching */ const path = require("path"); const fs = require("fs"); const fsPromises = require("fs").promises; const logger = require("../config/logger"); // Cache for image metadata (not content) const metadataCache = new Map(); const METADATA_CACHE_TTL = 600000; // 10 minutes const METADATA_CACHE_MAX = 1000; // Image mime types const MIME_TYPES = { ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".png": "image/png", ".gif": "image/gif", ".webp": "image/webp", ".svg": "image/svg+xml", ".ico": "image/x-icon", ".avif": "image/avif", }; /** * Get or cache image metadata */ async function getImageMetadata(filePath) { const cached = metadataCache.get(filePath); if (cached && Date.now() - cached.timestamp < METADATA_CACHE_TTL) { return cached.data; } try { const stats = await fsPromises.stat(filePath); const metadata = { exists: true, size: stats.size, mtime: stats.mtime.getTime(), etag: `"${stats.size}-${stats.mtime.getTime()}"`, lastModified: stats.mtime.toUTCString(), }; // LRU eviction if (metadataCache.size >= METADATA_CACHE_MAX) { const firstKey = metadataCache.keys().next().value; metadataCache.delete(firstKey); } metadataCache.set(filePath, { data: metadata, timestamp: Date.now() }); return metadata; } catch { const notFound = { exists: false }; metadataCache.set(filePath, { data: notFound, timestamp: Date.now() }); return notFound; } } /** * Serve optimized images with streaming and aggressive caching */ const imageOptimization = (uploadsDir) => { return async (req, res, next) => { // Only handle image requests const ext = path.extname(req.path).toLowerCase(); if (!MIME_TYPES[ext]) { return next(); } const imagePath = path.join(uploadsDir, req.path.replace("/uploads/", "")); // Get cached metadata const metadata = await getImageMetadata(imagePath); if (!metadata.exists) { return next(); } try { // Check if client has cached version (304 Not Modified) const ifNoneMatch = req.get("if-none-match"); const ifModifiedSince = req.get("if-modified-since"); if ( ifNoneMatch === metadata.etag || ifModifiedSince === metadata.lastModified ) { return res.status(304).end(); } // Set aggressive caching headers res.set({ "Content-Type": MIME_TYPES[ext], "Content-Length": metadata.size, "Cache-Control": "public, max-age=31536000, immutable", // 1 year ETag: metadata.etag, "Last-Modified": metadata.lastModified, Vary: "Accept-Encoding", "X-Content-Type-Options": "nosniff", }); // Use streaming for efficient memory usage const readStream = fs.createReadStream(imagePath, { highWaterMark: 64 * 1024, // 64KB chunks }); readStream.on("error", (error) => { logger.error("Image stream error:", { path: imagePath, error: error.message, }); if (!res.headersSent) { res.status(500).end(); } }); readStream.pipe(res); } catch (error) { logger.error("Image serve error:", { path: imagePath, error: error.message, }); next(); } }; }; module.exports = { imageOptimization };