import {DiscordWebhookHandler, OAuthRoute} from "./DiscordWebhookHandler.js"; import {getBaseUrl} from "./FastifyHelpers.js"; import pug from "pug"; import {renderError} from "./PugRenderer.js"; import {GameServer} from "./GameServer.js"; import {checkAndClearXSRFCookie, generateXSRFCookie, XSRFRoute} from "./CookieHelpers.js"; import {SetupCommand, setupComponentInteractionHandler} from "./commands/SetupCommand.js"; import {BaseServer, BaseServerDeps} from "./BaseServer.js"; export class SetupServer extends BaseServer { readonly gameFactory: () => GameServer constructor(deps: BaseServerDeps & { gameFactory: () => GameServer }) { super(deps) this.gameFactory = deps.gameFactory } async _initInternal(): Promise { this.slashcmd.registerCommand(new SetupCommand(this.slashcmd)) this.slashcmd.on("componentInteraction", setupComponentInteractionHandler) const gameHandler = new DiscordWebhookHandler({ webhook: this.gameWebhook, templateFilename: "setup/game.pug", appId: this.appId, secret: this.clientSecret, destinationFunc: () => { if (this.adminWebhook.isPresent) { return "clear" } else { return "adminChannel" } }, }) const adminHandler = new DiscordWebhookHandler({ webhook: this.adminWebhook, templateFilename: "setup/admin.pug", appId: this.appId, secret: this.clientSecret, destinationFunc: () => { if (this.gameWebhook.isPresent) { return "clear" } else { return "gameChannel" } }, }) this.server.get("/setup", async (req, res) => { if (!this.gameWebhook.isPresent) { res.redirect(`setup/gameChannel`) } else if (!this.adminWebhook.isPresent) { res.redirect(`setup/adminChannel`) } else { res.redirect(`setup/done`) } }) this.server.get("/setup/start", async (req, res) => { res.redirect(".") }) this.server.get("/game", async (req, res) => { res.redirect("setup") }) this.server.get("/game/started", async (req, res) => { res.redirect("../setup") }) this.server.get("/game/stop", async (req, res) => { res.redirect("../setup") }) this.server.get("/game/start", async (req, res) => { if (!checkAndClearXSRFCookie(req, res)) { return renderError({ baseUrl: getBaseUrl(req), res, code: 400, error: "Token was incorrect or not set.", context: "starting the game", buttonText: "Return to Setup", buttonUrl: "setup" }) } if (!this.gameWebhook.isPresent || !this.adminWebhook.isPresent) { return renderError({ baseUrl: getBaseUrl(req), res, code: 409, error: "You can't start the game while one of the channels is not set!", context: "starting the game", buttonText: "Finish Setup", buttonUrl: "setup" }) } res.code(200) res.type("text/html") res.send(pug.renderFile("static/pages/setup/start.pug", { startedUrl: "game/start" })) setImmediate(async () => { this.server.log.info("Shutting down the setup server and switching to the game server.") try { await this.server.close() } catch (e) { this.server.log.error(e, "Failed to shut down the setup server") } try { await this.gameFactory().initialize() } catch (e) { this.server.log.error(e, "Failed to start up the game server") } this.server.log.info("Successfully switched from the setup server to the game server.") }) }) this.server.get("/setup/gameChannel", async (req, res) => { return await gameHandler.handleRequest(req, res) }) this.server.get("/setup/adminChannel", async (req, res) => { return await adminHandler.handleRequest(req, res) }) this.server.get("/setup/clear", async (req, res) => { if (!checkAndClearXSRFCookie(req, res)) { return renderError({ baseUrl: getBaseUrl(req), res, code: 400, error: "Token was incorrect or not set.", context: "clearing the channel setup", buttonText: "Return to Setup", buttonUrl: "setup" }) } try { await Promise.all([this.gameWebhook, this.adminWebhook] .filter((item) => item.isPresent) .map((item) => item.clearHook())) } catch (e) { return renderError({ baseUrl: getBaseUrl(req), res, code: 500, error: e, context: "clearing and deleting the webhooks", buttonUrl: "setup/clear", buttonText: "Try Again" }) } res.redirect(".") }) this.server.get("/setup/done", async (req, res) => { if (!this.gameWebhook.isPresent) { res.redirect("gameChannel") } else if (!this.adminWebhook.isPresent) { res.redirect("adminChannel") } else { const token = generateXSRFCookie(res) res.code(200) res.type("text/html") res.send(pug.renderFile("static/pages/setup/done.pug", { baseUrl: getBaseUrl(req), gameModeUrl: `game/start?token=${token}`, clearUrl: `setup/clear?token=${token}`, gameSetupUrl: `setup/gameChannel`, adminSetupUrl: `setup/adminChannel`, shutdownUrl: `shutdown?token=${token}` })) } }) this.server.get("/shutdown", async (req, res) => { if (!checkAndClearXSRFCookie(req, res)) { return renderError({ baseUrl: getBaseUrl(req), res, code: 400, error: "Token was incorrect or not set.", context: "shutting the server down", buttonText: "Return to Setup", buttonUrl: "setup" }) } res.code(200) res.type("text/html") res.send(pug.renderFile("static/pages/shutdown.pug")) setImmediate(async () => { this.server.log.info("Shutting down the setup server.") try { await this.server.close() } catch (e) { this.server.log.error(e, "Failed to shut down the setup server") } this.server.log.info("Shut down. Good night...") }) }) } }