mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-10 09:53:48 +00:00
refactor: simplify setup of asset paths
This commit is contained in:
committed by
Carlos Valente
parent
e46948772e
commit
5950551da2
@@ -3,8 +3,8 @@ import { getErrorMessage, obfuscate } from 'ontime-utils';
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
|
||||
import { isDocker } from '../../externals.js';
|
||||
import { failEmptyObjects } from '../../utils/routerUtils.js';
|
||||
import { isDocker } from '../../setup/index.js';
|
||||
import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
|
||||
import { extractPin } from './settings.utils.js';
|
||||
|
||||
+9
-17
@@ -9,15 +9,8 @@ import serverTiming from 'server-timing';
|
||||
|
||||
// import utils
|
||||
import { resolve } from 'path';
|
||||
import {
|
||||
srcDirectory,
|
||||
environment,
|
||||
isProduction,
|
||||
resolveExternalsDirectory,
|
||||
resolveStylesDirectory,
|
||||
resolvedPath,
|
||||
resolvePublicDirectoy,
|
||||
} from './setup/index.js';
|
||||
import { publicDir, srcDir } from './setup/index.js';
|
||||
import { environment, isProduction } from './externals.js';
|
||||
import { ONTIME_VERSION } from './ONTIME_VERSION.js';
|
||||
import { consoleSuccess, consoleHighlight, consoleError } from './utils/console.js';
|
||||
|
||||
@@ -56,8 +49,8 @@ consoleHighlight(`Starting Ontime version ${ONTIME_VERSION}`);
|
||||
const canLog = isProduction;
|
||||
if (!canLog) {
|
||||
console.log(`Ontime running in ${environment} environment`);
|
||||
console.log(`Ontime source directory at ${srcDirectory} `);
|
||||
console.log(`Ontime public directory at ${resolvePublicDirectoy} `);
|
||||
console.log(`Ontime source directory at ${srcDir.root} `);
|
||||
console.log(`Ontime public directory at ${publicDir.root} `);
|
||||
}
|
||||
|
||||
// Create express APP
|
||||
@@ -82,17 +75,16 @@ app.use(express.json({ limit: '1mb' }));
|
||||
app.use('/data', appRouter); // router for application data
|
||||
app.use('/api', integrationRouter); // router for integrations
|
||||
|
||||
// serve static - css
|
||||
app.use('/external/styles', express.static(resolveStylesDirectory));
|
||||
app.use('/external/', express.static(resolveExternalsDirectory));
|
||||
// serve static external files
|
||||
app.use('/external/', express.static(publicDir.externalDir));
|
||||
// if the user reaches to the root, we show a 404
|
||||
app.use('/external', (req, res) => {
|
||||
res.status(404).send(`${req.originalUrl} not found`);
|
||||
});
|
||||
|
||||
// serve static - react, in dev/test mode we fetch the React app from module
|
||||
const reactAppPath = resolvedPath();
|
||||
app.use(
|
||||
expressStaticGzip(reactAppPath, {
|
||||
expressStaticGzip(srcDir.clientDir, {
|
||||
enableBrotli: true,
|
||||
orderPreference: ['br'],
|
||||
// when we build the client all the react subfiles will get a hashed name we can the immutable tag
|
||||
@@ -103,7 +95,7 @@ app.use(
|
||||
);
|
||||
|
||||
app.get('*', (_req, res) => {
|
||||
res.sendFile(resolve(reactAppPath, 'index.html'));
|
||||
res.sendFile(resolve(srcDir.clientDir, 'index.html'));
|
||||
});
|
||||
|
||||
// Implement catch all
|
||||
|
||||
@@ -2,9 +2,9 @@ import { Log, LogLevel } from 'ontime-types';
|
||||
import { generateId, millisToString } from 'ontime-utils';
|
||||
|
||||
import { clock } from '../services/Clock.js';
|
||||
import { isProduction } from '../setup/index.js';
|
||||
import { socket } from '../adapters/WebsocketAdapter.js';
|
||||
import { consoleSubdued, consoleError } from '../utils/console.js';
|
||||
import { isProduction } from '../externals.js';
|
||||
|
||||
class Logger {
|
||||
private queue: Log[];
|
||||
|
||||
@@ -13,11 +13,11 @@ import {
|
||||
import type { Low } from 'lowdb';
|
||||
import { JSONFilePreset } from 'lowdb/node';
|
||||
|
||||
import { isTest } from '../../setup/index.js';
|
||||
import { isPath } from '../../utils/fileManagement.js';
|
||||
import { shouldCrashDev } from '../../utils/development.js';
|
||||
import { isTest } from '../../externals.js';
|
||||
|
||||
import { safeMerge } from './DataProvider.utils.js';
|
||||
import { shouldCrashDev } from '../../utils/development.js';
|
||||
|
||||
type ReadonlyPromise<T> = Promise<Readonly<T>>;
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* This file contains a list of constants that may need to be resolved at runtime
|
||||
*/
|
||||
|
||||
// =================================================
|
||||
// resolve running environment
|
||||
const env = process.env.NODE_ENV || 'production';
|
||||
|
||||
export const isTest = Boolean(process.env.IS_TEST);
|
||||
export const environment = isTest ? 'test' : env;
|
||||
export const isDocker = env === 'docker';
|
||||
export const isProduction = isDocker || (env === 'production' && !isTest);
|
||||
@@ -1,9 +1,10 @@
|
||||
import { MaybeNumber, MaybeString, Playback } from 'ontime-types';
|
||||
|
||||
import { JSONFile } from 'lowdb/node';
|
||||
import { resolveRestoreFile } from '../setup/index.js';
|
||||
import { deepEqual } from 'fast-equals';
|
||||
|
||||
import { publicFiles } from '../setup/index.js';
|
||||
|
||||
export type RestorePoint = {
|
||||
playback: Playback;
|
||||
selectedEventId: MaybeString;
|
||||
@@ -147,4 +148,4 @@ export class RestoreService {
|
||||
}
|
||||
}
|
||||
|
||||
export const restoreService = new RestoreService(resolveRestoreFile);
|
||||
export const restoreService = new RestoreService(publicFiles.restoreFile);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Low } from 'lowdb';
|
||||
import { JSONFile } from 'lowdb/node';
|
||||
|
||||
import { appStatePath, isTest } from '../../setup/index.js';
|
||||
import { publicFiles } from '../../setup/index.js';
|
||||
import { isTest } from '../../externals.js';
|
||||
import { isPath } from '../../utils/fileManagement.js';
|
||||
import { shouldCrashDev } from '../../utils/development.js';
|
||||
|
||||
@@ -9,7 +10,7 @@ interface AppState {
|
||||
lastLoadedProject?: string;
|
||||
}
|
||||
|
||||
const adapter = new JSONFile<AppState>(appStatePath);
|
||||
const adapter = new JSONFile<AppState>(publicFiles.appState);
|
||||
const config = new Low<AppState>(adapter, {});
|
||||
|
||||
export async function isLastLoadedProject(projectName: string): Promise<boolean> {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { copyFile, rename } from 'fs/promises';
|
||||
|
||||
import { logger } from '../../classes/Logger.js';
|
||||
import { getNetworkInterfaces } from '../../utils/networkInterfaces.js';
|
||||
import { resolveCorruptDirectory, resolveProjectsDirectory, resolveStylesPath } from '../../setup/index.js';
|
||||
import { publicDir, publicFiles } from '../../setup/index.js';
|
||||
import {
|
||||
appendToName,
|
||||
ensureDirectory,
|
||||
@@ -47,8 +47,8 @@ init();
|
||||
* Ensure services has its dependencies initialized
|
||||
*/
|
||||
function init() {
|
||||
ensureDirectory(resolveProjectsDirectory);
|
||||
ensureDirectory(resolveCorruptDirectory);
|
||||
ensureDirectory(publicDir.projectsDir);
|
||||
ensureDirectory(publicDir.corruptDir);
|
||||
}
|
||||
|
||||
export async function getCurrentProject() {
|
||||
@@ -63,7 +63,7 @@ export async function getCurrentProject() {
|
||||
* to be composed in the loading functions
|
||||
*/
|
||||
async function loadDemoProject(): Promise<string> {
|
||||
const pathToNewFile = generateUniqueFileName(resolveProjectsDirectory, config.demoProject);
|
||||
const pathToNewFile = generateUniqueFileName(publicDir.projectsDir, config.demoProject);
|
||||
await initPersistence(getPathToProject(pathToNewFile), demoDb);
|
||||
const newName = getFileNameFromPath(pathToNewFile);
|
||||
await setLastLoadedProject(newName);
|
||||
@@ -75,7 +75,7 @@ async function loadDemoProject(): Promise<string> {
|
||||
* to be composed in the loading functions
|
||||
*/
|
||||
async function loadNewProject(): Promise<string> {
|
||||
const pathToNewFile = generateUniqueFileName(resolveProjectsDirectory, config.newProject);
|
||||
const pathToNewFile = generateUniqueFileName(publicDir.projectsDir, config.newProject);
|
||||
await initPersistence(getPathToProject(pathToNewFile), dbModel);
|
||||
const newName = getFileNameFromPath(pathToNewFile);
|
||||
await setLastLoadedProject(newName);
|
||||
@@ -273,7 +273,7 @@ export async function createProject(filename: string, projectData: ProjectData)
|
||||
},
|
||||
};
|
||||
|
||||
const uniqueFileName = generateUniqueFileName(resolveProjectsDirectory, filename);
|
||||
const uniqueFileName = generateUniqueFileName(publicDir.projectsDir, filename);
|
||||
const newFile = getPathToProject(uniqueFileName);
|
||||
|
||||
// change LowDB to point to new file
|
||||
@@ -316,14 +316,13 @@ export async function getInfo(): Promise<GetInfo> {
|
||||
// get nif and inject localhost
|
||||
const ni = getNetworkInterfaces();
|
||||
ni.unshift({ name: 'localhost', address: '127.0.0.1' });
|
||||
const cssOverride = resolveStylesPath;
|
||||
|
||||
return {
|
||||
networkInterfaces: ni,
|
||||
version,
|
||||
serverPort,
|
||||
osc,
|
||||
cssOverride,
|
||||
cssOverride: publicFiles.cssOverride,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { existsSync } from 'fs';
|
||||
import { copyFile, readFile, rename, stat } from 'fs/promises';
|
||||
import { extname, join } from 'path';
|
||||
|
||||
import { resolveCorruptDirectory, resolveProjectsDirectory } from '../../setup/index.js';
|
||||
import { publicDir } from '../../setup/index.js';
|
||||
import { getFilesFromFolder, removeFileExtension } from '../../utils/fileManagement.js';
|
||||
|
||||
/**
|
||||
@@ -13,7 +13,7 @@ import { getFilesFromFolder, removeFileExtension } from '../../utils/fileManagem
|
||||
* @param name
|
||||
*/
|
||||
export async function handleUploaded(filePath: string, name: string) {
|
||||
const newFilePath = join(resolveProjectsDirectory, name);
|
||||
const newFilePath = join(publicDir.projectsDir, name);
|
||||
await rename(filePath, newFilePath);
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ export async function handleUploaded(filePath: string, name: string) {
|
||||
* @throws {Error} Throws an error if there is an issue in reading the directory or fetching file statistics.
|
||||
*/
|
||||
export async function getProjectFiles(): Promise<ProjectFile[]> {
|
||||
const allFiles = await getFilesFromFolder(resolveProjectsDirectory);
|
||||
const allFiles = await getFilesFromFolder(publicDir.projectsDir);
|
||||
const filteredFiles = filterProjectFiles(allFiles);
|
||||
|
||||
const projectFiles: ProjectFile[] = [];
|
||||
for (const file of filteredFiles) {
|
||||
const filePath = join(resolveProjectsDirectory, file);
|
||||
const filePath = join(publicDir.projectsDir, file);
|
||||
const stats = await stat(filePath);
|
||||
|
||||
projectFiles.push({
|
||||
@@ -62,14 +62,14 @@ export function doesProjectExist(name: string): MaybeString {
|
||||
* Returns the absolute path to a project file
|
||||
*/
|
||||
export function getPathToProject(name: string): string {
|
||||
return join(resolveProjectsDirectory, name);
|
||||
return join(publicDir.projectsDir, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a copy of a given project to the corrupted directory
|
||||
*/
|
||||
export async function copyCorruptFile(filePath: string, name: string): Promise<void> {
|
||||
const newPath = join(resolveCorruptDirectory, name);
|
||||
const newPath = join(publicDir.corruptDir, name);
|
||||
return copyFile(filePath, newPath);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ export async function copyCorruptFile(filePath: string, name: string): Promise<v
|
||||
* Moves a file permanently to the corrupted directory
|
||||
*/
|
||||
export async function moveCorruptFile(filePath: string, name: string): Promise<void> {
|
||||
const newPath = join(resolveCorruptDirectory, name);
|
||||
const newPath = join(publicDir.corruptDir, name);
|
||||
return rename(filePath, newPath);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { sheets, sheets_v4 } from '@googleapis/sheets';
|
||||
import { Credentials, OAuth2Client } from 'google-auth-library';
|
||||
import got from 'got';
|
||||
|
||||
import { resolveSheetsDirectory } from '../../setup/index.js';
|
||||
import { publicDir } from '../../setup/index.js';
|
||||
import { ensureDirectory } from '../../utils/fileManagement.js';
|
||||
import { cellRequestFromEvent, type ClientSecret, getA1Notation, validateClientSecret } from './sheetUtils.js';
|
||||
import { parseExcel } from '../../utils/parser.js';
|
||||
@@ -57,7 +57,7 @@ function reset() {
|
||||
*/
|
||||
export function init() {
|
||||
reset();
|
||||
ensureDirectory(resolveSheetsDirectory);
|
||||
ensureDirectory(publicDir.sheetsDir);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
/**
|
||||
* This file handles resolving paths for the server resources
|
||||
* There are two main directories
|
||||
* - 1. the installation directory, exposed by __dirname
|
||||
* - 2. the public directory, exposed by getAppDataPath()
|
||||
*/
|
||||
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
|
||||
import { config } from './config.js';
|
||||
import { ensureDirectory } from '../utils/fileManagement.js';
|
||||
|
||||
// =================================================
|
||||
// resolve public path
|
||||
import { isProduction } from '../externals.js';
|
||||
|
||||
/**
|
||||
* @description Returns public path depending on OS
|
||||
* Returns public path depending on OS
|
||||
* This is the correct path for the app running in production mode
|
||||
*/
|
||||
export function getAppDataPath(): string {
|
||||
// handle docker
|
||||
/**
|
||||
* If we are running in docker, the ONTIME_DATA environment variable
|
||||
* allows moving the public directory to a user defined location
|
||||
*/
|
||||
if (process.env.ONTIME_DATA) {
|
||||
return join(process.env.ONTIME_DATA);
|
||||
}
|
||||
@@ -33,86 +41,86 @@ export function getAppDataPath(): string {
|
||||
}
|
||||
}
|
||||
|
||||
// =================================================
|
||||
// resolve running environment
|
||||
const env = process.env.NODE_ENV || 'production';
|
||||
/**
|
||||
* 1. Paths relative to the installation (or source in development)
|
||||
* ------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export const isTest = Boolean(process.env.IS_TEST);
|
||||
export const environment = isTest ? 'test' : env;
|
||||
export const isDocker = env === 'docker';
|
||||
export const isProduction = isDocker || (env === 'production' && !isTest);
|
||||
|
||||
// =================================================
|
||||
// Resolve directory paths
|
||||
|
||||
// resolve file URL in both CJS and ESM (build and dev)
|
||||
/** resolve file URL in both CJS and ESM (build and dev) */
|
||||
if (import.meta.url) {
|
||||
globalThis.__dirname = fileURLToPath(import.meta.url);
|
||||
}
|
||||
|
||||
// path to server src folder
|
||||
const currentDir = dirname(__dirname);
|
||||
// locally we are in src/setup, in the production build, this is a single file at src
|
||||
export const srcDirectory = isProduction ? currentDir : join(currentDir, '../');
|
||||
|
||||
// TODO: simplify logic
|
||||
// resolve path to client
|
||||
const productionPath = join(srcDirectory, 'client/');
|
||||
const devPath = join(srcDirectory, '../../client/build/');
|
||||
export const resolvedPath = (): string => {
|
||||
if (isTest) {
|
||||
return devPath;
|
||||
}
|
||||
if (isProduction) {
|
||||
return productionPath;
|
||||
}
|
||||
return devPath;
|
||||
/**
|
||||
* path to server src folder
|
||||
* when running in dev, this file is located in src/setup, so we go one level up
|
||||
* */
|
||||
const srcDirectory = isProduction ? currentDir : join(currentDir, '../');
|
||||
|
||||
export const srcDir = {
|
||||
root: srcDirectory,
|
||||
/** Path to the react app */
|
||||
clientDir: isProduction ? join(srcDirectory, 'client/') : join(srcDirectory, '../../client/build/'),
|
||||
/** Path to the demo app */
|
||||
demoDir: join(srcDirectory, '/external/demo/'),
|
||||
} as const;
|
||||
|
||||
export const srcFiles = {
|
||||
/** Path to bundled CSS */
|
||||
cssOverride: join(srcDir.root, '/external/styles/', config.styles.filename),
|
||||
};
|
||||
|
||||
// resolve public directory
|
||||
export const resolvePublicDirectoy = getAppDataPath();
|
||||
ensureDirectory(resolvePublicDirectoy);
|
||||
/**
|
||||
* 2. Paths relative to the user public directory
|
||||
* ------------------------------------------------
|
||||
*/
|
||||
|
||||
export const externalsStartDirectory = isProduction ? resolvePublicDirectoy : join(srcDirectory, 'external');
|
||||
// TODO: we only need one when they are all in the same folder
|
||||
export const resolveExternalsDirectory = join(isProduction ? resolvePublicDirectoy : srcDirectory, 'external');
|
||||
/** Resolve root to public directory */
|
||||
const resolvePublicDirectory = getAppDataPath();
|
||||
// Ensure directory tree is created
|
||||
ensureDirectory(resolvePublicDirectory);
|
||||
|
||||
// project files
|
||||
export const appStatePath = join(resolvePublicDirectoy, config.appState);
|
||||
export const uploadsFolderPath = join(resolvePublicDirectoy, config.uploads);
|
||||
/**
|
||||
* Path to external
|
||||
* This is unique in the way that we use the src directory in development
|
||||
* For simplicity we still bundle this in the public directory object
|
||||
*/
|
||||
const externalsStartDirectory = isProduction ? resolvePublicDirectory : join(srcDirectory, 'external');
|
||||
|
||||
// path to public styles
|
||||
export const resolveStylesDirectory = join(externalsStartDirectory, config.styles.directory);
|
||||
export const resolveStylesPath = join(resolveStylesDirectory, config.styles.filename);
|
||||
export const publicDir = {
|
||||
root: resolvePublicDirectory,
|
||||
/** path to sheets folder */
|
||||
sheetsDir: join(resolvePublicDirectory, config.sheets.directory),
|
||||
/** path to crash reports folder */
|
||||
crashDir: join(resolvePublicDirectory, config.crash),
|
||||
/** path to projects folder */
|
||||
projectsDir: join(resolvePublicDirectory, config.projects),
|
||||
/** path to corrupt folder */
|
||||
corruptDir: join(resolvePublicDirectory, config.corrupt),
|
||||
/** path to uploads folder */
|
||||
uploadsDir: join(resolvePublicDirectory, config.uploads),
|
||||
/** path to external folder */
|
||||
externalDir: externalsStartDirectory,
|
||||
/** path to demo project folder */
|
||||
demoDir: join(
|
||||
externalsStartDirectory,
|
||||
isProduction ? '/external/' : '', // move to external folder in production
|
||||
config.demo.directory,
|
||||
),
|
||||
/** path to external styles override */
|
||||
stylesDir: join(externalsStartDirectory, config.styles.directory),
|
||||
} as const;
|
||||
|
||||
export const pathToStartStyles = join(srcDirectory, '/external/styles/', config.styles.filename);
|
||||
|
||||
// path to public demo
|
||||
export const resolveDemoDirectory = join(
|
||||
externalsStartDirectory,
|
||||
isProduction ? '/external/' : '', // move to external folder in production
|
||||
config.demo.directory,
|
||||
);
|
||||
export const resolveDemoPath = config.demo.filename.map((file) => {
|
||||
return join(resolveDemoDirectory, file);
|
||||
});
|
||||
|
||||
// path to demo project
|
||||
export const pathToStartDemo = config.demo.filename.map((file) => {
|
||||
return join(srcDirectory, '/external/demo/', file);
|
||||
});
|
||||
|
||||
// path to restore file
|
||||
export const resolveRestoreFile = join(resolvePublicDirectoy, config.restoreFile);
|
||||
|
||||
// path to sheets folder
|
||||
export const resolveSheetsDirectory = join(resolvePublicDirectoy, config.sheets.directory);
|
||||
|
||||
// path to crash reports
|
||||
export const resolveCrashReportDirectory = join(resolvePublicDirectoy, config.crash);
|
||||
|
||||
// path to projects
|
||||
export const resolveProjectsDirectory = join(resolvePublicDirectoy, config.projects);
|
||||
|
||||
// path to corrupt files
|
||||
export const resolveCorruptDirectory = join(resolvePublicDirectoy, config.corrupt);
|
||||
/**
|
||||
* Resolve path to specific files
|
||||
*/
|
||||
export const publicFiles = {
|
||||
/** path to app state file */
|
||||
appState: join(publicDir.root, config.appState),
|
||||
/** path to restore file */
|
||||
restoreFile: join(publicDir.root, config.restoreFile),
|
||||
/** path to CSS override file */
|
||||
cssOverride: join(publicDir.stylesDir, config.styles.filename),
|
||||
};
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
import { copyFile } from 'fs/promises';
|
||||
import { pathToStartDemo, resolveDemoDirectory, resolveDemoPath } from './index.js';
|
||||
import { ensureDirectory } from '../utils/fileManagement.js';
|
||||
import { copyDirectory, ensureDirectory } from '../utils/fileManagement.js';
|
||||
|
||||
import { publicDir, srcDir } from './index.js';
|
||||
|
||||
/**
|
||||
* @description ensures directories exist and populates demo folder
|
||||
*/
|
||||
export const populateDemo = () => {
|
||||
ensureDirectory(resolveDemoDirectory);
|
||||
ensureDirectory(publicDir.demoDir);
|
||||
|
||||
// even if demo exist we want to use startup demo
|
||||
try {
|
||||
Promise.all(
|
||||
resolveDemoPath.map((to, index) => {
|
||||
const from = pathToStartDemo[index];
|
||||
return copyFile(from, to);
|
||||
}),
|
||||
);
|
||||
copyDirectory(srcDir.demoDir, publicDir.demoDir);
|
||||
} catch (_) {
|
||||
/* we do not handle this */
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import { copyFileSync, existsSync } from 'fs';
|
||||
import { pathToStartStyles, resolveStylesDirectory, resolveStylesPath } from './index.js';
|
||||
|
||||
import { ensureDirectory } from '../utils/fileManagement.js';
|
||||
|
||||
import { publicDir, publicFiles, srcFiles } from './index.js';
|
||||
|
||||
/**
|
||||
* @description ensures directories exist and populates stylesheet
|
||||
* ensures directories exist and populates stylesheet
|
||||
*/
|
||||
export const populateStyles = () => {
|
||||
ensureDirectory(resolveStylesDirectory);
|
||||
ensureDirectory(publicDir.stylesDir);
|
||||
// if styles doesn't exist we want to use startup stylesheet
|
||||
if (!existsSync(resolveStylesPath)) {
|
||||
if (!existsSync(publicFiles.cssOverride)) {
|
||||
try {
|
||||
copyFileSync(pathToStartStyles, resolveStylesPath);
|
||||
// copy the startup stylesheet to the public directory
|
||||
copyFileSync(srcFiles.cssOverride, publicFiles.cssOverride);
|
||||
} catch (_) {
|
||||
/* we do not handle this */
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isProduction } from '../setup/index.js';
|
||||
import { isProduction } from '../externals.js';
|
||||
import { consoleError } from '../utils/console.js';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { existsSync, mkdirSync } from 'fs';
|
||||
import { readdir } from 'fs/promises';
|
||||
import { readdir, copyFile } from 'fs/promises';
|
||||
import { basename, extname, join, parse } from 'path';
|
||||
|
||||
/**
|
||||
@@ -80,8 +80,28 @@ export function getFileNameFromPath(filePath: string): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility naivly checks for paths on whether it includes directories
|
||||
* Utility naively checks for paths on whether it includes directories
|
||||
*/
|
||||
export function isPath(filePath: string): boolean {
|
||||
return filePath !== basename(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively copies a directory and its contents.
|
||||
* @param {string} src - The source directory.
|
||||
* @param {string} dest - The destination directory.
|
||||
*/
|
||||
export async function copyDirectory(src: string, dest: string) {
|
||||
const entries = await readdir(src, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
const srcPath = join(src, entry.name);
|
||||
const destPath = join(dest, entry.name);
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
await copyDirectory(srcPath, destPath);
|
||||
} else {
|
||||
await copyFile(srcPath, destPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { join } from 'path';
|
||||
import { ONTIME_VERSION } from '../ONTIME_VERSION.js';
|
||||
import { get } from '../services/rundown-service/rundownCache.js';
|
||||
import { getState } from '../stores/runtimeState.js';
|
||||
import { resolveCrashReportDirectory } from '../setup/index.js';
|
||||
import { publicDir } from '../setup/index.js';
|
||||
|
||||
import { ensureDirectory } from './fileManagement.js';
|
||||
/**
|
||||
@@ -13,8 +13,8 @@ import { ensureDirectory } from './fileManagement.js';
|
||||
* @param content
|
||||
*/
|
||||
function writeToFile(fileName: string, content: object) {
|
||||
const path = join(resolveCrashReportDirectory, fileName);
|
||||
ensureDirectory(resolveCrashReportDirectory);
|
||||
const path = join(publicDir.crashDir, fileName);
|
||||
ensureDirectory(publicDir.crashDir);
|
||||
|
||||
try {
|
||||
const textContent = JSON.stringify(content, null, 2);
|
||||
|
||||
@@ -3,8 +3,9 @@ import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { rm } from 'fs/promises';
|
||||
|
||||
import { getAppDataPath, publicDir } from '../setup/index.js';
|
||||
|
||||
import { ensureDirectory } from './fileManagement.js';
|
||||
import { getAppDataPath, uploadsFolderPath } from '../setup/index.js';
|
||||
|
||||
function generateNewFileName(filePath: string, callback: (newName: string) => void) {
|
||||
const baseName = path.basename(filePath, path.extname(filePath));
|
||||
@@ -36,19 +37,19 @@ export const storage = multer.diskStorage({
|
||||
throw new Error('Could not resolve public folder for platform');
|
||||
}
|
||||
|
||||
ensureDirectory(uploadsFolderPath);
|
||||
ensureDirectory(publicDir.uploadsDir);
|
||||
|
||||
const filePath = path.join(uploadsFolderPath, file.originalname);
|
||||
const filePath = path.join(publicDir.uploadsDir, file.originalname);
|
||||
|
||||
// Check if file already exists
|
||||
fs.access(filePath, fs.constants.F_OK, (err) => {
|
||||
if (err) {
|
||||
// File does not exist, can safely proceed to this destination
|
||||
cb(null, uploadsFolderPath);
|
||||
cb(null, publicDir.uploadsDir);
|
||||
} else {
|
||||
generateNewFileName(filePath, (newName) => {
|
||||
file.originalname = newName;
|
||||
cb(null, uploadsFolderPath);
|
||||
cb(null, publicDir.uploadsDir);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -63,7 +64,7 @@ export const storage = multer.diskStorage({
|
||||
*/
|
||||
export async function clearUploadfolder() {
|
||||
try {
|
||||
await rm(uploadsFolderPath, { recursive: true });
|
||||
await rm(publicDir.uploadsDir, { recursive: true });
|
||||
} catch (_) {
|
||||
// we dont care that there was no folder
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user