import { FilesChangeNotifierService, IHashesCache, } from "./files_change_notifier_service"; import { IPipeline } from "../model/process_model"; import { ExecutorProgramService } from "./executor_program_service"; import { EXEC_EVENT, ExecError, SpawnError } from "../model/exec_error_model"; import { TypedEvent } from "../helper/typed_event"; import { Result } from "../helper/result"; import { ExecutorResult } from "../model/executor_result"; import { delay } from "../helper/delay"; import { TriggerService } from "./trigger_service"; import { Trigger } from "../../features/triggers/trigger_model"; export interface Iteration { hashes: IHashesCache | null; process: IPipeline; result?: ExecError | SpawnError | ExecutorResult; } export abstract class IStackService { abstract callStack: Iteration[]; abstract path: string; abstract init(processed: IPipeline[], path: string): void; } export class StackService extends TypedEvent implements IStackService { callStack: Iteration[]; path: string; constructor(processed: IPipeline[], path: string) { super(); this.path = path; this.callStack = []; this.init(processed); } public init(processed: IPipeline[]) { for (let el of processed) { el = this.commandHandler(el); this.callStack.push({ hashes: null, process: el, }); } } private commandHandler(processMetaData: IPipeline) { processMetaData.process.command = processMetaData.process.command.replace( "$PATH", this.path ); return processMetaData; } public async call() { let inc = 0; for await (const el of this.callStack!) { await this.execStack(inc, el); inc += 1; this.emit(this.callStack); } } async execStack( stackNumber: number, stackLayer: Iteration ): Promise { const executorService = new ExecutorProgramService(this.path); executorService.call( stackLayer.process.process.type, stackLayer.process.process.command ); const filesChangeNotifierService = new FilesChangeNotifierService( this.path ); filesChangeNotifierService.call(); const result = await this.waitEvent< Result >(executorService); await delay(100); if (result.isSuccess()) { this.callStack[stackNumber].result = result.value; this.callStack[stackNumber].hashes = filesChangeNotifierService.hashes; const triggerResult = await this.triggerExec( stackLayer.process.trigger, stackNumber ); triggerResult.fold( (s) => { s; }, (e) => { e; } ); } filesChangeNotifierService.cancel(); return; } public waitEvent(stream: TypedEvent): Promise { const promise = new Promise((resolve, reject) => { const addListener = () => { stream.on((e) => { const event = e as Result; event.fold( (s) => { if (s.event === EXEC_EVENT.END) { resolve(e); } }, (e) => { reject(e); } ); }); }; addListener(); }); return promise; } private async triggerExec( trigger: Trigger | null, stackNumber: number ): Promise> { if (trigger !== null) { const hashes = this.callStack[stackNumber].hashes; if (hashes != null) { return await new TriggerService(trigger, hashes, this.path).call(); } throw new Error("Hashes is null"); } return Result.ok(); } }