UNPKG

@fontoxml/fontoxml-development-tools

Version:

Development tools for Fonto.

52 lines (49 loc) 1.67 kB
/** @typedef {import('express').Request} Request */ /** @typedef {import('express').Response} Response */ /** @typedef {import('express').NextFunction} NextFunction */ /** @typedef {import('./connectors-cms-standard/stores/DevelopmentCms').DevCmsFileLock} DevCmsFileLock */ /** * Wrapper which cleans up locks on completion of the request, and allows async handlers. * * @description * Express does not handle rejected promises, so this also explicitly catches and handles them. * * @param {(acquireLock: (filePath) => Promise<DevCmsFileLock>, req: Request, res: Response, next: NextFunction) => Promise<void>} asyncHandler * * @return {(req: Request, res: Response, next: NextFunction) => void} */ export default function asyncRouteWithLockCleanupHandler(asyncHandler) { return async (req, res, next) => { let hasCalledNext = false; /** @type {Promise<DevCmsFileLock>[]} */ const lockPromises = []; try { const acquireLock = async (filePath) => { const lockPromise = req.cms.acquireLock(filePath); lockPromises.push(lockPromise); return lockPromise; }; await asyncHandler(acquireLock, req, res, next); } catch (error) { // Pass any error to the next middleware / default error handler. hasCalledNext = true; next(error); } finally { // Release all locks. Note that locks might already have been released. for (const lockPromise of lockPromises) { let firstError; try { (await lockPromise).release(); } catch (error) { if (!firstError) { firstError = error; } } if (firstError && !hasCalledNext) { hasCalledNext = true; next(firstError); } } } }; }