diff --git a/server/src/core/controllers/app.ts b/server/src/core/controllers/app.ts index cde0692..a65ba2f 100644 --- a/server/src/core/controllers/app.ts +++ b/server/src/core/controllers/app.ts @@ -58,6 +58,8 @@ export class App extends TypedEvent { io.on("connection", (socket) => { this.socketSubscribers.map((el) => { el.emitter.on((e) => { + console.log(el.event) + console.log(e) socket.emit(el.event, e); }); }); diff --git a/server/src/core/models/exec_error_model.ts b/server/src/core/models/exec_error_model.ts index 12cb3ac..9e28fb3 100644 --- a/server/src/core/models/exec_error_model.ts +++ b/server/src/core/models/exec_error_model.ts @@ -3,6 +3,19 @@ import { extensions } from "../extensions/extensions"; extensions(); export class ExecError extends Error { + id?:string; + script: string; + unixTime: number; + type = EXEC_TYPE.EXEC; + error: any; + + constructor(script: string, ...args: any) { + super(...args); + this.script = script; + this.unixTime = Date.now(); + this.error = args.firstElement(); + } + static isExecError(e: any): ExecError | void { try { if (e) { @@ -14,16 +27,6 @@ export class ExecError extends Error { console.log(error); } } - script: string; - unixTime: number; - type = EXEC_TYPE.EXEC; - error: any; - constructor(script: string, ...args: any) { - super(...args); - this.script = script; - this.unixTime = Date.now(); - this.error = args.firstElement(); - } } export class SpawnError extends Error { diff --git a/server/src/core/models/executor_result.ts b/server/src/core/models/executor_result.ts index fd4c32a..c5c5d87 100644 --- a/server/src/core/models/executor_result.ts +++ b/server/src/core/models/executor_result.ts @@ -4,6 +4,7 @@ export class ExecutorResult { type: EXEC_TYPE; event: EXEC_EVENT; data: any; + id?:string constructor(type: EXEC_TYPE, event: EXEC_EVENT, data: any) { this.type = type; this.event = event; diff --git a/server/src/core/services/executor_program_service.ts b/server/src/core/services/executor_program_service.ts index 847915f..bee83c7 100644 --- a/server/src/core/services/executor_program_service.ts +++ b/server/src/core/services/executor_program_service.ts @@ -25,7 +25,12 @@ export class ExecutorProgramService this.maxTime = maxTime; } - private async workerExecuted(command: string, workerType: WorkerType, args: Array | undefined = undefined) { + private async workerExecuted( + command: string, + workerType: WorkerType, + args: Array | undefined = undefined, + id: string | undefined = undefined + ) { try { cluster.setupPrimary({ exec: __dirname + "/../helpers/worker_computed.js", @@ -55,6 +60,7 @@ export class ExecutorProgramService const execError = ExecError.isExecError(e); if (execError instanceof ExecError) { + execError.id = id this.emit(Result.error(execError)); this.worker = undefined; return; @@ -62,6 +68,7 @@ export class ExecutorProgramService const executorResult = ExecutorResult.isExecutorResult(e); if (executorResult instanceof ExecutorResult) { + executorResult.id = id this.emit(Result.ok(executorResult)); this.worker = undefined; return; @@ -85,13 +92,18 @@ export class ExecutorProgramService if (this.worker) this.worker.kill(); this.worker = undefined; } - public async call(type: EXEC_TYPE, command: string, args: Array | undefined = undefined): Promise { + public async call( + type: EXEC_TYPE, + command: string, + args: Array | undefined = undefined, + id: string | undefined = undefined + ): Promise { if (type == EXEC_TYPE.EXEC) { - this.workerExecuted(command, WorkerType.EXEC); + this.workerExecuted(command, WorkerType.EXEC, undefined, id); return; } - this.workerExecuted(command, WorkerType.SPAWN, args); + this.workerExecuted(command, WorkerType.SPAWN, args, id); return; } diff --git a/server/src/core/usecases/exec_process_usecase.ts b/server/src/core/usecases/exec_process_usecase.ts index 32e7161..12b7d16 100644 --- a/server/src/core/usecases/exec_process_usecase.ts +++ b/server/src/core/usecases/exec_process_usecase.ts @@ -5,7 +5,7 @@ import { EXEC_TYPE, ExecError, SpawnError } from "../models/exec_error_model"; import { ExecutorResult } from "../models/executor_result"; import { ExecutorProgramService } from "../services/executor_program_service"; -const executorProgramService = new ExecutorProgramService(""); +export const executorProgramService = new ExecutorProgramService(""); export class KillLastProcessUseCase extends CallbackStrategyWithEmpty { call = async (): Promise> => { executorProgramService.deleteWorker(); @@ -26,6 +26,7 @@ export class ExecProcessUseCase { call = async ( path: string, command: string, + id:string, watcher?: TypedEvent> ): Promise> => { try { @@ -33,7 +34,7 @@ export class ExecProcessUseCase { executorProgramService.on((event) => { if (watcher) watcher.emit(event); }); - executorProgramService.call(EXEC_TYPE.EXEC, command); + executorProgramService.call(EXEC_TYPE.EXEC, command, undefined ,id); return Result.ok("ok"); } catch (error) { diff --git a/server/src/features/datasets/domain/exec_process_scenario.ts b/server/src/features/datasets/domain/exec_process_scenario.ts index 5a18e25..41d375a 100644 --- a/server/src/features/datasets/domain/exec_process_scenario.ts +++ b/server/src/features/datasets/domain/exec_process_scenario.ts @@ -6,8 +6,7 @@ import { MongoIdValidation } from "../../../core/validations/mongo_id_validation import { DatasetDBModel } from "../models/dataset_database_model"; import { IDatasetModel } from "../models/dataset_validation_model"; import { ProcessWatcherAndDatabaseUpdateService } from "./create_dataset_scenario"; -import { UpdateDataBaseModelUseCase } from "../../../core/usecases/update_database_model_usecase"; - + export class ExecDatasetProcessScenario extends CallbackStrategyWithIdQuery { idValidationExpression = new MongoIdValidation(); @@ -18,6 +17,7 @@ export class ExecDatasetProcessScenario extends CallbackStrategyWithIdQuery { return new ExecProcessUseCase().call( `${model.project.rootDir}/`, `python3 $PYTHON_BLENDER_PROC --path '${model.project.rootDir}/${model.name}/'`, + id, new ProcessWatcherAndDatabaseUpdateService(id as unknown as ObjectId) ); }); diff --git a/server/src/features/projects/domain/upload_file_to_to_project_scenario.ts b/server/src/features/projects/domain/upload_file_to_to_project_scenario.ts index 826ee25..e24a7bf 100644 --- a/server/src/features/projects/domain/upload_file_to_to_project_scenario.ts +++ b/server/src/features/projects/domain/upload_file_to_to_project_scenario.ts @@ -18,6 +18,7 @@ export class UploadCadFileToProjectScenario extends CallbackStrategyWithFileUplo async () => await new ExecProcessUseCase().call( `${databaseModel.rootDir}/`, + '', `python3 $PYTHON_BLENDER --path '${databaseModel.rootDir}/assets/'` ) ) diff --git a/server/src/main.ts b/server/src/main.ts index 6591d87..f8166fc 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -3,10 +3,10 @@ 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 { pipelineRealTimeService } from "./features/_realtime/realtime_presentation"; - +import { executorProgramService } from "./core/usecases/exec_process_usecase"; + extensions(); -const socketSubscribers = [new SocketSubscriber(pipelineRealTimeService, "realtime")]; +const socketSubscribers = [new SocketSubscriber(executorProgramService, "realtime")]; new App(httpRoutes, socketSubscribers).listen(); diff --git a/ui/src/core/extensions/extensions.ts b/ui/src/core/extensions/extensions.ts index 8116b3e..3f6f7dd 100644 --- a/ui/src/core/extensions/extensions.ts +++ b/ui/src/core/extensions/extensions.ts @@ -26,6 +26,7 @@ declare global { toPx(): string; unixFromDate(): string; isValid(str: string): boolean; + randRange(min:number,max:number):number } interface String { diff --git a/ui/src/core/extensions/number.ts b/ui/src/core/extensions/number.ts index 324d512..2a33423 100644 --- a/ui/src/core/extensions/number.ts +++ b/ui/src/core/extensions/number.ts @@ -24,4 +24,10 @@ export const NumberExtensions = () => { return !isNaN(Number(str)); }; } + if(Number().randRange === undefined){ + // eslint-disable-next-line no-extend-native + Number.prototype.randRange = function (min,max) { + return Math.random() * (max - min) + min; + } + } }; diff --git a/ui/src/core/repository/socket_repository.ts b/ui/src/core/repository/socket_repository.ts index 6eda6e7..697c3ea 100644 --- a/ui/src/core/repository/socket_repository.ts +++ b/ui/src/core/repository/socket_repository.ts @@ -1,14 +1,30 @@ import { Socket, io } from "socket.io-client"; +import { Result } from "../helper/result"; +import { TypedEvent } from "../helper/typed_event"; -export class SocketRepository { +export class SocketRepository extends TypedEvent { serverURL = "ws://localhost:4001"; socket: Socket | undefined; - async connect() { + + async connect():Promise> { const socket = io(this.serverURL); this.socket = socket; socket.connect(); socket.on('realtime', (d) =>{ + console.log("D") console.log(d) + + this.emit({ + event:"realtime", + payload:d + }) }) + if(socket.connected){ + return Result.ok(true) + } + return Result.error(false) } + } + +export const socketRepository = new SocketRepository() \ No newline at end of file diff --git a/ui/src/core/ui/input/input.tsx b/ui/src/core/ui/input/input.tsx index 81d74f2..2aa86de 100644 --- a/ui/src/core/ui/input/input.tsx +++ b/ui/src/core/ui/input/input.tsx @@ -1,6 +1,5 @@ -import React from "react"; +import * as React from "react"; import { CoreText, CoreTextType } from "../text/text"; -import { Input } from "antd"; interface IInputProps { label: string; @@ -10,16 +9,19 @@ interface IInputProps { validation?: (value: string) => boolean; error?: string; } -export const CoreInput = (props: IInputProps) => { - const [key, setKey] = React.useState(undefined); +export const CoreInput = (props: IInputProps) => { + const [value, setValue] = React.useState(() => props.value ?? ""); + const ref = React.useRef(null); + const [isAppendInnerText, setAppendInnerText] = React.useState(true); React.useEffect(() => { - setKey(props.value); - return () => { - setKey(undefined); - }; - }, [key, setKey, props]); - + if (ref.current && isAppendInnerText) { + ref.current.innerText = value; + setAppendInnerText(false); + } + }, [ref, value, isAppendInnerText, setAppendInnerText]); + + return (
{ > - { color: "#1D1B20", height: 24, width: "100%", + userSelect: 'none', + outline:'none' }} onChange={(e) => { const val = e.target.value; + setValue(val) if (val) { if (props.validation !== undefined && props.validation(val) && props.onChange) { props.onChange(val); @@ -62,9 +66,9 @@ export const CoreInput = (props: IInputProps) => { } }} /> - {props.value ? ( + {value ? ( props.validation ? ( - props.validation(props.value) ? null : ( + props.validation(value) ? null : (
{props.error ? props.error : "error"}
) ) : null diff --git a/ui/src/features/dataset/dataset_screen.tsx b/ui/src/features/dataset/dataset_screen.tsx index a90bcf3..719007c 100644 --- a/ui/src/features/dataset/dataset_screen.tsx +++ b/ui/src/features/dataset/dataset_screen.tsx @@ -62,6 +62,7 @@ export const DataSetScreen: React.FunctionComponent = observer(() => { /> store.editDrawer(DrawersDataset.FormBuilderDrawer, false)} open={store.drawers.find((el) => el.name === DrawersDataset.FormBuilderDrawer)?.status ?? false} > @@ -84,6 +85,7 @@ export const DataSetScreen: React.FunctionComponent = observer(() => { store.editDrawer(DrawersDataset.NewDataset, false)} open={store.drawers.find((el) => el.name === DrawersDataset.NewDataset)?.status} > diff --git a/ui/src/features/dataset/dataset_store.ts b/ui/src/features/dataset/dataset_store.ts index f42113b..f4eec4f 100644 --- a/ui/src/features/dataset/dataset_store.ts +++ b/ui/src/features/dataset/dataset_store.ts @@ -2,9 +2,10 @@ import makeAutoObservable from "mobx-store-inheritance"; import { DataSetRepository } from "./dataset_repository"; import { UiErrorState } from "../../core/store/base_store"; import { HttpError } from "../../core/repository/http_repository"; -import { Asset, Assets, DataSetModel, IDatasetModel } from "./dataset_model"; +import { Asset, Assets, DataSetModel, IDatasetModel, ProcessStatus } from "./dataset_model"; import { message } from "antd"; import { UUID } from "../all_projects/data/project_repository"; +import { SocketRepository, socketRepository } from "../../core/repository/socket_repository"; export enum DrawersDataset { NewDataset = "Новый датасет", @@ -21,9 +22,10 @@ export class DataSetStore extends UiErrorState { activeProject: UUID; dataSetModel = DataSetModel.empty(); drawers: Drawer[]; - + socketRepository: SocketRepository; constructor() { super(); + this.socketRepository = socketRepository; this.dataSetRepository = new DataSetRepository(); this.drawers = Object.entries(DrawersDataset).map((k, v) => { return { @@ -32,13 +34,30 @@ export class DataSetStore extends UiErrorState { }; }); makeAutoObservable(this); + socketRepository.on((e) => { + if (e.event === "realtime") { + if (e.payload !== undefined && e.payload.value !== undefined && e.payload.value.id !== undefined) { + this.updateDatasetStatus(String(e.payload.value.id), ProcessStatus.END); + } + if (e.payload !== undefined && e.payload.error !== undefined && e.payload.error.id !== undefined) { + this.updateDatasetStatus(String(e.payload.error.id), ProcessStatus.ERROR); + } + } + }); + } + updateDatasetStatus(id: string, status: ProcessStatus) { + this.datasets = this.datasets?.map((el) => { + if (el._id.isEqual(id)) { + el.processStatus = status; + } + return el; + }); } - openEmptyCard() { this.dataSetModel = DataSetModel.empty(); this.editDrawer(DrawersDataset.NewDataset, true); } - + setNewDatasetName(e: string): void { this.dataSetModel.name = e; } @@ -74,7 +93,6 @@ export class DataSetStore extends UiErrorState { editDataset(id: string) { this.dataSetModel = DataSetModel.fromIDatasetModel(this.datasets?.find((el) => el._id === id) as IDatasetModel); - console.log(this.dataSetModel.name); this.editDrawer(DrawersDataset.NewDataset, true); } @@ -93,6 +111,7 @@ export class DataSetStore extends UiErrorState { async (s) => { (await this.dataSetRepository.execDatasetProcess(id)).fold( () => { + this.updateDatasetStatus(id,ProcessStatus.RUN) message.success("Процесс запущен"); }, (e) => message.error(e.message) diff --git a/ui/src/features/socket_lister/socket_lister.tsx b/ui/src/features/socket_lister/socket_lister.tsx index abc7004..3e00adf 100644 --- a/ui/src/features/socket_lister/socket_lister.tsx +++ b/ui/src/features/socket_lister/socket_lister.tsx @@ -9,7 +9,7 @@ export interface ISocketListerProps { export const SocketLister = observer((props: ISocketListerProps) => { return ( - <> +
{socketListerStore.socketHasDisconnect ? ( { @@ -28,6 +28,6 @@ export const SocketLister = observer((props: ISocketListerProps) => { )} {props.children} - +
); }); diff --git a/ui/src/features/socket_lister/socket_lister_store.ts b/ui/src/features/socket_lister/socket_lister_store.ts index d744af9..956c571 100644 --- a/ui/src/features/socket_lister/socket_lister_store.ts +++ b/ui/src/features/socket_lister/socket_lister_store.ts @@ -1,5 +1,5 @@ import { makeAutoObservable } from "mobx"; -import { SocketRepository } from "../../core/repository/socket_repository"; +import { SocketRepository, socketRepository } from "../../core/repository/socket_repository"; class SocketListerStore { repository: SocketRepository; @@ -8,13 +8,22 @@ class SocketListerStore { constructor(repository: SocketRepository) { this.repository = repository; makeAutoObservable(this); - repository.connect() + this.init(); + } + async init() { + (await this.repository.connect()).fold( + () => { + this.socketHasDisconnect = false + }, + () => { + this.socketHasDisconnect = true + } + ); } - async reconnect() { - await this.repository.connect() - this.socketHasDisconnect = false + await this.repository.connect(); + this.socketHasDisconnect = false; } } -export const socketListerStore = new SocketListerStore(new SocketRepository()); +export const socketListerStore = new SocketListerStore(socketRepository);