summaryrefslogtreecommitdiff
path: root/hooks/mod.ts
diff options
context:
space:
mode:
authorElizabeth Alexander Hunt <me@liz.coffee>2025-05-13 09:50:15 -0700
committerElizabeth Alexander Hunt <me@liz.coffee>2025-05-13 09:50:15 -0700
commit2543ac8b11af11f034836591046cdb52911f9403 (patch)
treed2fa475348c9867aab2994e9914895a57db88d75 /hooks/mod.ts
parente49fda41176d025a671802be76c219d66167276f (diff)
downloadci-2543ac8b11af11f034836591046cdb52911f9403.tar.gz
ci-2543ac8b11af11f034836591046cdb52911f9403.zip
snapshot
Diffstat (limited to 'hooks/mod.ts')
-rw-r--r--[-rwxr-xr-x]hooks/mod.ts274
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";