diff --git a/packages/server/prisma/dbml/schema.dbml b/packages/server/prisma/dbml/schema.dbml index d7f5123..19dc59d 100644 --- a/packages/server/prisma/dbml/schema.dbml +++ b/packages/server/prisma/dbml/schema.dbml @@ -2,6 +2,11 @@ //// THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) //// ------------------------------------------------------ +Table Setting { + key String [pk] + value String [not null] +} + Table User { sub String [pk] lastPixelTime DateTime [default: `now()`, not null] diff --git a/packages/server/prisma/migrations/20240530220300_add_settings/migration.sql b/packages/server/prisma/migrations/20240530220300_add_settings/migration.sql new file mode 100644 index 0000000..666328d --- /dev/null +++ b/packages/server/prisma/migrations/20240530220300_add_settings/migration.sql @@ -0,0 +1,7 @@ +-- CreateTable +CREATE TABLE "Setting" ( + "key" TEXT NOT NULL, + "value" TEXT NOT NULL, + + CONSTRAINT "Setting_pkey" PRIMARY KEY ("key") +); diff --git a/packages/server/prisma/schema.prisma b/packages/server/prisma/schema.prisma index 599b5b1..85f3280 100644 --- a/packages/server/prisma/schema.prisma +++ b/packages/server/prisma/schema.prisma @@ -14,6 +14,11 @@ datasource db { url = env("DATABASE_URL") } +model Setting { + key String @id + value String // this value will be parsed with JSON.parse +} + model User { sub String @id lastPixelTime DateTime @default(now()) // the time the last pixel was placed at diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 7da56d3..b8fdd8a 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -5,6 +5,7 @@ import { Logger } from "./lib/Logger"; import { ExpressServer } from "./lib/Express"; import { SocketServer } from "./lib/SocketServer"; import { OpenID } from "./lib/oidc"; +import { loadSettings } from "./lib/Settings"; // Validate environment variables @@ -57,10 +58,16 @@ if (!process.env.OIDC_CALLBACK_HOST) { process.exit(1); } -Redis.connect(); -OpenID.setup().then(() => { - Logger.info("Setup OpenID"); -}); +// run startup tasks, all of these need to be completed to serve +Promise.all([ + Redis.connect(), + OpenID.setup().then(() => { + Logger.info("Setup OpenID"); + }), + loadSettings(), +]).then(() => { + Logger.info("Startup tasks have completed, starting server"); -const express = new ExpressServer(); -new SocketServer(express.httpServer); + const express = new ExpressServer(); + new SocketServer(express.httpServer); +}); diff --git a/packages/server/src/lib/Canvas.ts b/packages/server/src/lib/Canvas.ts index 9c4fc80..fcf75c0 100644 --- a/packages/server/src/lib/Canvas.ts +++ b/packages/server/src/lib/Canvas.ts @@ -2,6 +2,7 @@ import { CanvasConfig } from "@sc07-canvas/lib/src/net"; import { prisma } from "./prisma"; import { Redis } from "./redis"; import { SocketServer } from "./SocketServer"; +import { Logger } from "./Logger"; class Canvas { /** @@ -37,7 +38,23 @@ class Canvas { * @param height */ async setSize(width: number, height: number) { + Logger.info("Canvas#setSize has started", { + old: this.canvasSize, + new: [width, height], + }); + this.canvasSize = [width, height]; + await prisma.setting.upsert({ + where: { key: "canvas.size" }, + create: { + key: "canvas.size", + value: JSON.stringify({ width, height }), + }, + update: { + key: "canvas.size", + value: JSON.stringify({ width, height }), + }, + }); // we're about to use the redis keys, make sure they are all updated await this.pixelsToRedis(); @@ -51,6 +68,8 @@ class Canvas { await this.getPixelsArray().then((pixels) => { SocketServer.instance.io.emit("canvas", pixels); }); + + Logger.info("Canvas#setSize has finished"); } /** diff --git a/packages/server/src/lib/Settings.ts b/packages/server/src/lib/Settings.ts new file mode 100644 index 0000000..3b95600 --- /dev/null +++ b/packages/server/src/lib/Settings.ts @@ -0,0 +1,31 @@ +import Canvas from "./Canvas"; +import { Logger } from "./Logger"; +import { prisma } from "./prisma"; + +export const loadSettings = async () => { + Logger.info("Loading settings..."); + + const sideEffects: Promise[] = []; + + // canvas size + const canvasSize = await prisma.setting.findFirst({ + where: { key: "canvas.size" }, + }); + if (canvasSize) { + const data = JSON.parse(canvasSize.value); + Logger.info("Canvas size loaded as " + JSON.stringify(data)); + sideEffects.push( + Canvas.setSize(data.width, data.height).then(() => { + Logger.info("Canvas size successfully updated"); + }) + ); + } else { + Logger.warn("Setting canvas.size is not set, did you run init_settings?"); + } + + Logger.info( + "Settings loaded into memory, waiting for side effects to finish..." + ); + + await Promise.allSettled(sideEffects); +}; diff --git a/packages/server/src/tools/init_settings.ts b/packages/server/src/tools/init_settings.ts new file mode 100644 index 0000000..2fe3b45 --- /dev/null +++ b/packages/server/src/tools/init_settings.ts @@ -0,0 +1,41 @@ +import { PrismaClient } from "@prisma/client"; + +const prisma = new PrismaClient(); + +// eslint-disable-next-line no-console +const log = (...msg: any[]) => console.log(...msg); + +async function main() { + const SETTINGS: { key: string; defaultValue: any }[] = [ + { + key: "canvas.size", + defaultValue: { + width: 100, + height: 100, + }, + }, + ]; + + for (const setting of SETTINGS) { + log("Ensuring setting", setting.key); + await prisma.setting.upsert({ + where: { key: setting.key }, + update: {}, + create: { + key: setting.key, + value: JSON.stringify(setting.defaultValue), + }, + }); + } +} + +main() + .then(async () => { + await prisma.$disconnect(); + }) + .catch(async (e) => { + // eslint-disable-next-line no-console + console.error(e); + await prisma.$disconnect(); + process.exit(1); + });