From 6412f46a45d3b66c85c0cc3952206ad9cca0a110 Mon Sep 17 00:00:00 2001 From: Linnnus Date: Sat, 22 Feb 2025 06:50:02 +0100 Subject: Add watermarking service, fix everything --- app/src/app.d.ts | 3 +++ app/src/hooks.server.ts | 13 +++++++---- app/src/lib/common/assignments.ts | 18 +++++++-------- app/src/lib/server/assignments.ts | 27 +++++++++++++++------- app/src/lib/server/beanstalkd.ts | 19 +++++++++++++++ app/src/routes/assignments/+page.svelte | 19 +++++++++++---- .../assignments/[assignmentId]/+page.server.ts | 8 ++++++- .../routes/assignments/[assignmentId]/+page.svelte | 4 +++- 8 files changed, 83 insertions(+), 28 deletions(-) create mode 100644 app/src/lib/server/beanstalkd.ts (limited to 'app/src') diff --git a/app/src/app.d.ts b/app/src/app.d.ts index 6dba3f1..71e7b15 100644 --- a/app/src/app.d.ts +++ b/app/src/app.d.ts @@ -1,5 +1,6 @@ import type { User } from "$lib/server/users"; import type { S3Client } from "@aws-sdk/client-s3"; +import type BeanstalkdClient from "beanstalkd"; import type { PoolClient } from "pg"; // See https://svelte.dev/docs/kit/types#app.d.ts @@ -12,6 +13,8 @@ declare global { s3Client: S3Client; + beanstalkdClient: BeanstalkdClient; + /** * The user, if they are logged in. * diff --git a/app/src/hooks.server.ts b/app/src/hooks.server.ts index f342e03..78342cd 100644 --- a/app/src/hooks.server.ts +++ b/app/src/hooks.server.ts @@ -1,21 +1,23 @@ -import { getDbConnection } from "$lib/server/db"; +import { getDbClient } from "$lib/server/db"; import { getS3Client } from "$lib/server/s3"; import { validateSessionToken } from "$lib/server/sessions"; import { type Handle } from "@sveltejs/kit"; import { sequence } from "@sveltejs/kit/hooks"; +import { beanstalkdHandle } from "$lib/server/beanstalkd"; const dbHandle = (async ({ event, resolve }) => { - const dbConn = await getDbConnection(); - event.locals.dbConn = dbConn; + const dbClient = await getDbClient(); + event.locals.dbClient = dbClient; try { return await resolve(event); } finally { - dbConn.release(); + dbClient.release(); } }) satisfies Handle; // FIXME: Kind of stupid to load for every request. Should probs move handler to $lib and import for relevant routes. +// Same goes for beanstalkd. const s3Handle = (async ({ event, resolve }) => { const s3Client = getS3Client(); event.locals.s3Client = s3Client; @@ -39,4 +41,5 @@ const sessionHandle = (async ({ event, resolve }) => { return resolve(event); }) satisfies Handle; -export const handle = sequence(dbHandle, s3Handle, sessionHandle); +// FIXME: Kind of stupid to load for every request. Should probs move handler to $lib and import for relevant routes. +export const handle = sequence(dbHandle, s3Handle, beanstalkdHandle, sessionHandle); diff --git a/app/src/lib/common/assignments.ts b/app/src/lib/common/assignments.ts index 79553cd..6e9d574 100644 --- a/app/src/lib/common/assignments.ts +++ b/app/src/lib/common/assignments.ts @@ -7,12 +7,12 @@ export interface CemetaryPlot { } /** Corresponds to `assignment_state`. */ -export type AssignmentState = "AWAITING_GARDENER_NOTIFICATION" - | "AWAITING_FINISH" - | "AWAITING_WATERMARKING" - | "AWAITING_OWNER_NOTIFICATION" - | "DONE" - ; +export type AssignmentState = + | "AWAITING_GARDENER_NOTIFICATION" + | "AWAITING_FINISH" + | "AWAITING_WATERMARKING" + | "AWAITING_OWNER_NOTIFICATION" + | "DONE"; /** A row from the `assignments` table. */ export interface Assignment { @@ -23,10 +23,10 @@ export interface Assignment { state: AssignmentState; } - // FIXME: We have ORM at home. A more clearly defined (OOP) model layer. /** Checks whether the state of the assignment allows it to be "finished". */ export function canBeFinished(assignment: Assignment): boolean { - return (assignment.state === "AWAITING_GARDENER_NOTIFICATION" || - assignment.state === "AWAITING_FINISH") + return ( + assignment.state === "AWAITING_GARDENER_NOTIFICATION" || assignment.state === "AWAITING_FINISH" + ); } diff --git a/app/src/lib/server/assignments.ts b/app/src/lib/server/assignments.ts index c66f25c..9c28cff 100644 --- a/app/src/lib/server/assignments.ts +++ b/app/src/lib/server/assignments.ts @@ -1,6 +1,7 @@ -import { PutObjectCommand, type S3Client } from "@aws-sdk/client-s3"; /*=;* / +import { PutObjectCommand, type S3Client } from "@aws-sdk/client-s3"; /*=;*/ import type { ClientBase } from "pg"; -import type { CemetaryPlot, Assignment, AssignmentState } from "../common/assignments"; +import type { CemetaryPlot, Assignment } from "../common/assignments"; +import type BeanstalkdClient from "beanstalkd"; /** * Retrieves all assignments for the given user. @@ -73,17 +74,24 @@ export async function getAssignmentAndCemetaryById( } export interface FinishAssignmentArgs { + dbClient: ClientBase; + s3Client: S3Client; + beanstalkdClient: BeanstalkdClient; + images: { bytes: Uint8Array; name: string }[]; note?: string; assignmentId: number; } // TODO: Error recovery. -export async function finishAssignment( - dbClient: ClientBase, - s3Client: S3Client, - { images, note, assignmentId }: FinishAssignmentArgs, -): Promise { +export async function finishAssignment({ + dbClient, + s3Client, + beanstalkdClient, + images, + note, + assignmentId, +}: FinishAssignmentArgs): Promise { // Upload to S3, returning path // FIXME: Should be factored out? const uploadPromises = images.map(async (image) => { @@ -101,7 +109,10 @@ export async function finishAssignment( }); const uploadedImages = await Promise.all(uploadPromises); - // TODO: Add beanstalkd job + // Instruct background worker to do watermarking. + // FIXME: magic constants yay how fun + await beanstalkdClient.use("watermarking"); + console.debug(await beanstalkdClient.put(0, 0, 60, JSON.stringify({ assignmentId }))); await dbClient.query("BEGIN"); diff --git a/app/src/lib/server/beanstalkd.ts b/app/src/lib/server/beanstalkd.ts new file mode 100644 index 0000000..10f392a --- /dev/null +++ b/app/src/lib/server/beanstalkd.ts @@ -0,0 +1,19 @@ +import pkg from "beanstalkd"; +import type { Handle } from "@sveltejs/kit"; + +// Annoying CommonJS interop issue (vitejs/vite#2139) which combines with incorrect typings from DefinitelyTyped project :( +// @ts-ignore +const BeanstalkdClient = pkg.default as typeof pkg; + +export const beanstalkdHandle = (async ({ event, resolve }) => { + // FIXME: Should obv. read from env. + const beanstalkdClient = new BeanstalkdClient("localhost", 11300); + await beanstalkdClient.connect(); + + event.locals.beanstalkdClient = beanstalkdClient; + try { + return await resolve(event); + } finally { + beanstalkdClient.quit(); + } +}) satisfies Handle; diff --git a/app/src/routes/assignments/+page.svelte b/app/src/routes/assignments/+page.svelte index f43767d..5a3a4cb 100644 --- a/app/src/routes/assignments/+page.svelte +++ b/app/src/routes/assignments/+page.svelte @@ -1,15 +1,19 @@ -

Kommende opgaver for {data.user.firstName}

+

{data.user.firstName}s opgaver

+

Kommende opgaver

    - {#each data.assignments as assignment} + {#each unfinishedAssignments as assignment}
  1. {assignment.date} Mere info @@ -17,5 +21,12 @@ {/each}
- +

Færdiggjorte opgaver

+
    + {#each finishedAssignments as assignment} +
  1. + {assignment.date} + Mere info +
  2. + {/each} +
diff --git a/app/src/routes/assignments/[assignmentId]/+page.server.ts b/app/src/routes/assignments/[assignmentId]/+page.server.ts index 3b53a7c..b6634f0 100644 --- a/app/src/routes/assignments/[assignmentId]/+page.server.ts +++ b/app/src/routes/assignments/[assignmentId]/+page.server.ts @@ -42,7 +42,13 @@ export const actions = { })), ); - await finishAssignment(locals.dbClient, locals.s3Client, { + const { beanstalkdClient, dbClient, s3Client } = locals; + + await finishAssignment({ + beanstalkdClient, + dbClient, + s3Client, + images, note, assignmentId: +params.assignmentId, // We have parsing at home... diff --git a/app/src/routes/assignments/[assignmentId]/+page.svelte b/app/src/routes/assignments/[assignmentId]/+page.svelte index 6b24f38..bf955f9 100644 --- a/app/src/routes/assignments/[assignmentId]/+page.svelte +++ b/app/src/routes/assignments/[assignmentId]/+page.svelte @@ -30,7 +30,9 @@ -- cgit v1.2.3