From 6ea3567c94d30d642e5b2f4e3a09597262642370 Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Wed, 5 Mar 2025 18:41:47 +0100 Subject: [PATCH] Refactor code saving data Move the code dealing with saving and loading data to server/database to gather it all up into one place. --- server/api/create-event.post.ts | 6 ++--- server/api/delete-event.post.ts | 6 ++--- server/api/modify-event.post.ts | 6 ++--- server/api/schedule.ts | 5 ++-- server/api/subscribe.post.ts | 18 +++----------- server/api/unsubscribe.post.ts | 18 +++----------- server/database.ts | 44 +++++++++++++++++++++++++++++++++ server/web-push.ts | 19 +++----------- 8 files changed, 64 insertions(+), 58 deletions(-) create mode 100644 server/database.ts diff --git a/server/api/create-event.post.ts b/server/api/create-event.post.ts index 018f1cc..079ae06 100644 --- a/server/api/create-event.post.ts +++ b/server/api/create-event.post.ts @@ -1,11 +1,11 @@ import { Schedule } from "~/shared/types/schedule"; -import { readFile, writeFile } from "node:fs/promises"; import { broadcastUpdate } from "~/server/streams"; import { sendPush } from "~/server/web-push"; +import { readSchedule, writeSchedule } from "~/server/database"; export default defineEventHandler(async (event) => { const formData = await readFormData(event); - const schedule: Schedule = JSON.parse(await readFile("schedule.json", "utf-8")); + const schedule: Schedule = await readSchedule(); const id = formData.get("id") as string; const name = formData.get("name") as string; const description = formData.get("description") as string; @@ -26,6 +26,6 @@ export default defineEventHandler(async (event) => { ] }); broadcastUpdate(schedule); - await writeFile("schedule.json", JSON.stringify(schedule, null, "\t"), "utf-8"); + await writeSchedule(schedule); await sendPush("New event", `${name} will start at ${start}`); }); diff --git a/server/api/delete-event.post.ts b/server/api/delete-event.post.ts index 147a636..d6ddc62 100644 --- a/server/api/delete-event.post.ts +++ b/server/api/delete-event.post.ts @@ -1,10 +1,10 @@ import { Schedule } from "~/shared/types/schedule"; -import { readFile, writeFile } from "fs/promises"; import { broadcastUpdate } from "~/server/streams"; +import { readSchedule, writeSchedule } from "~/server/database"; export default defineEventHandler(async (event) => { const formData = await readFormData(event); - const schedule: Schedule = JSON.parse(await readFile("schedule.json", "utf-8")); + const schedule: Schedule = await readSchedule(); const id = formData.get("id") as string; const index = schedule.events.findIndex(event => event.id === id); if (index === -1) { @@ -12,5 +12,5 @@ export default defineEventHandler(async (event) => { } schedule.events.splice(index, 1); broadcastUpdate(schedule); - await writeFile("schedule.json", JSON.stringify(schedule, null, "\t"), "utf-8"); + await writeSchedule(schedule); }); diff --git a/server/api/modify-event.post.ts b/server/api/modify-event.post.ts index f43de4d..985f5a5 100644 --- a/server/api/modify-event.post.ts +++ b/server/api/modify-event.post.ts @@ -1,11 +1,11 @@ import { Schedule } from "~/shared/types/schedule"; -import { readFile, writeFile } from "fs/promises"; import { broadcastUpdate } from "~/server/streams"; import { sendPush } from "~/server/web-push"; +import { readSchedule, writeSchedule } from "~/server/database"; export default defineEventHandler(async (event) => { const formData = await readFormData(event); - const schedule: Schedule = JSON.parse(await readFile("schedule.json", "utf-8")); + const schedule: Schedule = await readSchedule(); const id = formData.get("id") as string; const name = formData.get("name") as string; const description = formData.get("description") as string; @@ -31,7 +31,7 @@ export default defineEventHandler(async (event) => { ] }; broadcastUpdate(schedule); - await writeFile("schedule.json", JSON.stringify(schedule, null, "\t"), "utf-8"); + await writeSchedule(schedule); if (timeChanged) await sendPush(`New time for ${name}`, `${name} will now start at ${start}`); }); diff --git a/server/api/schedule.ts b/server/api/schedule.ts index 890ce6c..cf4630c 100644 --- a/server/api/schedule.ts +++ b/server/api/schedule.ts @@ -1,6 +1,5 @@ -import { readFile } from "node:fs/promises"; -import { Schedule } from "~/shared/types/schedule"; +import { readSchedule } from "~/server/database"; export default defineEventHandler(async (event) => { - return JSON.parse(await readFile("schedule.json", "utf-8")) as Schedule; + return await readSchedule(); }) diff --git a/server/api/subscribe.post.ts b/server/api/subscribe.post.ts index 5b8f4c9..a5f22bb 100644 --- a/server/api/subscribe.post.ts +++ b/server/api/subscribe.post.ts @@ -1,27 +1,15 @@ -import { readFile, writeFile } from "node:fs/promises"; +import { readSubscriptions, writeSubscriptions } from "~/server/database"; export default defineEventHandler(async (event) => { const body: { subscription: PushSubscriptionJSON } = await readBody(event); - let subscriptions: PushSubscriptionJSON[]; - try { - subscriptions = JSON.parse(await readFile("push-subscriptions.json", "utf-8")); - } catch (err: any) { - if (err.code !== "ENOENT") { - throw err; - } - subscriptions = []; - } + const subscriptions = await readSubscriptions(); const existingIndex = subscriptions.findIndex(sub => sub.endpoint === body.subscription.endpoint); if (existingIndex !== -1) { subscriptions[existingIndex] = body.subscription; } else { subscriptions.push(body.subscription); } - await writeFile( - "push-subscriptions.json", - JSON.stringify(subscriptions, undefined, "\t"), - "utf-8" - ); + await writeSubscriptions(subscriptions); if (existingIndex !== -1) { return { message: "Existing subscription refreshed."}; } diff --git a/server/api/unsubscribe.post.ts b/server/api/unsubscribe.post.ts index fc38069..e84bfcd 100644 --- a/server/api/unsubscribe.post.ts +++ b/server/api/unsubscribe.post.ts @@ -1,26 +1,14 @@ -import { readFile, writeFile } from "fs/promises"; +import { readSubscriptions, writeSubscriptions } from "~/server/database"; export default defineEventHandler(async (event) => { const body: { subscription: PushSubscriptionJSON } = await readBody(event); - let subscriptions: PushSubscriptionJSON[]; - try { - subscriptions = JSON.parse(await readFile("push-subscriptions.json", "utf-8")); - } catch (err: any) { - if (err.code !== "ENOENT") { - throw err; - } - subscriptions = []; - } + const subscriptions = await readSubscriptions(); const existingIndex = subscriptions.findIndex(sub => sub.endpoint === body.subscription.endpoint); if (existingIndex !== -1) { subscriptions.splice(existingIndex, 1); } else { return { message: "No subscription registered."}; } - await writeFile( - "push-subscriptions.json", - JSON.stringify(subscriptions, undefined, "\t"), - "utf-8" - ); + await writeSubscriptions(subscriptions); return { message: "Existing subscription removed."}; }) diff --git a/server/database.ts b/server/database.ts new file mode 100644 index 0000000..276cf1d --- /dev/null +++ b/server/database.ts @@ -0,0 +1,44 @@ +import { readFile, writeFile } from "node:fs/promises"; +import { Schedule } from "~/shared/types/schedule"; + +// For this demo I'm just storing the runtime data in JSON files. When making +// this into proper application this should be replaced with an actual database. + +const schedulePath = "schedule.json" +const subscriptionsPath = "push-subscriptions.json" + +export async function readSchedule() { + let schedule: Schedule; + try { + schedule = JSON.parse(await readFile(schedulePath, "utf-8")); + } catch (err: any) { + if (err.code !== "ENOENT") + throw err; + // Use an empty schedule if nothing is stored yet. + schedule = { + locations: [], + events: [], + } + } + return schedule;; +} + +export async function writeSchedule(schedule: Schedule) { + await writeFile(schedulePath, JSON.stringify(schedule, undefined, "\t") + "\n", "utf-8"); +} + +export async function readSubscriptions() { + let subscriptions: PushSubscriptionJSON[]; + try { + subscriptions = JSON.parse(await readFile(subscriptionsPath, "utf-8")); + } catch (err: any) { + if (err.code !== "ENOENT") + throw err; + subscriptions = []; + } + return subscriptions;; +} + +export async function writeSubscriptions(subscriptions: PushSubscriptionJSON[]) { + await writeFile(subscriptionsPath, JSON.stringify(subscriptions, undefined, "\t") + "\n", "utf-8"); +} diff --git a/server/web-push.ts b/server/web-push.ts index 79193ec..0f7178d 100644 --- a/server/web-push.ts +++ b/server/web-push.ts @@ -1,5 +1,5 @@ -import { readFile, writeFile } from "node:fs/promises"; import webPush from "web-push"; +import { readSubscriptions, writeSubscriptions } from "~/server/database"; webPush.setVapidDetails( "mailto:webmaster@hornwitser.no", @@ -9,16 +9,7 @@ webPush.setVapidDetails( export async function sendPush(title: string, body: string) { const payload = JSON.stringify({ title, body }); - let subscriptions: PushSubscriptionJSON[]; - try { - subscriptions = JSON.parse(await readFile("push-subscriptions.json", "utf-8")); - } catch (err: any) { - if (err.code !== "ENOENT") { - console.log(`Dropping "${payload}", no push subscribers`); - return; - } - subscriptions = []; - } + const subscriptions = await readSubscriptions(); console.log(`Sending "${payload}" to ${subscriptions.length} subscribers`); const removeIndexes = []; for (let index = 0; index < subscriptions.length; index += 1) { @@ -46,11 +37,7 @@ export async function sendPush(title: string, body: string) { for (const index of removeIndexes) { subscriptions.splice(index, 1); } - await writeFile( - "push-subscriptions.json", - JSON.stringify(subscriptions, undefined, "\t"), - "utf-8" - ); + await writeSubscriptions(subscriptions); } console.log("Push notices sent"); }