import { Either, ErrorSource, type IActivity, type IEither, type ITraceable, jsonModel, JsonResponse, LogLevel, Metric, PenguenoError, type PenguenoRequest, type ServerTrace, TraceUtil, validateExecutionEntries, } from "@emprespresso/pengueno"; import { isJob, type Job } from "@emprespresso/ci-model"; import type { IJobQueuer } from "@emprespresso/ci-hooks"; const wellFormedJobMetric = Metric.fromName("Job.WellFormed"); const jobJsonTransformer = ( j: ITraceable, ): IEither => j .bimap(TraceUtil.withMetricTrace(wellFormedJobMetric)) .map((tJson) => { if (!isJob(tJson) || !validateExecutionEntries(tJson)) { const err = "seems like a pwetty mawfomed job \\(-.-)/"; tJson.trace.addTrace(LogLevel.WARN).trace(err); return Either.left(new PenguenoError(err, 400)); } return Either.right(tJson); }) .peek((tJob) => tJob.trace.trace( tJob .get() .fold((err) => err ? wellFormedJobMetric.failure : wellFormedJobMetric.success, ), ), ) .get(); export interface IJobHookActivity { processHook: IActivity; } const jobHookRequestMetric = Metric.fromName("JobHook.process"); export class JobHookActivityImpl implements IJobHookActivity { constructor( private readonly queuer: IJobQueuer>, ) {} private trace(r: ITraceable) { return r .bimap(TraceUtil.withClassTrace(this)) .bimap(TraceUtil.withMetricTrace(jobHookRequestMetric)); } public processHook(r: ITraceable) { return this.trace(r) .map(jsonModel(jobJsonTransformer)) .map(async (tEitherJobJson) => { const eitherJob = await tEitherJobJson.get(); return eitherJob.flatMapAsync(async (job) => { const eitherQueued = await tEitherJobJson .move(job) .map(this.queuer.queue) .get(); return eitherQueued.mapLeft((e) => new PenguenoError(e.message, 500)); }); }) .peek( TraceUtil.promiseify((tJob) => tJob .get() .fold( (err: PenguenoError | undefined, _val: string | undefined) => { if (!err) { tJob.trace.trace(jobHookRequestMetric.success); tJob.trace.trace( `all queued up and weady to go :D !! ${_val}`, ); return; } tJob.trace.trace( err.source === ErrorSource.SYSTEM ? jobHookRequestMetric.failure : jobHookRequestMetric.warn, ); tJob.trace.addTrace(err.source).trace(`${err}`); }, ), ), ) .map( TraceUtil.promiseify( (tEitherQueuedJob) => new JsonResponse(r, tEitherQueuedJob.get(), { status: tEitherQueuedJob .get() .fold(({ status }, _val) => (_val ? 200 : status)), }), ), ) .get(); } }