webstudio/server/src/core/services/stack_service.ts
2023-12-14 23:04:45 +03:00

116 lines
3.6 KiB
TypeScript

import { FilesChangeNotifierService, IHashesCache } from "./files_change_notifier_service";
import { IPipeline } from "../models/process_model";
import { ExecutorProgramService } from "./executor_program_service";
import { EXEC_EVENT, ExecError, SpawnError } from "../models/exec_error_model";
import { TypedEvent } from "../helpers/typed_event";
import { Result } from "../helpers/result";
import { ExecutorResult } from "../models/executor_result";
import { delay } from "../helpers/delay";
import { TriggerService } from "./trigger_service";
import { Trigger } from "../../features/triggers/models/trigger_database_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<Iteration[]> 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<void | boolean> {
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<ExecError | SpawnError, ExecutorResult>>(executorService);
console.log(200);
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<T>(stream: TypedEvent<T>): Promise<T> {
const promise = new Promise<T>((resolve, reject) => {
const addListener = () => {
stream.on((e) => {
const event = e as Result<ExecError | SpawnError, ExecutorResult>;
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<Result<boolean, boolean>> {
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();
}
}