diff --git a/server/package.json b/server/package.json index d707641af..1737bca83 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "ontime", - "version": "1.0.0", + "version": "1.0.1", "author": "Carlos Valente", "description": "Time keeping for live events", "repository": "https://github.com/cpvalente/ontime", diff --git a/server/src/app.js b/server/src/app.js index 83348796c..c25de8733 100644 --- a/server/src/app.js +++ b/server/src/app.js @@ -4,53 +4,14 @@ import 'dotenv/config'; // import config import { config } from './config/config.js'; +// import dependencies +import { dirname, join, resolve } from 'path'; // init database -import { Low, JSONFile } from 'lowdb'; - -import path from 'path'; -import { fileURLToPath } from 'url'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const env = process.env.NODE_ENV || 'prod'; - -const file = path.join(__dirname, 'data/', config.database.filename); -const adapter = new JSONFile(file); -export const db = new Low(adapter); - -console.log(`Starting ontime version ${process.env.npm_package_version}`) - +import loadDb from './modules/loadDb.js'; // dependencies import express from 'express'; import http from 'http'; import cors from 'cors'; -import { dbModelv1 as dbModel } from './models/dataModel.js'; -import { parseJson_v1 as parseJson } from './utils/parser.js'; -import { validateFile } from './utils/parserUtils.js'; - -// validate JSON before attempting read -let isValid = validateFile(file); - -if (isValid) { - // Read data from JSON file, this will set db.data content - await db.read(); -} - -// If file.json doesn't exist, db.data will be null -// Set default data -// db.data ||= { events: [] }; NODE v15 - v16 -if (db.data == null || !isValid) { - db.data = dbModel; - await db.write(); -} - -// get data -// there is also the case of the db being corrupt -// try to parse the data, make sure that all fields exist (enforce) -export const data = await parseJson(db.data, true); -db.data = data; -await db.write(); // Import Routes import { router as eventsRouter } from './routes/eventsRouter.js'; @@ -60,6 +21,18 @@ import { router as playbackRouter } from './routes/playbackRouter.js'; // Global Objects import { EventTimer } from './classes/EventTimer.js'; +// Start OSC server +import { initiateOSC, shutdownOSCServer } from './controllers/OscController.js'; +import { fileURLToPath } from 'url'; + +// get environment +const env = process.env.NODE_ENV || 'prod'; +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +export const { db, data } = await loadDb(__dirname); + +console.log(`Starting ontime version ${process.env.npm_package_version}`); // Create express APP const app = express(); @@ -83,21 +56,11 @@ app.use('/ontime', ontimeRouter); app.use('/playback', playbackRouter); // serve react -app.use( - express.static( - path.join(__dirname, env === 'prod' ? '../' : '../../', 'client/build'), - ), -); +app.use(express.static(join(__dirname, env === 'prod' ? '../' : '../../', 'client/build'))); app.get('*', (req, res) => { res.sendFile( - path.resolve( - __dirname, - env === 'prod' ? '../' : '../../', - 'client', - 'build', - 'index.html', - ), + resolve(__dirname, env === 'prod' ? '../' : '../../', 'client', 'build', 'index.html') ); }); @@ -124,11 +87,7 @@ const oscInEnabled = osc?.enabled !== undefined ? osc.enabled : config.osc.input const serverPort = data.settings.serverPort || config.server.port; -// Start OSC server -import { initiateOSC, shutdownOSCServer } from './controllers/OscController.js'; - export const startOSCServer = async (overrideConfig = null) => { - if (!oscInEnabled) { global.timer.info('RX', 'OSC Input Disabled'); return; diff --git a/server/src/modules/loadDb.js b/server/src/modules/loadDb.js new file mode 100644 index 000000000..77c688219 --- /dev/null +++ b/server/src/modules/loadDb.js @@ -0,0 +1,67 @@ +import { JSONFile, Low } from 'lowdb'; +import { join } from 'path'; +import { copyFileSync, existsSync } from 'fs'; +import { ensureDirectory, getAppDataPath } from '../utils/fileManagement.js'; +import { config } from '../config/config.js'; +import { validateFile } from '../utils/parserUtils.js'; +import { dbModelv1 as dbModel } from '../models/dataModel.js'; +import { parseJson_v1 as parseJson } from '../utils/parser.js'; + +/** + * @description ensures directories exist and picks available db path + * @param runningDirectory + * @return {string} + */ +const checkDirectories = (runningDirectory) => { + const appPath = getAppDataPath(); + const dbDirectory = join(appPath, 'data'); + const dbInDisk = join(dbDirectory, config.database.filename); + const startupDb = join(runningDirectory, 'data', config.database.filename); + ensureDirectory(dbDirectory); + + // if dbInDisk doesnt exist we want to use startup db + if (!existsSync(dbInDisk)) { + try { + copyFileSync(startupDb, dbInDisk); + } catch (error) { + console.log(error); + } + } + + return dbInDisk; +}; + +/** + * @description parses a json file to the adapter + * @param fileToRead + * @param adapterToUse + * @return {Promise} + */ +const parseDb = async (fileToRead, adapterToUse) => { + if (validateFile(fileToRead)) { + await adapterToUse.read(); + } else { + adapterToUse.data = dbModel; + } + + return parseJson(adapterToUse.data, true); +}; + +/** + * @description Modules loads ontime db + * @param runningDirectory + * @return {Promise<{data: (number|*), db: Low}>} + */ +export default async function loadDb(runningDirectory) { + const dbInDisk = checkDirectories(runningDirectory); + + const adapter = new JSONFile(dbInDisk); + const db = new Low(adapter); + + const data = await parseDb(dbInDisk, db); + + db.data = data; + await db.write(); + + return { db, data }; +} diff --git a/server/src/package.json b/server/src/package.json index dc4f800dd..4f29f67e7 100644 --- a/server/src/package.json +++ b/server/src/package.json @@ -1,7 +1,7 @@ { "name": "ontime-server", "type": "module", - "version": "1.0.0", + "version": "1.1.0", "dependencies": { "body-parser": "^1.20.0", "dotenv": "^16.0.0", diff --git a/server/src/utils/fileManagement.js b/server/src/utils/fileManagement.js new file mode 100644 index 000000000..ea6b8104f --- /dev/null +++ b/server/src/utils/fileManagement.js @@ -0,0 +1,46 @@ +import { existsSync, mkdirSync } from 'fs'; +import path from 'path'; + +/** + * @description Creates a directory if it doesnt exist + * @param directory + */ +export function ensureDirectory(directory) { + if (!existsSync(directory)) { + try { + mkdirSync(directory, { recursive: true }); + } catch (err) { + throw new Error(`Could not create directory: ${err}`); + } + } +} + +/** + * @description Whether a file exists + * @param directory + * @return {boolean} + */ +export function doesFileExist(directory) { + return existsSync(directory); +} + +/** + * @description Returns public path depending on OS + * @return {string|*} + */ +export function getAppDataPath() { + switch (process.platform) { + case 'darwin': { + return path.join(process.env.HOME, 'Library', 'Application Support', 'Ontime'); + } + case 'win32': { + return path.join(process.env.APPDATA, 'Ontime'); + } + case 'linux': { + return path.join(process.env.HOME, '.Ontime'); + } + default: { + throw new Error('Could not resolve public folder for platform'); + } + } +} diff --git a/server/src/utils/upload.js b/server/src/utils/upload.js index 4c1e23c65..25119cdea 100644 --- a/server/src/utils/upload.js +++ b/server/src/utils/upload.js @@ -1,28 +1,7 @@ import multer from 'multer'; -import { existsSync, mkdirSync } from 'fs'; import * as path from 'path'; import { EXCEL_MIME, JSON_MIME } from './parser.js'; - -/** - * @description Returns public path depending on os - * @return {string|*} - */ -function getAppDataPath() { - switch (process.platform) { - case 'darwin': { - return path.join(process.env.HOME, 'Library', 'Application Support', 'Ontime'); - } - case 'win32': { - return path.join(process.env.APPDATA, 'Ontime'); - } - case 'linux': { - return path.join(process.env.HOME, '.Ontime'); - } - default: { - return ''; - } - } -} +import { ensureDirectory, getAppDataPath } from './fileManagement.js'; // Define multer storage object const storage = multer.diskStorage({ @@ -36,13 +15,7 @@ const storage = multer.diskStorage({ const newDestination = path.join(appDataPath, 'uploads'); // Create directory if not exist - if (!existsSync(newDestination)) { - try { - mkdirSync(newDestination); - } catch (err) { - throw new Error('Could not create directory'); - } - } + ensureDirectory(newDestination); cb(null, newDestination); }, filename: function (req, file, cb) {