pandora
Version:
A powerful and lightweight application manager for Node.js applications powered by TypeScript.
139 lines (116 loc) • 3.53 kB
text/typescript
import {ApplicationRepresentation, ComplexApplicationStructureRepresentation} from '../domain';
import uuid = require('uuid');
import {State} from '../const';
import {ProcfileReconciler} from '../application/ProcfileReconciler';
import {ApplicationHandler} from '../application/ApplicationHandler';
import {exists} from 'mz/fs';
import {backupLog, getAppLogPath} from '../universal/LoggerBroker';
export class ComplexHandler {
public state: State;
public appId: string = null;
public appRepresentation: ApplicationRepresentation = null;
public mountedApplications: ApplicationHandler[];
private startTime: number;
private complexStructure: ComplexApplicationStructureRepresentation;
constructor(appRepresentation: ApplicationRepresentation) {
this.state = State.pending;
this.appId = uuid.v4();
this.appRepresentation = appRepresentation;
}
public get name() {
return this.appRepresentation.appName;
}
public get appDir() {
return this.appRepresentation.appDir;
}
public get mode() {
return this.appRepresentation.mode;
}
public get pids(): Array<number> {
const ret = [];
if(this.mountedApplications) {
for(const app of this.mountedApplications) {
if(app.pid) {
ret.push(app.pid);
}
}
}
return ret;
}
public get startCount(): number {
let ret = 0;
if(this.mountedApplications) {
for(const app of this.mountedApplications) {
ret += app.startCount;
}
}
return ret;
}
public get uptime(): number {
if(!this.startTime) {
return 0;
}
return (Date.now() - this.startTime) / 1000;
}
public async getComplex(): Promise<ComplexApplicationStructureRepresentation> {
if(!this.complexStructure) {
this.complexStructure = await ProcfileReconciler.getComplexViaNewProcess(this.appRepresentation);
}
return this.complexStructure;
}
protected async fillMounted () {
if(this.mountedApplications) {
return;
}
this.mountedApplications = [];
const {mount: mountList} = await this.getComplex();
for(const mount of mountList) {
const appHandler = new ApplicationHandler(mount);
this.mountedApplications.push(appHandler);
}
}
async start () {
if(!await exists(this.appDir)) {
new Error(`AppDir ${this.appDir} does not exist`);
}
await this.backupStdoutLogFile();
await this.fillMounted();
if(!this.mountedApplications.length) {
throw new Error('Start failed, looks like not a pandora project, in appDir ' + this.appDir);
}
const startedHandlers = [];
for(const appHandler of this.mountedApplications) {
try {
await appHandler.start();
} catch (error) {
for(const started of startedHandlers) {
await started.stop();
}
throw error;
}
startedHandlers.push(appHandler);
}
this.state = State.complete;
this.startTime = Date.now();
}
async stop () {
if (this.state === State.stopped) {
return;
}
for(const appHandler of this.mountedApplications) {
await appHandler.stop();
}
this.state = State.stopped;
}
async reload (processName: string) {
for(const appHandler of this.mountedApplications) {
await appHandler.reload(processName);
}
}
async backupStdoutLogFile() {
const targetPath = getAppLogPath(this.name, 'nodejs_stdout');
if(await exists(targetPath)) {
await backupLog(targetPath);
}
}
}