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