feat: Implement ETag-based conditional caching for API and HTML, add immutable caching for images, and introduce concurrency control with resizing for picture syncing.

This commit is contained in:
sebseb7
2025-11-23 10:51:16 +01:00
parent 3f451dde06
commit 49246169db
4 changed files with 127 additions and 19 deletions

View File

@@ -9,10 +9,48 @@ class PictureSyncer {
return PictureSyncer.instance;
}
this.cacheBaseDir = process.env.CACHE_LOCATION || '.';
// Track syncing state per group
this.isSyncing = new Map(); // groupName -> boolean
this.queuedSyncs = new Map(); // groupName -> { imageIds, groupName }
PictureSyncer.instance = this;
}
async syncImages(imageIds, groupName) {
// Check if already syncing this group
if (this.isSyncing.get(groupName)) {
if (this.queuedSyncs.has(groupName)) {
console.log(`🚫 Image sync for '${groupName}' already in progress and queued. Ignoring.`);
return;
}
console.log(`⏳ Image sync for '${groupName}' already in progress. Queuing.`);
this.queuedSyncs.set(groupName, { imageIds, groupName });
return;
}
await this._doSync(imageIds, groupName);
}
async _doSync(imageIds, groupName) {
this.isSyncing.set(groupName, true);
try {
await this._performSync(imageIds, groupName);
} finally {
this.isSyncing.set(groupName, false);
// Process queued sync for this group if any
if (this.queuedSyncs.has(groupName)) {
console.log(`🔄 Processing queued image sync for '${groupName}'...`);
const queued = this.queuedSyncs.get(groupName);
this.queuedSyncs.delete(groupName);
setImmediate(() => this.syncImages(queued.imageIds, queued.groupName));
}
}
}
async _performSync(imageIds, groupName) {
const groupDir = path.join(this.cacheBaseDir, 'img', groupName);
// Ensure directory exists
@@ -74,8 +112,12 @@ class PictureSyncer {
for (const record of result.recordset) {
if (record.bBild) {
const filePath = path.join(dir, `${record.kBild}.avif`);
// Convert to AVIF using sharp
// Resize to 130x130 and convert to AVIF using sharp
await sharp(record.bBild)
.resize(130, 130, {
fit: 'cover',
position: 'center'
})
.avif({ quality: 80 })
.toFile(filePath);
}