mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-12-25 01:21:44 +08:00
Update Configuration to handle arrays/ Add new db client (#2395)
* Update Configuration to handle arrays * Add new db client * Add comment
This commit is contained in:
parent
086f949e38
commit
5beb1bf619
7 changed files with 145 additions and 79 deletions
|
|
@ -3,7 +3,7 @@
|
|||
* To add a new configuration. Simply add it to this object.
|
||||
* When changing this template, please follow the principle of "Secure by default" (https://en.wikipedia.org/wiki/Secure_by_default).
|
||||
*/
|
||||
const BASE_CONFIGURATION = {
|
||||
const BASE_CONFIGURATION = Object.freeze({
|
||||
maintenance: false,
|
||||
quoteReport: {
|
||||
enabled: false,
|
||||
|
|
@ -16,6 +16,6 @@ const BASE_CONFIGURATION = {
|
|||
resultObjectHashCheck: {
|
||||
enabled: false,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
module.exports = BASE_CONFIGURATION;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
const _ = require("lodash");
|
||||
const { mongoDB } = require("../init/mongodb");
|
||||
const db = require("../init/db");
|
||||
const BASE_CONFIGURATION = require("../constants/base-configuration");
|
||||
const Logger = require("../handlers/logger.js");
|
||||
|
||||
const CONFIG_UPDATE_INTERVAL = 10 * 60 * 1000; // 10 Minutes
|
||||
|
||||
let databaseConfigurationUpdated = false;
|
||||
|
||||
function mergeConfigurations(baseConfiguration, liveConfiguration) {
|
||||
if (
|
||||
!_.isPlainObject(baseConfiguration) ||
|
||||
|
|
@ -22,9 +20,21 @@ function mergeConfigurations(baseConfiguration, liveConfiguration) {
|
|||
const baseValue = base[key];
|
||||
const sourceValue = source[key];
|
||||
|
||||
if (_.isPlainObject(baseValue) && _.isPlainObject(sourceValue)) {
|
||||
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) {
|
||||
} else if (
|
||||
typeof baseValue === typeof sourceValue &&
|
||||
!arrayObjectMismatch // typeof {} = "object", typeof [] = "object"
|
||||
) {
|
||||
base[key] = sourceValue;
|
||||
}
|
||||
});
|
||||
|
|
@ -34,8 +44,9 @@ function mergeConfigurations(baseConfiguration, liveConfiguration) {
|
|||
}
|
||||
|
||||
class ConfigurationDAO {
|
||||
static configuration = Object.freeze(BASE_CONFIGURATION);
|
||||
static configuration = BASE_CONFIGURATION;
|
||||
static lastFetchTime = 0;
|
||||
static databaseConfigurationUpdated = false;
|
||||
|
||||
static async getCachedConfiguration(attemptCacheUpdate = false) {
|
||||
if (
|
||||
|
|
@ -51,28 +62,23 @@ class ConfigurationDAO {
|
|||
static async getLiveConfiguration() {
|
||||
this.lastFetchTime = Date.now();
|
||||
|
||||
const configurationCollection = db.collection("configuration");
|
||||
|
||||
try {
|
||||
const liveConfiguration = await mongoDB()
|
||||
.collection("configuration")
|
||||
.findOne();
|
||||
const liveConfiguration = await configurationCollection.findOne();
|
||||
|
||||
if (liveConfiguration) {
|
||||
const baseConfiguration = _.cloneDeep(BASE_CONFIGURATION);
|
||||
mergeConfigurations(baseConfiguration, liveConfiguration);
|
||||
|
||||
this.configuration = baseConfiguration;
|
||||
|
||||
if (!databaseConfigurationUpdated) {
|
||||
await mongoDB()
|
||||
.collection("configuration")
|
||||
.updateOne({}, { $set: Object.assign({}, this.configuration) });
|
||||
databaseConfigurationUpdated = true;
|
||||
}
|
||||
this.pushConfiguration(baseConfiguration);
|
||||
this.configuration = Object.freeze(baseConfiguration);
|
||||
} else {
|
||||
await mongoDB()
|
||||
.collection("configuration")
|
||||
.insertOne(Object.assign({}, BASE_CONFIGURATION)); // Seed the base configuration.
|
||||
await configurationCollection.insertOne(
|
||||
Object.assign({}, BASE_CONFIGURATION)
|
||||
); // Seed the base configuration.
|
||||
}
|
||||
|
||||
Logger.log(
|
||||
"fetch_configuration_success",
|
||||
"Successfully fetched live configuration."
|
||||
|
|
@ -84,10 +90,27 @@ class ConfigurationDAO {
|
|||
);
|
||||
}
|
||||
|
||||
this.configuration = Object.freeze(this.configuration);
|
||||
|
||||
return this.configuration;
|
||||
}
|
||||
|
||||
static async pushConfiguration(configuration) {
|
||||
if (this.databaseConfigurationUpdated) {
|
||||
return;
|
||||
}
|
||||
|
||||
const configurationCollection = db.collection("configuration");
|
||||
|
||||
try {
|
||||
await configurationCollection.replaceOne({}, configuration);
|
||||
|
||||
this.databaseConfigurationUpdated = true;
|
||||
} catch (error) {
|
||||
Logger.log(
|
||||
"push_configuration_failure",
|
||||
`Could not push configuration: ${error.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ConfigurationDAO;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
const { mongoDB } = require("../init/mongodb");
|
||||
const db = require("../init/db");
|
||||
|
||||
async function log(event, message, uid) {
|
||||
const logsCollection = db.collection("logs");
|
||||
|
||||
console.log(new Date(), "\t", event, "\t", uid, "\t", message);
|
||||
await mongoDB().collection("logs").insertOne({
|
||||
await logsCollection.insertOne({
|
||||
timestamp: Date.now(),
|
||||
uid,
|
||||
event,
|
||||
|
|
|
|||
75
backend/init/db.js
Normal file
75
backend/init/db.js
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
const { MongoClient } = require("mongodb");
|
||||
|
||||
class DatabaseClient {
|
||||
static mongoClient = null;
|
||||
static db = null;
|
||||
static collections = {};
|
||||
static connected = false;
|
||||
|
||||
static async connect() {
|
||||
const {
|
||||
DB_USERNAME,
|
||||
DB_PASSWORD,
|
||||
DB_AUTH_MECHANISM,
|
||||
DB_AUTH_SOURCE,
|
||||
DB_URI,
|
||||
DB_NAME,
|
||||
} = process.env;
|
||||
|
||||
const connectionOptions = {
|
||||
useNewUrlParser: true,
|
||||
useUnifiedTopology: true,
|
||||
connectTimeoutMS: 2000,
|
||||
serverSelectionTimeoutMS: 2000,
|
||||
};
|
||||
|
||||
if (DB_USERNAME && DB_PASSWORD) {
|
||||
connectionOptions.auth = {
|
||||
username: DB_USERNAME,
|
||||
password: DB_PASSWORD,
|
||||
};
|
||||
}
|
||||
|
||||
if (DB_AUTH_MECHANISM) {
|
||||
connectionOptions.authMechanism = DB_AUTH_MECHANISM;
|
||||
}
|
||||
|
||||
if (DB_AUTH_SOURCE) {
|
||||
connectionOptions.authSource = DB_AUTH_SOURCE;
|
||||
}
|
||||
|
||||
this.mongoClient = new MongoClient(DB_URI, connectionOptions);
|
||||
|
||||
try {
|
||||
await this.mongoClient.connect();
|
||||
this.db = this.mongoClient.db(DB_NAME);
|
||||
this.connected = true;
|
||||
} catch (error) {
|
||||
console.error(e.message);
|
||||
console.error(
|
||||
"Failed to connect to database. Exiting with exit status code 1."
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static async close() {
|
||||
if (this.connected) {
|
||||
await this.mongoClient.close();
|
||||
}
|
||||
}
|
||||
|
||||
static collection(collectionName) {
|
||||
if (!this.connected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(collectionName in this.collections)) {
|
||||
this.collections[collectionName] = this.db.collection(collectionName);
|
||||
}
|
||||
|
||||
return this.collections[collectionName];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DatabaseClient;
|
||||
|
|
@ -1,42 +1,7 @@
|
|||
const { MongoClient } = require("mongodb");
|
||||
|
||||
let mongoClient;
|
||||
const db = require("./db");
|
||||
|
||||
module.exports = {
|
||||
async connectDB() {
|
||||
let options = {
|
||||
useNewUrlParser: true,
|
||||
useUnifiedTopology: true,
|
||||
connectTimeoutMS: 2000,
|
||||
serverSelectionTimeoutMS: 2000,
|
||||
};
|
||||
|
||||
if (process.env.DB_USERNAME && process.env.DB_PASSWORD) {
|
||||
options.auth = {
|
||||
username: process.env.DB_USERNAME,
|
||||
password: process.env.DB_PASSWORD,
|
||||
};
|
||||
}
|
||||
|
||||
if (process.env.DB_AUTH_MECHANISM) {
|
||||
options.authMechanism = process.env.DB_AUTH_MECHANISM;
|
||||
}
|
||||
|
||||
if (process.env.DB_AUTH_SOURCE) {
|
||||
options.authSource = process.env.DB_AUTH_SOURCE;
|
||||
}
|
||||
|
||||
return MongoClient.connect(process.env.DB_URI, options)
|
||||
.then((client) => {
|
||||
mongoClient = client;
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e.message);
|
||||
console.error("FAILED TO CONNECT TO DATABASE. EXITING...");
|
||||
process.exit(1);
|
||||
});
|
||||
},
|
||||
mongoDB() {
|
||||
return mongoClient.db(process.env.DB_NAME);
|
||||
return db;
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ const cors = require("cors");
|
|||
const admin = require("firebase-admin");
|
||||
const Logger = require("./handlers/logger.js");
|
||||
const serviceAccount = require("./credentials/serviceAccountKey.json");
|
||||
const { connectDB, mongoDB } = require("./init/mongodb");
|
||||
const db = require("./init/db");
|
||||
const jobs = require("./jobs");
|
||||
const addApiRoutes = require("./api/routes");
|
||||
const contextMiddleware = require("./middlewares/context");
|
||||
|
|
@ -15,7 +15,7 @@ const ConfigurationDAO = require("./dao/configuration");
|
|||
|
||||
const PORT = process.env.PORT || 5005;
|
||||
|
||||
// MIDDLEWARE & SETUP
|
||||
// MIDDLEWARE & SETUP
|
||||
const app = express();
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
app.use(express.json());
|
||||
|
|
@ -62,7 +62,7 @@ app.use(function (e, req, res, _next) {
|
|||
`${monkeyError.status} ${monkeyError.message}`,
|
||||
monkeyError.uid
|
||||
);
|
||||
mongoDB().collection("errors").insertOne({
|
||||
db.collection("errors").insertOne({
|
||||
_id: monkeyError.errorID,
|
||||
timestamp: Date.now(),
|
||||
status: monkeyError.status,
|
||||
|
|
@ -80,12 +80,15 @@ app.use(function (e, req, res, _next) {
|
|||
console.log("Starting server...");
|
||||
app.listen(PORT, async () => {
|
||||
console.log(`Listening on port ${PORT}`);
|
||||
|
||||
console.log("Connecting to database...");
|
||||
await connectDB();
|
||||
await db.connect();
|
||||
console.log("Database connected");
|
||||
|
||||
admin.initializeApp({
|
||||
credential: admin.credential.cert(serviceAccount),
|
||||
});
|
||||
|
||||
await ConfigurationDAO.getLiveConfiguration();
|
||||
|
||||
console.log("Starting cron jobs...");
|
||||
|
|
|
|||
|
|
@ -1,19 +1,13 @@
|
|||
const express = require("express");
|
||||
const { config } = require("dotenv");
|
||||
const path = require("path");
|
||||
const MonkeyError = require("./handlers/error");
|
||||
config({ path: path.join(__dirname, ".env") });
|
||||
|
||||
const cors = require("cors");
|
||||
const db = require("./init/db");
|
||||
const admin = require("firebase-admin");
|
||||
|
||||
const serviceAccount = require("./credentials/serviceAccountKey.json");
|
||||
const { connectDB, mongoDB } = require("./init/mongodb");
|
||||
|
||||
const PORT = process.env.PORT || 5005;
|
||||
|
||||
async function main() {
|
||||
await connectDB();
|
||||
await db.connect();
|
||||
await admin.initializeApp({
|
||||
credential: admin.credential.cert(serviceAccount),
|
||||
});
|
||||
|
|
@ -25,8 +19,11 @@ main();
|
|||
|
||||
async function refactor() {
|
||||
console.log("getting all users");
|
||||
let users = await mongoDB().collection("users").find({}).toArray();
|
||||
|
||||
const usersCollection = db.collection("users");
|
||||
let users = await usersCollection.find({}).toArray();
|
||||
console.log(users.length);
|
||||
|
||||
for (let user of users) {
|
||||
let obj = user.personalBests;
|
||||
|
||||
|
|
@ -67,9 +64,10 @@ async function refactor() {
|
|||
});
|
||||
}
|
||||
|
||||
await mongoDB()
|
||||
.collection("users")
|
||||
.updateOne({ _id: user._id }, { $set: { lbPersonalBests: lbPb } });
|
||||
await usersCollection.updateOne(
|
||||
{ _id: user._id },
|
||||
{ $set: { lbPersonalBests: lbPb } }
|
||||
);
|
||||
console.log(`updated ${user.name}`);
|
||||
}
|
||||
console.log("done");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue