pandora
Version:
A powerful and lightweight application manager for Node.js applications powered by TypeScript.
134 lines (110 loc) • 3.22 kB
text/typescript
import {ApplicationRepresentation, ApplicationStructureRepresentation} from '../domain';
import uuid = require('uuid');
import {State} from '../const';
import {ProcfileReconciler} from './ProcfileReconciler';
import {ProcessHandler} from './ProcessHandler';
import {exists} from 'mz/fs';
export class ApplicationHandler {
public state: State;
public appId: string = null;
public appRepresentation: ApplicationRepresentation = null;
public mountedProcesses: ProcessHandler[];
private startTime: number;
private structure: ApplicationStructureRepresentation;
constructor(appRepresentation: ApplicationRepresentation) {
this.state = State.pending;
this.appId = uuid.v4();
this.appRepresentation = appRepresentation;
}
public get appName() {
return this.appRepresentation.appName;
}
public get appDir() {
return this.appRepresentation.appDir;
}
public get pids(): Array<number> {
const ret = [];
if(this.mountedProcesses) {
for(const app of this.mountedProcesses) {
if(app.pid) {
ret.push(app.pid);
}
}
}
return ret;
}
public get startCount(): number {
let ret = 0;
if(this.mountedProcesses) {
for(const handler of this.mountedProcesses) {
ret += handler.startCount;
}
}
return ret;
}
public get restartCount(): number {
let ret = this.startCount;
ret = Math.max(0, ret - this.mountedProcesses.length);
return ret;
}
public get uptime(): number {
if(!this.startTime) {
return 0;
}
return (Date.now() - this.startTime) / 1000;
}
public async getStructure(): Promise<ApplicationStructureRepresentation> {
if(!this.structure) {
this.structure = await ProcfileReconciler.getStructureViaNewProcess(this.appRepresentation);
}
return this.structure;
}
public async fillMounted() {
if(this.mountedProcesses) {
return;
}
this.mountedProcesses = [];
const {process: mountList} = await this.getStructure();
for(const mount of mountList) {
const appHandler = new ProcessHandler(mount);
this.mountedProcesses.push(appHandler);
}
}
async start () {
if(!await exists(this.appDir)) {
throw new Error(`AppDir ${this.appDir} does not exist`);
}
await this.fillMounted();
if(!this.mountedProcesses.length) {
throw new Error('Start failed, looks like not a pandora project, in appDir ' + this.appDir);
}
const startedHandlers = [];
for(const handler of this.mountedProcesses) {
try {
await handler.start();
} catch (error) {
for(const started of startedHandlers) {
await started.stop();
}
throw error;
}
startedHandlers.push(handler);
}
this.state = State.complete;
this.startTime = Date.now();
}
async stop () {
if (this.state === State.stopped) {
return;
}
for(const appHandler of this.mountedProcesses) {
await appHandler.stop();
}
this.state = State.stopped;
}
async reload (processName: string) {
for(const appHandler of this.mountedProcesses) {
await appHandler.reload(processName);
}
}
}