refactor(config): Extract configuration into src/config/ module
- Create src/config/paths.js for all file paths and env vars - Create src/config/site.js for site configuration loading - Create src/config/index.js as unified config export - Prepare for server.js modularization (Phase 2.1) Part of deslopification roadmap: break 1997-line server.js into layers
This commit is contained in:
38
dashcaddy-api/src/config/index.js
Normal file
38
dashcaddy-api/src/config/index.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Centralized configuration module
|
||||||
|
* Exports all configuration loading and path resolution
|
||||||
|
*/
|
||||||
|
const paths = require('./paths');
|
||||||
|
const site = require('./site');
|
||||||
|
const { APP, LIMITS, TIMEOUTS, RETRIES, CADDY } = require('../../constants');
|
||||||
|
|
||||||
|
// Load logging level
|
||||||
|
const LOG_LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
|
||||||
|
const LOG_LEVEL = LOG_LEVELS[process.env.LOG_LEVEL || 'info'] || 1;
|
||||||
|
|
||||||
|
const PORT = APP.PORT;
|
||||||
|
const MAX_ERROR_LOG_SIZE = LIMITS.ERROR_LOG_SIZE;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// Paths
|
||||||
|
...paths,
|
||||||
|
|
||||||
|
// Site configuration
|
||||||
|
siteConfig: site.siteConfig,
|
||||||
|
loadSiteConfig: site.loadSiteConfig,
|
||||||
|
buildDomain: site.buildDomain,
|
||||||
|
buildServiceUrl: site.buildServiceUrl,
|
||||||
|
|
||||||
|
// App constants
|
||||||
|
PORT,
|
||||||
|
LOG_LEVELS,
|
||||||
|
LOG_LEVEL,
|
||||||
|
MAX_ERROR_LOG_SIZE,
|
||||||
|
|
||||||
|
// Re-export constants for convenience
|
||||||
|
APP,
|
||||||
|
LIMITS,
|
||||||
|
TIMEOUTS,
|
||||||
|
RETRIES,
|
||||||
|
CADDY,
|
||||||
|
};
|
||||||
42
dashcaddy-api/src/config/paths.js
Normal file
42
dashcaddy-api/src/config/paths.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* Platform-specific paths and environment variable configuration
|
||||||
|
*/
|
||||||
|
const path = require('path');
|
||||||
|
const platformPaths = require('../../platform-paths');
|
||||||
|
|
||||||
|
const CADDYFILE_PATH = process.env.CADDYFILE_PATH || platformPaths.caddyfile;
|
||||||
|
const CADDY_ADMIN_URL = process.env.CADDY_ADMIN_URL || platformPaths.caddyAdminUrl;
|
||||||
|
const SERVICES_FILE = process.env.SERVICES_FILE || platformPaths.servicesFile;
|
||||||
|
const SERVICES_DIR = path.dirname(SERVICES_FILE);
|
||||||
|
const CONFIG_FILE = process.env.CONFIG_FILE || path.join(SERVICES_DIR, 'config.json');
|
||||||
|
const DNS_CREDENTIALS_FILE = process.env.DNS_CREDENTIALS_FILE || path.join(SERVICES_DIR, 'dns-credentials.json');
|
||||||
|
const TAILSCALE_CONFIG_FILE = process.env.TAILSCALE_CONFIG_FILE || path.join(SERVICES_DIR, 'tailscale-config.json');
|
||||||
|
const NOTIFICATIONS_FILE = process.env.NOTIFICATIONS_FILE || path.join(SERVICES_DIR, 'notifications.json');
|
||||||
|
const TOTP_CONFIG_FILE = process.env.TOTP_CONFIG_FILE || path.join(SERVICES_DIR, 'totp-config.json');
|
||||||
|
const ERROR_LOG_FILE = process.env.ERROR_LOG_FILE || path.join(__dirname, '../../dashcaddy-errors.log');
|
||||||
|
const LICENSE_SECRET_FILE = process.env.LICENSE_SECRET_FILE || path.join(__dirname, '../../.license-secret');
|
||||||
|
|
||||||
|
const BROWSE_ROOTS = (process.env.MEDIA_BROWSE_ROOTS || '')
|
||||||
|
.split(',')
|
||||||
|
.filter(r => r.includes('='))
|
||||||
|
.map(r => {
|
||||||
|
const eqIndex = r.indexOf('=');
|
||||||
|
const containerPath = r.slice(0, eqIndex).trim();
|
||||||
|
const hostPath = r.slice(eqIndex + 1).trim();
|
||||||
|
return { containerPath, hostPath };
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
CADDYFILE_PATH,
|
||||||
|
CADDY_ADMIN_URL,
|
||||||
|
SERVICES_FILE,
|
||||||
|
SERVICES_DIR,
|
||||||
|
CONFIG_FILE,
|
||||||
|
DNS_CREDENTIALS_FILE,
|
||||||
|
TAILSCALE_CONFIG_FILE,
|
||||||
|
NOTIFICATIONS_FILE,
|
||||||
|
TOTP_CONFIG_FILE,
|
||||||
|
ERROR_LOG_FILE,
|
||||||
|
LICENSE_SECRET_FILE,
|
||||||
|
BROWSE_ROOTS,
|
||||||
|
};
|
||||||
79
dashcaddy-api/src/config/site.js
Normal file
79
dashcaddy-api/src/config/site.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* Site configuration loader
|
||||||
|
* Loads and manages site-wide settings from config.json
|
||||||
|
*/
|
||||||
|
const fs = require('fs');
|
||||||
|
const { validateConfig } = require('../../config-schema');
|
||||||
|
const { CADDY } = require('../../constants');
|
||||||
|
|
||||||
|
let siteConfig = {
|
||||||
|
tld: '.home',
|
||||||
|
caName: '',
|
||||||
|
dnsServerIp: '',
|
||||||
|
dnsServerPort: CADDY.DEFAULT_DNS_PORT,
|
||||||
|
dashboardHost: '',
|
||||||
|
timezone: 'UTC',
|
||||||
|
dnsServers: {},
|
||||||
|
configurationType: 'homelab',
|
||||||
|
domain: '',
|
||||||
|
routingMode: 'subdomain'
|
||||||
|
};
|
||||||
|
|
||||||
|
function loadSiteConfig(CONFIG_FILE, log) {
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(CONFIG_FILE)) {
|
||||||
|
const raw = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
||||||
|
|
||||||
|
// Validate config and log any issues
|
||||||
|
const { valid, errors: configErrors, warnings: configWarnings } = validateConfig(raw);
|
||||||
|
if (log && log.warn) {
|
||||||
|
if (!valid) {
|
||||||
|
log.warn('config', 'Config validation errors', { errors: configErrors });
|
||||||
|
}
|
||||||
|
for (const w of configWarnings) {
|
||||||
|
log.warn('config', w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
siteConfig.tld = raw.tld || '.home';
|
||||||
|
if (!siteConfig.tld.startsWith('.')) siteConfig.tld = '.' + siteConfig.tld;
|
||||||
|
siteConfig.caName = raw.caName || '';
|
||||||
|
siteConfig.dnsServerIp = (raw.dns && raw.dns.ip) || '';
|
||||||
|
siteConfig.dnsServerPort = (raw.dns && raw.dns.port) || CADDY.DEFAULT_DNS_PORT;
|
||||||
|
siteConfig.dashboardHost = raw.dashboardHost || `status${siteConfig.tld}`;
|
||||||
|
siteConfig.timezone = raw.timezone || 'UTC';
|
||||||
|
siteConfig.dnsServers = raw.dnsServers || {};
|
||||||
|
siteConfig.configurationType = raw.configurationType || 'homelab';
|
||||||
|
siteConfig.domain = raw.domain || '';
|
||||||
|
siteConfig.routingMode = raw.routingMode || 'subdomain';
|
||||||
|
siteConfig.pylon = raw.pylon || null;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (log && log.error) {
|
||||||
|
log.error('config', 'Failed to load site config', { error: e.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Build a domain from subdomain + configured TLD or public domain */
|
||||||
|
function buildDomain(subdomain) {
|
||||||
|
if (siteConfig.configurationType === 'public' && siteConfig.domain) {
|
||||||
|
return `${subdomain}.${siteConfig.domain}`;
|
||||||
|
}
|
||||||
|
return `${subdomain}${siteConfig.tld}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Build full service URL (protocol + host + path) */
|
||||||
|
function buildServiceUrl(subdomain) {
|
||||||
|
if (siteConfig.routingMode === 'subdirectory' && siteConfig.domain) {
|
||||||
|
return `https://${siteConfig.domain}/${subdomain}`;
|
||||||
|
}
|
||||||
|
return `https://${buildDomain(subdomain)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
siteConfig,
|
||||||
|
loadSiteConfig,
|
||||||
|
buildDomain,
|
||||||
|
buildServiceUrl,
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user