Jerryo / src /server /jobStore.ts
EricaLuvGemma's picture
Upload 6 files
972b772 verified
Raw
History Blame Contribute Delete
1.99 kB
import * as fs from "fs";
import * as path from "path";
import { EventEmitter } from "events";
import { DownloadJob } from "./types";
const DATA_DIR = path.join(__dirname, "..", "data");
const JOBS_FILE = path.join(DATA_DIR, "jobs.json");
if (!fs.existsSync(DATA_DIR)) {
fs.mkdirSync(DATA_DIR, { recursive: true });
}
if (!fs.existsSync(JOBS_FILE)) {
fs.writeFileSync(JOBS_FILE, "[]", "utf-8");
}
// Fired every time a job is created or updated, so the SSE route can push
// live status to the frontend without polling the file.
export const jobEvents = new EventEmitter();
function readAll(): DownloadJob[] {
const raw = fs.readFileSync(JOBS_FILE, "utf-8");
try {
return JSON.parse(raw) as DownloadJob[];
} catch {
return [];
}
}
function writeAll(jobs: DownloadJob[]): void {
fs.writeFileSync(JOBS_FILE, JSON.stringify(jobs, null, 2), "utf-8");
}
export function listJobs(): DownloadJob[] {
return readAll().sort((a, b) => (a.createdAt < b.createdAt ? 1 : -1));
}
export function getJob(id: string): DownloadJob | undefined {
return readAll().find((j) => j.id === id);
}
export function createJob(title: string, sourceUrl: string): DownloadJob {
const now = new Date().toISOString();
const job: DownloadJob = {
id: `job_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
title,
sourceUrl,
status: "queued",
progress: 0,
bytesReceived: 0,
bytesTotal: null,
filePath: null,
error: null,
createdAt: now,
updatedAt: now,
};
const jobs = readAll();
jobs.push(job);
writeAll(jobs);
jobEvents.emit("update", job);
return job;
}
export function updateJob(id: string, patch: Partial<DownloadJob>): DownloadJob | undefined {
const jobs = readAll();
const idx = jobs.findIndex((j) => j.id === id);
if (idx === -1) return undefined;
jobs[idx] = { ...jobs[idx], ...patch, updatedAt: new Date().toISOString() };
writeAll(jobs);
jobEvents.emit("update", jobs[idx]);
return jobs[idx];
}