diff options
author | Elizabeth Alexander Hunt <me@liz.coffee> | 2025-05-13 09:50:15 -0700 |
---|---|---|
committer | Elizabeth Alexander Hunt <me@liz.coffee> | 2025-05-13 09:50:15 -0700 |
commit | 2543ac8b11af11f034836591046cdb52911f9403 (patch) | |
tree | d2fa475348c9867aab2994e9914895a57db88d75 /hooks/mod.ts | |
parent | e49fda41176d025a671802be76c219d66167276f (diff) | |
download | ci-2543ac8b11af11f034836591046cdb52911f9403.tar.gz ci-2543ac8b11af11f034836591046cdb52911f9403.zip |
snapshot
Diffstat (limited to 'hooks/mod.ts')
-rw-r--r--[-rwxr-xr-x] | hooks/mod.ts | 274 |
1 files changed, 2 insertions, 272 deletions
diff --git a/hooks/mod.ts b/hooks/mod.ts index 9df7d67..738003c 100755..100644 --- a/hooks/mod.ts +++ b/hooks/mod.ts @@ -1,272 +1,2 @@ -#!/usr/bin/env -S deno run --allow-env --allow-net --allow-run - -import { - getRequiredEnv, - getStdout, - invalidExecutionEntriesOf, - Traceable, - ITraceable, - ITraceableLogger, - IEither, - Either, -} from "@liz-ci/utils"; -import type { Job } from "@liz-ci/model"; - -const SERVER_CONFIG = { - host: "0.0.0.0", - port: 9000, -}; -interface IHealthCheckActivity { - healthCheck(req: Traceable<Request>): Traceable<Promise<Response>>; -} - -class HealthCheckActivity implements IHealthCheckActivity { - public healthCheck( - req: Traceable<Request>, - ) { - return req.map(async ({ logger }) => { - try { - getRequiredEnv("LAMINAR_HOST"); - await getStdout(["laminarc", "show-jobs"]); - const msg = `think im healthy!! (✿˘◡˘) ready to do work~\n`; - logger.log(msg); - return new Response( - msg, - { status: 200 }, - ); - } catch (error) { - logger.error(error); - return new Response( - "oh no, i need to eat more vegetables (。•́︿•̀。)...\n", - { status: 500 }, - ); - } - }); - } -} - -const aPost = (req: Traceable<Request>): IEither<Response, Request> => { - const {item: request, logger} = req; - const {method} = request; - if (method !== "POST") { - const msg = "that's not how you pet me (⋟﹏⋞) try post instead~"; - logger.warn(msg); - return { err: new Response(msg + "\n", {status: 405}) }; - } - return {ok: request}; -}; - -type JsonTransformer<JsonT, R> = (json: Traceable<JsonT>) => Either<string, R>; -const aJson = <BodyT, JsonT = unknown>(jsonTransformer: JsonTransformer<JsonT, BodyT>) => - (r: Traceable<Request>) => r - .map(async ({item: request, logger}): Promise<Either<string, JsonT>> => { - try { - return {ok: <JsonT>(await request.json())}; - } catch (e) { - const err = "seems to be invalid JSON (>//<) can you fix?"; - logger.warn(err); - return { err }; - } - }) - .flatMapAsync(TraceableImpl.promiseify((t): Traceable<Either<string, BodyT>> => { - const {item: {err, ok: json}} = t; - if (err) return t.map(() => ({ err })); - return t.map(() => json!).map(jsonTransformer); - })) - - -interface IJobHookActivity { - processHook(req: Traceable<Request>): Traceable<Promise<Response>>; -} -type GetJobRequest = { jobType: string; args: unknown }; -class JobHookActivityImpl implements IJobHookActivity { - constructor(private readonly queuer: IJobQueuer) {} - - private getJob( - { logger, item }: Traceable<unknown>, - ): Either<string, Job> { - const isObject = (o: unknown): o is Record<string, unknown> => - typeof o === "object" && !Array.isArray(o) && !!o; - if (!isObject(item) || !isObject(item.arguments)|| typeof item.type !== "string") { - const err = "seems like a pwetty mawfomed job \\(-.-)/"; - logger.warn(err) - return { err }; - } - - const ok = { type: item.type, arguments: item.arguments }; - const invalidArgEntries = invalidExecutionEntriesOf({type: ok.type, ...ok.arguments}); - if (invalidArgEntries.length > 0) { - const err = "your reqwest seems invawid (´。﹏。`) can you fix? uwu\n" + invalidArgEntries; - logger.warn(err); - return { err }; - } - - return { ok: <Job>ok }; - } - - public processHook(r: Traceable<Request>) { - return r.map(aPost) - .map((t) => { - either((err) => ({ err }), (request) => ) - const {item: {ok: request, err}} = t; - if (err) return <Traceable<{ err: Response }>> t; - return t.map(() => request!).map(aJson(this.getJob)); - }); -// flatMapAsync(aJsonPost(this.getJob)) -// .map(TraceableImpl.promiseify((g) => { -// if (jobRequest) { -// return g.map(() => jobRequest) -// .map(this.getJob) -// .map( -// ({ item: { ok: jobRequest, err } }) => { -// if (err) return { err: new Response(err, { status: 400 }) }; -// return { ok: jobRequest }; -// }, -// ); -// } -// return g.map(() => ({ ok: undefined, err })); -// })) -// .map(TraceableImpl.promiseify(({ item: t }) => { -// const { item: { ok: job, err } } = t; -// if (err) return t.map(() => Promise.resolve(err)); -// -// return t.map(() => job!) -// .map(this.queuer.queue) -// .map(TraceableImpl.promiseify(({ item, logger }) => { -// if (item.ok) { -// return new Response(item.ok, { status: 200 }); -// } -// logger.error(item.err); -// return new Response("i messed up D:\n", { status: 500 }); -// })); -// })); -// } -} - -class LizCIServerImpl implements ILizCIServer { - constructor( - private readonly healthCheckActivity: IHealthCheckActivity, - private readonly jobHookActivity: IJobHookActivity, - ) {} - - private route( - req: Traceable<Request & { pathname: string }>, - ): Traceable<Promise<Response>> { - return req.flatMap((req) => { - const { logger, item: { method, pathname } } = req; - if (pathname === "/health") { - return this.healthCheckActivity.healthCheck(req); - } - return this.jobHookActivity.processHook(req); - }); - } - - public async serve(req: Request): Promise<Response> { - const traceId = crypto.randomUUID(); - const { pathname } = new URL(req.url); - const traceSupplier = () => `[${traceId} <- ${req.method}'d @ ${pathname}]`; - return TraceableImpl.from(req) - .bimap(({ item: req }) => [{ req, pathname }, traceSupplier]) - .flatMap(this.route) - .map(({ item, logger }) => - item.catch((e) => { - const errorMessage = `oh noes! something went wrong (ಥ_ಥ) so sowwy!`; - logger.error(errorMessage, e); - return new Response(`${errorMessage}\n`, { status: 500 }); - }) - ) - .item; - } -} - -class JobQueue { - private readonly logger: PrefixLogger; - private readonly url: URL; - private readonly pathname: string; - - constructor(private readonly request: Request, private readonly) { - this.url = new URL(request.url); - this.pathname = this.url.pathname; - this.logger = this.createLogger(); - } - - /** - * Creates a logger with request-specific context - */ - - /** - * Performs health checks on dependent services - */ - private async performHealthCheck(): Promise<void> { - } - - /** - * Handles health check requests - */ - private async handleHealthCheck(): Promise<Response> { - try { - await this.performHealthCheck(); - } catch (error) { - } - } - - /** - * Queues a job in the laminar system - */ - private async queueJob(jobName: string, args: JobRequest): Promise<Response> { - } - - /** - * Validates job request parameters - */ - private validateJobRequest( - jobName: string, - args: unknown, - ): { valid: boolean; response?: Response } { - } - - /** - * Main method to handle the request - */ - public async handle(): Promise<Response> { - this.logger.log("go! :DDD"); - - // Handle health check requests - if (this.pathname === "/health") { - return this.handleHealthCheck(); - } - - // Validate HTTP method - if (this.request.method !== "POST") { - } - - // Extract job name from path - - if (!validation.valid) { - return validation.response!; - } - - // Queue the job - return this.queueJob(jobName, requestBody as JobRequest); - } - - /** - * Handles the entire request lifecycle, including error handling - */ - public async processRequest(): Promise<Response> { - try { - return await this.handle(); - } catch (error) { - } finally { - this.logger.log("allll done!"); - } - } -} - -/** - * Entry point - starts the server - */ -Deno.serve(SERVER_CONFIG, async (request: Request) => { - const handler = new RequestHandler(request); - return handler.processRequest(); -}); +export * from "./queuer.ts"; +export * from "./server.ts"; |