From 4daf76e7d976ca00abfcb43cd12aebe9fa0e1092 Mon Sep 17 00:00:00 2001 From: Bruce Berrios <58147810+Bruception@users.noreply.github.com> Date: Fri, 25 Feb 2022 13:20:38 -0500 Subject: [PATCH] Migrate config client to ts (#2588) by Bruception --- backend/constants/base-configuration.ts | 2 +- backend/handlers/misc.js | 7 +++ .../configuration.ts} | 62 +++++++++---------- backend/middlewares/context.ts | 4 +- backend/server.ts | 4 +- 5 files changed, 40 insertions(+), 39 deletions(-) rename backend/{dao/configuration.js => init/configuration.ts} (59%) diff --git a/backend/constants/base-configuration.ts b/backend/constants/base-configuration.ts index d50488ec2..b19bcb512 100644 --- a/backend/constants/base-configuration.ts +++ b/backend/constants/base-configuration.ts @@ -24,4 +24,4 @@ const BASE_CONFIGURATION: MonkeyTypes.Configuration = { }, }; -export default Object.freeze(BASE_CONFIGURATION); +export default BASE_CONFIGURATION; diff --git a/backend/handlers/misc.js b/backend/handlers/misc.js index ae599ad7c..7d8d6925c 100644 --- a/backend/handlers/misc.js +++ b/backend/handlers/misc.js @@ -25,3 +25,10 @@ export function kogasa(cov) { 100 * (1 - Math.tanh(cov + Math.pow(cov, 3) / 3 + Math.pow(cov, 5) / 5)) ); } + +export function identity(value) { + return Object.prototype.toString + .call(value) + .replace(/^\[object\s+([a-z]+)\]$/i, "$1") + .toLowerCase(); +} diff --git a/backend/dao/configuration.js b/backend/init/configuration.ts similarity index 59% rename from backend/dao/configuration.js rename to backend/init/configuration.ts index 7847734eb..3c856c48c 100644 --- a/backend/dao/configuration.js +++ b/backend/init/configuration.ts @@ -1,11 +1,15 @@ +import db from "./db"; import _ from "lodash"; -import db from "../init/db"; -import BASE_CONFIGURATION from "../constants/base-configuration"; import Logger from "../handlers/logger.js"; +import { identity } from "../handlers/misc"; +import BASE_CONFIGURATION from "../constants/base-configuration"; const CONFIG_UPDATE_INTERVAL = 10 * 60 * 1000; // 10 Minutes -function mergeConfigurations(baseConfiguration, liveConfiguration) { +function mergeConfigurations( + baseConfiguration: MonkeyTypes.Configuration, + liveConfiguration: MonkeyTypes.Configuration +): void { if ( !_.isPlainObject(baseConfiguration) || !_.isPlainObject(liveConfiguration) @@ -13,7 +17,7 @@ function mergeConfigurations(baseConfiguration, liveConfiguration) { return; } - function merge(base, source) { + function merge(base: object, source: object): void { const commonKeys = _.intersection(_.keys(base), _.keys(source)); commonKeys.forEach((key) => { @@ -22,19 +26,10 @@ function mergeConfigurations(baseConfiguration, liveConfiguration) { const isBaseValueObject = _.isPlainObject(baseValue); const isSourceValueObject = _.isPlainObject(sourceValue); - const isBaseValueArray = _.isArray(baseValue); - const isSourceValueArray = _.isArray(sourceValue); - - const arrayObjectMismatch = - (isBaseValueObject && isSourceValueArray) || - (isBaseValueArray && isSourceValueObject); if (isBaseValueObject && isSourceValueObject) { merge(baseValue, sourceValue); - } else if ( - typeof baseValue === typeof sourceValue && - !arrayObjectMismatch // typeof {} = "object", typeof [] = "object" - ) { + } else if (identity(baseValue) === identity(sourceValue)) { base[key] = sourceValue; } }); @@ -43,23 +38,25 @@ function mergeConfigurations(baseConfiguration, liveConfiguration) { merge(baseConfiguration, liveConfiguration); } -class ConfigurationDAO { - static configuration = BASE_CONFIGURATION; +class ConfigurationClient { + static configuration: MonkeyTypes.Configuration = BASE_CONFIGURATION; static lastFetchTime = 0; static databaseConfigurationUpdated = false; - static async getCachedConfiguration(attemptCacheUpdate = false) { + static async getCachedConfiguration( + attemptCacheUpdate = false + ): Promise { if ( attemptCacheUpdate && this.lastFetchTime < Date.now() - CONFIG_UPDATE_INTERVAL ) { - Logger.log("stale_configuration", "Cached configuration is stale."); + console.log("Cached configuration is stale."); return await this.getLiveConfiguration(); } return this.configuration; } - static async getLiveConfiguration() { + static async getLiveConfiguration(): Promise { this.lastFetchTime = Date.now(); const configurationCollection = db.collection("configuration"); @@ -69,20 +66,17 @@ class ConfigurationDAO { if (liveConfiguration) { const baseConfiguration = _.cloneDeep(BASE_CONFIGURATION); - mergeConfigurations(baseConfiguration, liveConfiguration); + const liveConfigurationWithoutId = _.omit( + liveConfiguration, + "_id" + ) as MonkeyTypes.Configuration; + mergeConfigurations(baseConfiguration, liveConfigurationWithoutId); this.pushConfiguration(baseConfiguration); - this.configuration = Object.freeze(baseConfiguration); + this.configuration = baseConfiguration; } else { - await configurationCollection.insertOne( - Object.assign({}, BASE_CONFIGURATION) - ); // Seed the base configuration. + await configurationCollection.insertOne(BASE_CONFIGURATION); // Seed the base configuration. } - - Logger.log( - "fetch_configuration_success", - "Successfully fetched live configuration." - ); } catch (error) { Logger.log( "fetch_configuration_failure", @@ -93,15 +87,15 @@ class ConfigurationDAO { return this.configuration; } - static async pushConfiguration(configuration) { + static async pushConfiguration( + configuration: MonkeyTypes.Configuration + ): Promise { if (this.databaseConfigurationUpdated) { return; } - const configurationCollection = db.collection("configuration"); - try { - await configurationCollection.replaceOne({}, configuration); + await db.collection("configuration").replaceOne({}, configuration); this.databaseConfigurationUpdated = true; } catch (error) { @@ -113,4 +107,4 @@ class ConfigurationDAO { } } -export default ConfigurationDAO; +export default ConfigurationClient; diff --git a/backend/middlewares/context.ts b/backend/middlewares/context.ts index 1d54f571e..7ebc48685 100644 --- a/backend/middlewares/context.ts +++ b/backend/middlewares/context.ts @@ -1,4 +1,4 @@ -import ConfigurationDAO from "../dao/configuration"; +import ConfigurationClient from "../init/configuration"; import { Response, NextFunction } from "express"; async function contextMiddleware( @@ -6,7 +6,7 @@ async function contextMiddleware( _res: Response, next: NextFunction ): Promise { - const configuration = await ConfigurationDAO.getCachedConfiguration(true); + const configuration = await ConfigurationClient.getCachedConfiguration(true); req.ctx = { configuration, diff --git a/backend/server.ts b/backend/server.ts index 4c3449915..3f878cd05 100644 --- a/backend/server.ts +++ b/backend/server.ts @@ -4,7 +4,7 @@ import admin, { ServiceAccount } from "firebase-admin"; import serviceAccount from "./credentials/serviceAccountKey.json"; // eslint-disable-line require-path-exists/exists import db from "./init/db"; import jobs from "./jobs"; -import ConfigurationDAO from "./dao/configuration.js"; +import ConfigurationClient from "./init/configuration"; import app from "./app"; import { Server } from "http"; @@ -23,7 +23,7 @@ async function bootServer(port: number): Promise { console.log("Firebase app initialized"); console.log("Fetching live configuration..."); - await ConfigurationDAO.getLiveConfiguration(); + await ConfigurationClient.getLiveConfiguration(); console.log("Live configuration fetched"); console.log("Starting cron jobs...");