import * as plugins from './smartnginx.plugins'; import * as paths from './smartnginx.paths'; import * as snippets from './smartnginx.snippets'; import { NginxHost } from './smartnginx.classes.nginxhost'; import { NginxProcess } from './smartnginx.classes.nginxprocess'; import { IHostConfig } from './interfaces/hostconfig'; 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 = plugins.smartlog.defaultLogger); } // =================== // 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.find(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}); plugins.smartfile.memory.toFsSync(selfsignedCert.private, plugins.path.join(paths.nginxConfigDirPath, './default.private.pem')); plugins.smartfile.memory.toFsSync(selfsignedCert.public, plugins.path.join(paths.nginxConfigDirPath, './default.public.pem')); // deploy hosts plugins.smartfile.fs.ensureEmptyDirSync(paths.nginxHostDirPath); 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(); } } }