@bitblit/ratchet-epsilon-common
Version:
Tiny adapter to simplify building API gateway Lambda APIS
129 lines • 6.44 kB
JavaScript
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