From ddecabba54eb24ab4ac07a67621f805d3ad9e2ce Mon Sep 17 00:00:00 2001 From: Kevin J Hoerr Date: Sun, 26 Apr 2020 21:53:26 -0400 Subject: These changes moved a lot of the startup async to run in a streamlined async init function. This brings more logic "to light", so it should probably have unit tests added to check the edge cases. As a bonus, no async runs as a result of route initialization. Speaking of routes, it might be nice to trim down the route calls themselves with async functions, if possible. The upload routes in particular use a lot of async. Just a note for the future. --- src/util/config.test.ts | 10 +++---- src/util/config.ts | 75 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 6 deletions(-) (limited to 'src/util') diff --git a/src/util/config.test.ts b/src/util/config.test.ts index 19d7564..418edb7 100644 --- a/src/util/config.test.ts +++ b/src/util/config.test.ts @@ -1,11 +1,11 @@ +const exit = jest + .spyOn(process, "exit") + .mockImplementation(() => undefined as never); + import { configOrError, handleShutdown } from "./config"; import { MongoClient } from "mongodb"; import { Server } from "http"; -const exit = jest.spyOn(process, "exit").mockImplementation(() => { - throw Error(""); -}); - const CommonMocks = { connect: jest.fn(), isConnected: jest.fn(), @@ -111,7 +111,7 @@ describe("handleShutdown", () => { } // Assert - expect(exit).toHaveBeenCalledWith(1); + expect(exit).toHaveBeenCalledWith(0); }); it("should exit with error with Mongo error", async () => { diff --git a/src/util/config.ts b/src/util/config.ts index 1eddda3..b3a1ead 100644 --- a/src/util/config.ts +++ b/src/util/config.ts @@ -1,8 +1,11 @@ import winston from "winston"; -import { MongoClient } from "mongodb"; +import { MongoClient, MongoError } from "mongodb"; import { Server } from "http"; +import path from "path"; +import fs from "fs"; import loggerConfig from "./logger"; +import processTemplate, { Template } from "../templates"; const logger = winston.createLogger(loggerConfig("ROOT")); @@ -16,6 +19,76 @@ export const configOrError = (varName: string): string => { } }; +export const persistTemplate = async (input: Template): Promise => { + try { + const template = await processTemplate(input); + logger.debug("Generated '%s' from template file", template.outputFile); + } catch (err1) { + try { + await fs.promises.access(input.outputFile, fs.constants.R_OK); + } catch (err2) { + logger.error( + "Error while generating '%s' from template file: %s", + input.outputFile, + err1 + ); + logger.error("Cannot proceed due to error: %s", err2); + + process.exit(1); + } + // if the output file exists, then we are fine with continuing without + logger.warning( + "Could not generate '%s' from template file, but file already exists: %s", + input.outputFile, + err1 + ); + } +}; + +const MONGO_URI = configOrError("MONGO_URI"); +const TARGET_URL = process.env.TARGET_URL ?? "http://localhost:3000"; +const HOST_DIR = configOrError("HOST_DIR"); + +export const handleStartup = async (): Promise => { + await fs.promises.access(HOST_DIR, fs.constants.R_OK | fs.constants.W_OK); + if (!path.isAbsolute(HOST_DIR)) { + logger.error("HOST_DIR must be an absolute path"); + process.exit(1); + } + + const mongo = await new MongoClient(MONGO_URI, { useUnifiedTopology: true }) + .connect() + .catch((err: MongoError) => { + logger.error(err.message ?? "Unable to connect to database"); + process.exit(1); + }); + + await persistTemplate({ + inputFile: path.join( + __dirname, + "..", + "public", + "templates", + "bash.template" + ), + outputFile: path.join(HOST_DIR, "bash"), + context: { TARGET_URL } + } as Template); + await persistTemplate({ + inputFile: path.join( + __dirname, + "..", + "public", + "templates", + "index.html.template" + ), + outputFile: path.join(HOST_DIR, "index.html"), + context: { TARGET_URL } + } as Template); + + return mongo; +}; + export const handleShutdown = (mongo: MongoClient, server: Server) => ( signal: NodeJS.Signals ): Promise => { -- cgit