diff --git a/server/src/core/scenarios/exec_process_scenario_v2.ts b/server/src/core/scenarios/exec_process_scenario_v2.ts new file mode 100644 index 0000000..9f00e97 --- /dev/null +++ b/server/src/core/scenarios/exec_process_scenario_v2.ts @@ -0,0 +1,58 @@ +import { Disposable, Listener, TypedEvent } from "../helpers/typed_event"; +import { GetRootDirUseCase } from "../usecases/get_root_dir_usecase" +import { exec } from 'child_process'; + +enum ProcessStatus { + run = 'run', + endError = 'endError', + endOk = 'endOk', +} + +class ProcessData { + log: string | undefined; + status: ProcessStatus; + constructor(log: string | undefined, status: ProcessStatus) { + // console.log(log) + if (log !== undefined) { + this.log = log; + } + this.status = status; + + } +} +abstract class Watcher { +} +export abstract class ExecProcessWatcher extends TypedEvent implements Watcher { + logs: string[] = []; + status: ProcessStatus; + constructor() { + super(); + this.on((event) => { + if (event.log !== undefined) { + console.log(event.log) + this.logs.push(event.log); + } + this.status = event.status; + if (event.status.isEqualMany([ProcessStatus.endError, ProcessStatus.endOk])) { + this.result() + } + }) + } + abstract result(): Promise + +} +export class ExecProcessScenarioV2 { + call = (command: string, watcher: ExecProcessWatcher): void => { + const process = exec(command, { cwd: new GetRootDirUseCase().call() }); + process.stdout.on('data', (data) => watcher.emit(new ProcessData(data, ProcessStatus.run))) + process.stderr.on('data', (data) => watcher.emit(new ProcessData(data, ProcessStatus.run))); + process.on('close', (code) =>{ + if(code === 0){ + watcher.emit(new ProcessData(undefined, ProcessStatus.endOk)) + }else{ + watcher.emit(new ProcessData(undefined, ProcessStatus.endError)) + } + }); + process.on('error', (err) => watcher.emit(new ProcessData(err.message, ProcessStatus.endError))); + } +} \ No newline at end of file diff --git a/server/src/core/usecases/get_root_dir_usecase.ts b/server/src/core/usecases/get_root_dir_usecase.ts new file mode 100644 index 0000000..c134d6f --- /dev/null +++ b/server/src/core/usecases/get_root_dir_usecase.ts @@ -0,0 +1,5 @@ +import * as os from 'os'; + +export class GetRootDirUseCase { + call = (): string => os.homedir() +} \ No newline at end of file diff --git a/server/src/features/calculations_instance/calculations_instance_presentation.ts b/server/src/features/calculations_instance/calculations_instance_presentation.ts index 42f8793..8dfeb8e 100644 --- a/server/src/features/calculations_instance/calculations_instance_presentation.ts +++ b/server/src/features/calculations_instance/calculations_instance_presentation.ts @@ -4,6 +4,7 @@ import { CalculationInstanceValidationModel } from "./models/calculations_instan import { CalculationInstanceDBModel } from "./models/calculations_instance_database_model"; import { CreateCalculationInstanceScenario } from "./domain/create_calculation_instance_scenario"; import { DeleteCalculationsInstanceScenario } from "./domain/delete_calculations_instance_scenario"; + export class CalculationsInstancesPresentation extends CrudController< CalculationInstanceValidationModel, @@ -26,3 +27,4 @@ export class CalculationsInstancesPresentation extends CrudController< }); } } + \ No newline at end of file diff --git a/server/src/features/calculations_instance/domain/exec_calculations_instance_process_scenario.ts b/server/src/features/calculations_instance/domain/exec_calculations_instance_process_scenario.ts index e98afc1..ec28885 100644 --- a/server/src/features/calculations_instance/domain/exec_calculations_instance_process_scenario.ts +++ b/server/src/features/calculations_instance/domain/exec_calculations_instance_process_scenario.ts @@ -7,7 +7,21 @@ import { ProcessWatcherAndDatabaseUpdateService } from "../../datasets/domain/cr import { CalculationInstanceDBModel, ICalculationInstance } from "../models/calculations_instance_database_model"; import { Result } from "../../../core/helpers/result"; import { CreateFileUseCase } from "../../../core/usecases/create_file_usecase"; +import { ExecProcessScenarioV2, ExecProcessWatcher } from "../../../core/scenarios/exec_process_scenario_v2"; +class ExecProcess extends ExecProcessWatcher { + id: string; + constructor(id: string) { + super() + this.id = id; + } + result = async (): Promise => (await new ReadByIdDataBaseModelUseCase(CalculationInstanceDBModel).call(this.id)).map(async (model) => { + model.lastProcessLogs = this.logs.join('\n') + model.processStatus = this.status; + // @ts-ignore + await model.save() + }); +} export class ExecCalculationInstanceProcessScenario extends CallbackStrategyWithIdQuery { idValidationExpression = new MongoIdValidation(); call = async (id: string): ResponseBase => @@ -17,19 +31,15 @@ export class ExecCalculationInstanceProcessScenario extends CallbackStrategyWith return (await new IsHaveActiveProcessUseCase().call()).map(async () => { const execCommand = `${model.script } --path ${model.instancePath.pathNormalize()} --form ${fileOutPath}`.replace("\n", ""); - + await new CreateFileUseCase().call(fileOutPath, Buffer.from(JSON.stringify(model.formBuilder))); await CalculationInstanceDBModel.findById(id).updateOne({ processStatus: "RUN", lastProcessExecCommand: execCommand, }); - new ExecProcessUseCase().call( - // @ts-expect-error - `${model.project.rootDir}/`, - execCommand, - id, - new ProcessWatcherAndDatabaseUpdateService(id as unknown as ObjectId, CalculationInstanceDBModel) - ); + + new ExecProcessScenarioV2().call(execCommand, new ExecProcess(model._id)) + return Result.ok("OK"); }); } diff --git a/server/src/features/calculations_instance/models/calculations_instance_database_model.ts b/server/src/features/calculations_instance/models/calculations_instance_database_model.ts index 43e13d9..f52a63d 100644 --- a/server/src/features/calculations_instance/models/calculations_instance_database_model.ts +++ b/server/src/features/calculations_instance/models/calculations_instance_database_model.ts @@ -3,6 +3,7 @@ import { FormBuilderValidationModel } from "../../datasets/models/dataset_valida import { IProjectModel, projectSchema } from "../../projects/models/project_model_database_model"; export interface ICalculationInstance { + _id: string; script: string; instancePath: string; formBuilder: FormBuilderValidationModel; diff --git a/server/src/features/calculations_instance/models/calculations_instance_validation_model.ts b/server/src/features/calculations_instance/models/calculations_instance_validation_model.ts index 46b993c..eb8e6e2 100644 --- a/server/src/features/calculations_instance/models/calculations_instance_validation_model.ts +++ b/server/src/features/calculations_instance/models/calculations_instance_validation_model.ts @@ -4,6 +4,7 @@ import { FormBuilderValidationModel } from "../../datasets/models/dataset_valida import { IProjectModel } from "../../projects/models/project_model_database_model"; export class CalculationInstanceValidationModel implements ICalculationInstance { + _id: string; @IsNotEmpty() @IsString() instanceName: string; diff --git a/server/src/main.ts b/server/src/main.ts index 31d168e..1398356 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -3,8 +3,7 @@ import { App } from "./core/controllers/app"; import { SocketSubscriber } from "./core/controllers/socket_controller"; import { extensions } from "./core/extensions/extensions"; import { httpRoutes } from "./core/controllers/routes"; -import { SpawnProcessUseCase, executorProgramService } from "./core/usecases/exec_process_usecase"; -import { ProcessWatcher } from "./features/runtime/service/process_watcher"; +import { executorProgramService } from "./core/usecases/exec_process_usecase"; extensions(); diff --git a/ui/src/features/calculation_instance/presentation/calculation_instance_screen.tsx b/ui/src/features/calculation_instance/presentation/calculation_instance_screen.tsx index fc9dec4..a149435 100644 --- a/ui/src/features/calculation_instance/presentation/calculation_instance_screen.tsx +++ b/ui/src/features/calculation_instance/presentation/calculation_instance_screen.tsx @@ -28,7 +28,7 @@ export const CalculationInstanceScreenPath = "/calculation"; export const CalculationInstanceScreen = observer(() => { const store = useStore(CalculationInstanceStore); - + // console.log(200); return ( <> { label={"Тип карточки"} onChange={(text: string) => store.updateForm({ card: text })} /> - store.updateForm({ name: text })} /> - store.updateForm({ script: text })} /> + store.updateForm({ name: text.replaceAll("\n", "") })} + /> + store.updateForm({ script: text.replaceAll("\n", "") })} + /> (store.viewModel.formBuilder.result = text)}