import * as plugins from './smartnginx.plugins.js'; import * as paths from './smartnginx.paths.js'; import * as snippets from './smartnginx.snippets.js'; import { NginxHost } from './smartnginx.classes.nginxhost.js'; import { NginxProcess } from './smartnginx.classes.nginxprocess.js'; import { type IHostConfig } from './interfaces/hostconfig.js'; export interface ISmartNginxContructorOptions { logger?: plugins.smartlog.Smartlog; defaultProxyUrl: string; } /** * main class that manages a NginxInstance */ export class SmartNginx { public options: ISmartNginxContructorOptions; public logger: plugins.smartlog.Smartlog; // the objectmaps private deployedHosts = new plugins.lik.ObjectMap(); private hostCandidates = new plugins.lik.ObjectMap(); public nginxProcess: NginxProcess = new NginxProcess(this); constructor(optionsArg: ISmartNginxContructorOptions) { this.options = optionsArg; this.options.logger ? (this.logger = this.options.logger) : (this.logger = new plugins.smartlog.Smartlog({ logContext: null })); } // =================== // interact with Hosts // =================== /** * add a host * @param nginxHostArg */ public addHostCandidate(optionsArg: IHostConfig): NginxHost { const nginxHost = new NginxHost(this, optionsArg); this.hostCandidates.add(nginxHost); return nginxHost; } /** * Gets a NginxHost by hostname * @param hostNameArg */ public getDeployedNginxHostByHostName(hostNameArg: string): NginxHost { return this.deployedHosts.findSync((nginxHost) => { return nginxHost.hostName === hostNameArg; }); } /** * listHosts */ public async listDeployedHosts(): Promise { return this.deployedHosts.getArray(); } /** * remove a Host * @param nginxHostArg */ public async removeDeployedHost(nginxHostArg: NginxHost) { if (this.hostCandidates.isEmpty()) { this.deployedHosts.forEach((hostArg) => { this.hostCandidates.add(hostArg); }); } this.hostCandidates.remove(nginxHostArg); this.deploy(); } /** * check wether there has been a diverging host configuration * this function will only redeploy the nginx configuration in case there has been a change */ private async areHostsDiverged(): Promise { let hostCounter = 0; let unfoundHosts = 0; await this.hostCandidates.forEach(async (hostCandidateArg) => { let foundHost = false; await this.deployedHosts.forEach(async (deployedHostArg) => { if ( hostCandidateArg.hostName === deployedHostArg.hostName && hostCandidateArg.destination === deployedHostArg.destination && hostCandidateArg.destinationPort === deployedHostArg.destinationPort ) { hostCounter++; foundHost = true; } }); if (!foundHost) { unfoundHosts++; } }); return ( this.deployedHosts.getArray().length !== this.hostCandidates.getArray().length || hostCounter !== this.deployedHosts.getArray().length || unfoundHosts !== 0 ); } /** * deploy the current stack and restart nginx */ public async deploy() { if (await this.areHostsDiverged()) { this.logger.log('ok', `hosts have diverged, trigger config deployment and nginx reload!`); this.deployedHosts.wipe(); this.deployedHosts.addArray(this.hostCandidates.getArray()); this.hostCandidates.wipe(); // write base config plugins.smartfile.fs.ensureDirSync(paths.nginxConfigDirPath); plugins.smartfile.memory.toFsSync( snippets.getBaseConfigString(this.options.defaultProxyUrl), paths.nginxConfFile ); // write standard self signed certificate const selfsignedCert = plugins.selfsigned.generate( [{ name: 'commonName', value: 'selfsigned.git.zone' }], { days: 365 } ); // deploy hosts plugins.smartfile.fs.ensureDirSync(paths.nginxHostDirPath); plugins.smartfile.memory.toFsSync( selfsignedCert.private, plugins.path.join(paths.nginxHostDirPath, './default.private.pem') ); plugins.smartfile.memory.toFsSync( selfsignedCert.cert, plugins.path.join(paths.nginxHostDirPath, './default.public.pem') ); for (const host of this.deployedHosts.getArray()) { await host.deploy(); this.logger.log('info', `Host ${host.hostName} deployed!`); } this.nginxProcess.reloadConfig(); } else { this.logger.log('info', `hosts have not diverged, skipping nginx reload`); this.hostCandidates.wipe(); } } /** * stops the smartnginx instance */ public async stop() { if (this.nginxProcess) { await this.nginxProcess.stop(); } } }