@paroicms/server-image-cache-engine
Version:
The image variant engine that we use at Paroi.
121 lines • 4.69 kB
JavaScript
import { createVariantEngineContext } from "./internal/engine-context.js";
import { clearAll, deleteOrphanVariants, deleteVariants, deleteVariantsByDependencies, fetchImageVariantWithBinary, fetchImageVariantWithBinaryByOwner, fetchUsedRawSizesByMedia, } from "./internal/queries.js";
import { processAllPending } from "./internal/task-processor.js";
import { makeOwnerKey, makeTaskKey } from "./internal/utils.js";
import { createOwnerTransaction } from "./owner-transaction/owner-transaction.js";
let pendingSeq = 0;
export async function createImageCacheEngine(options) {
const { context, isCleared } = await createVariantEngineContext(options);
let processing = false;
const pendingTransactions = new Map();
function checkStatus() {
if (context.status !== "ready") {
throw new Error(`ImageCacheEngine is ${context.status}`);
}
}
function startQueue() {
if (processing)
return;
processing = true;
void processAllPending(context)
.catch((error) => {
context.logger.error("Error when proccessing =>", error);
})
.then(() => {
processing = false;
});
}
function addPending(closeNow) {
const pendingId = ++pendingSeq;
pendingTransactions.set(pendingId, closeNow);
return () => {
pendingTransactions.delete(pendingId);
};
}
const imageCache = {
async getImageVariantWithBinary({ mediaId, mediaType, rawWidth, rawHeight }) {
checkStatus();
const taskKey = makeTaskKey({ mediaId, rawSizeName: `${rawWidth}x${rawHeight}`, mediaType });
const pth = context.pendingTasks.get(taskKey);
if (pth)
return pth.promise;
const found = await fetchImageVariantWithBinary(context, {
mediaId,
mediaType,
rawWidth,
rawHeight,
});
return found ? found.variant : undefined;
},
async getImageVariantWithBinaryByOwner(options) {
checkStatus();
const oneOwnerKey = makeOwnerKey(options);
const pth = context.pendingTaskByOwnerKeys.get(oneOwnerKey);
if (pth)
return pth.promise;
const found = await fetchImageVariantWithBinaryByOwner(context, options);
return found ? found.variant : undefined;
},
async makeImageAvailable({ ownerHandle, isHandleReusable, canBeRetrievedByOwner, ...input }) {
checkStatus();
const transaction = createOwnerTransaction({
engine: { context: context, startQueue, checkStatus, addPending },
ownerHandle,
isHandleReusable,
canBeRetrievedByOwner,
});
const [result] = await transaction.makeImageAvailable([input]);
await transaction.flush();
await transaction.close();
return result;
},
createOwnerTransaction(ownerHandle) {
checkStatus();
return createOwnerTransaction({
engine: { context: context, startQueue, checkStatus, addPending },
ownerHandle,
isHandleReusable: false,
canBeRetrievedByOwner: false,
});
},
async invalidate(options) {
checkStatus();
if ("ownerHandles" in options) {
await deleteVariantsByDependencies(context, options);
}
else {
await deleteVariants(context, options);
}
},
async cleanUnusedValues() {
checkStatus();
const count = await deleteOrphanVariants(context);
if (count !== undefined && count > 0) {
context.logger.debug(`${count} unused cache image were deleted`);
}
},
async clearCache() {
checkStatus();
await clearAll(context);
context.logger.debug("cache is cleared");
},
async getUsedRawSizesByMedia(mediaId) {
checkStatus();
return await fetchUsedRawSizesByMedia(context, mediaId);
},
async close() {
if (context.status === "closed")
return;
context.status = "closed";
for (const closeNow of pendingTransactions.values()) {
await closeNow();
}
await context.cn.destroy();
},
};
return {
imageCache,
isCleared,
};
}
//# sourceMappingURL=image-cache-engine.js.map