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(); } }