UNPKG

@bitblit/ratchet-epsilon-common

Version:

Tiny adapter to simplify building API gateway Lambda APIS

129 lines 6.44 kB
import { Logger } from '@bitblit/ratchet-common/logger/logger'; import { BackgroundProcessHandling } from './background-process-handling.js'; import { BadRequestError } from '../http/error/bad-request-error.js'; import { NotFoundError } from '../http/error/not-found-error.js'; import { PromiseRatchet } from '@bitblit/ratchet-common/lang/promise-ratchet'; import { StringRatchet } from '@bitblit/ratchet-common/lang/string-ratchet'; import { StopWatch } from '@bitblit/ratchet-common/lang/stop-watch'; import { BooleanRatchet } from '@bitblit/ratchet-common/lang/boolean-ratchet'; export class BackgroundHttpAdapterHandler { backgroundConfig; modelValidator; backgroundManager; maxWaitInMsForBackgroundJobToStart; constructor(backgroundConfig, modelValidator, backgroundManager, maxWaitInMsForBackgroundJobToStart = 10_000) { this.backgroundConfig = backgroundConfig; this.modelValidator = modelValidator; this.backgroundManager = backgroundManager; this.maxWaitInMsForBackgroundJobToStart = maxWaitInMsForBackgroundJobToStart; } get httpMetaEndpoint() { return this.backgroundConfig.httpMetaEndpoint; } get httpSubmissionPath() { return this.backgroundConfig.httpSubmissionPath; } get httpStatusPath() { return this.backgroundConfig.httpStatusEndpoint; } get implyTypeFromPathSuffix() { return this.backgroundConfig.implyTypeFromPathSuffix; } async handleBackgroundStatusRequest(evt, _context) { Logger.info('handleBackgroundStatusRequest called'); if (!this.backgroundConfig.transactionLogger) { throw new BadRequestError('Process logging not enabled'); } else { const guid = StringRatchet.trimToNull(evt.pathParameters['guid']) || StringRatchet.trimToNull(evt.queryStringParameters['guid']); if (guid) { const sw = new StopWatch(); let log = null; while (!log && sw.elapsedMS() < this.maxWaitInMsForBackgroundJobToStart) { log = await this.backgroundConfig.transactionLogger.readTransactionLog(guid); if (!log) { Logger.debug('No log found yet, waiting 500 ms and retrying (%s of %d waited so far)', sw.dump(), this.maxWaitInMsForBackgroundJobToStart); await PromiseRatchet.wait(500); } } if (!log) { throw new NotFoundError().withFormattedErrorMessage('No background result found for guid %s', guid); } return log; } else { throw new BadRequestError('No guid specified'); } } } async handleBackgroundMetaRequest(_evt, _context) { Logger.info('handleBackgroundMetaRequest called'); const currentCount = await this.backgroundManager.fetchApproximateNumberOfQueueEntries(); const valid = this.backgroundConfig.processors.map((b) => b.typeName).filter((a) => !!a); valid.sort((a, b) => a.localeCompare(b)); const rval = { currentQueueLength: currentCount, validTypes: valid, backgroundManagerName: this.backgroundManager.backgroundManagerName, }; return rval; } async handleBackgroundSubmission(evt, _context) { Logger.info('handleBackgroundSubmission : %j (mgr:%s)', evt.parsedBody, this.backgroundManager.backgroundManagerName); let rval = null; const startIdx = evt.path.indexOf(this.httpSubmissionPath) + this.httpSubmissionPath.length; let pathSuppliedBackgroundType = this.backgroundConfig.implyTypeFromPathSuffix ? evt.path.substring(startIdx).split('-').join('').toLowerCase() : ''; if (pathSuppliedBackgroundType.includes('?')) { pathSuppliedBackgroundType = pathSuppliedBackgroundType.substring(0, pathSuppliedBackgroundType.indexOf('?')); } if (pathSuppliedBackgroundType.includes('#')) { pathSuppliedBackgroundType = pathSuppliedBackgroundType.substring(0, pathSuppliedBackgroundType.indexOf('#')); } const entry = evt.parsedBody || {}; if (StringRatchet.trimToNull(pathSuppliedBackgroundType)) { if (StringRatchet.trimToNull(entry?.type) && entry.type.toLocaleLowerCase() !== pathSuppliedBackgroundType.toLocaleLowerCase()) { throw new BadRequestError('Background submission has type but does not match path supplied type'); } else { entry.type = pathSuppliedBackgroundType; } } else { if (!StringRatchet.trimToNull(entry?.type)) { throw new BadRequestError('Background submission missing type and not configured in pathed mode'); } } const foundProc = this.backgroundConfig.processors.find((s) => s.typeName.toLowerCase() === entry.type.toLowerCase()); const immediate = BooleanRatchet.parseBool(evt.queryStringParameters['immediate']); const startProcessor = BooleanRatchet.parseBool(evt.queryStringParameters['startProcessor']); if (foundProc) { if (StringRatchet.trimToNull(foundProc.dataSchemaName)) { const errors = this.modelValidator.validate(foundProc.dataSchemaName, entry.data, false, false); if (errors.length > 0) { throw new BadRequestError().withErrors(errors); } } let result = null; if (immediate) { result = await this.backgroundManager.fireImmediateProcessRequest(entry); } else { result = await this.backgroundManager.addEntryToQueue(entry, startProcessor); } rval = { processHandling: immediate ? BackgroundProcessHandling.Immediate : BackgroundProcessHandling.Queued, startProcessorRequested: startProcessor, success: true, resultId: result, error: null, }; } else { throw new BadRequestError().withFormattedErrorMessage('Could not find target background processor : %s', entry.type); } return rval; } } //# sourceMappingURL=background-http-adapter-handler.js.map