Track HiveGrid Cloud planning reference
This commit is contained in:
1 parent
b3d5ea6764
commit
e341c5938a
5784 files changed
+1104929
-3
No files matched your search
@@ -0,0 +1,85 @@
|
||||
// Producer-side helper for the toolctrl.file-scan BullMQ queue. Web routes
|
||||
// call enqueueFileScan(...) after a successful upload to trigger the
|
||||
// asynchronous post-upload ClamAV scan in the worker. Mirrors the
|
||||
// TransactionalEmailQueue.server.ts shape so the queue lifecycle is the
|
||||
// same shared pattern.
|
||||
|
||||
import {
|
||||
buildFileScanJob,
|
||||
enqueueJob,
|
||||
queueNames,
|
||||
resolveRedisConnectionOptions,
|
||||
resolveRedisConnectionOptionsFromProcessEnv,
|
||||
type RedisConnectionEnv,
|
||||
type TypedQueue,
|
||||
} from "@toolctrl/queue";
|
||||
|
||||
export type EnqueueFileScanInput = {
|
||||
bucket: string;
|
||||
key: string;
|
||||
tenantId?: string;
|
||||
uploadId?: string;
|
||||
contentType?: string;
|
||||
// AK-P4a §5 — File row id so the worker can write the verdict back onto
|
||||
// File.scanStatus (clean|infected). See enqueueFileScan callers.
|
||||
fileId?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type EnqueueFileScanResult =
|
||||
| { enqueued: true; jobId?: string }
|
||||
| { enqueued: false; reason: "scan-disabled" | "queue-unavailable" };
|
||||
|
||||
type Dependencies = {
|
||||
env?: RedisConnectionEnv & { SCAN_QUEUE_ENABLED?: string };
|
||||
queue?: TypedQueue<typeof queueNames.fileScan>;
|
||||
};
|
||||
|
||||
export async function enqueueFileScan(input: EnqueueFileScanInput, dependencies: Dependencies = {}): Promise<EnqueueFileScanResult> {
|
||||
const env = dependencies.env ?? (process.env as RedisConnectionEnv & { SCAN_QUEUE_ENABLED?: string });
|
||||
if (env.SCAN_QUEUE_ENABLED !== "true") {
|
||||
return { enqueued: false, reason: "scan-disabled" };
|
||||
}
|
||||
|
||||
let queue = dependencies.queue;
|
||||
let shouldCloseQueue = false;
|
||||
const connection = queue
|
||||
? undefined
|
||||
: dependencies.env
|
||||
? resolveRedisConnectionOptions({ env: dependencies.env })
|
||||
: resolveRedisConnectionOptionsFromProcessEnv();
|
||||
|
||||
if (!queue && !connection) {
|
||||
return { enqueued: false, reason: "queue-unavailable" };
|
||||
}
|
||||
|
||||
if (!queue && connection) {
|
||||
const queueRuntimeModule = "@toolctrl/queue/runtime";
|
||||
const { createQueue } = (await import(/* @vite-ignore */ queueRuntimeModule)) as typeof import("@toolctrl/queue/runtime");
|
||||
queue = createQueue(queueNames.fileScan, { connection });
|
||||
shouldCloseQueue = true;
|
||||
}
|
||||
if (!queue) {
|
||||
return { enqueued: false, reason: "queue-unavailable" };
|
||||
}
|
||||
|
||||
try {
|
||||
const descriptor = buildFileScanJob({
|
||||
bucket: input.bucket,
|
||||
key: input.key,
|
||||
tenantId: input.tenantId,
|
||||
uploadId: input.uploadId,
|
||||
contentType: input.contentType,
|
||||
fileId: input.fileId,
|
||||
metadata: input.metadata,
|
||||
});
|
||||
const job = await enqueueJob(queue, descriptor, {
|
||||
...(input.tenantId !== undefined ? { tenantId: input.tenantId } : {}),
|
||||
});
|
||||
return { enqueued: true, jobId: typeof job.id === "string" ? job.id : undefined };
|
||||
} finally {
|
||||
if (shouldCloseQueue && queue) {
|
||||
await queue.close().catch(() => {});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user