adding socket listner dataset screen

This commit is contained in:
IDONTSUDO 2024-04-16 15:20:24 +03:00
parent 776b6e540e
commit a2066ce5cd
16 changed files with 127 additions and 50 deletions

View file

@ -58,6 +58,8 @@ export class App extends TypedEvent<ServerStatus> {
io.on("connection", (socket) => { io.on("connection", (socket) => {
this.socketSubscribers.map((el) => { this.socketSubscribers.map((el) => {
el.emitter.on((e) => { el.emitter.on((e) => {
console.log(el.event)
console.log(e)
socket.emit(el.event, e); socket.emit(el.event, e);
}); });
}); });

View file

@ -3,6 +3,19 @@ import { extensions } from "../extensions/extensions";
extensions(); extensions();
export class ExecError extends Error { 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 { static isExecError(e: any): ExecError | void {
try { try {
if (e) { if (e) {
@ -14,16 +27,6 @@ export class ExecError extends Error {
console.log(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 { export class SpawnError extends Error {

View file

@ -4,6 +4,7 @@ export class ExecutorResult {
type: EXEC_TYPE; type: EXEC_TYPE;
event: EXEC_EVENT; event: EXEC_EVENT;
data: any; data: any;
id?:string
constructor(type: EXEC_TYPE, event: EXEC_EVENT, data: any) { constructor(type: EXEC_TYPE, event: EXEC_EVENT, data: any) {
this.type = type; this.type = type;
this.event = event; this.event = event;

View file

@ -25,7 +25,12 @@ export class ExecutorProgramService
this.maxTime = maxTime; this.maxTime = maxTime;
} }
private async workerExecuted(command: string, workerType: WorkerType, args: Array<string> | undefined = undefined) { private async workerExecuted(
command: string,
workerType: WorkerType,
args: Array<string> | undefined = undefined,
id: string | undefined = undefined
) {
try { try {
cluster.setupPrimary({ cluster.setupPrimary({
exec: __dirname + "/../helpers/worker_computed.js", exec: __dirname + "/../helpers/worker_computed.js",
@ -55,6 +60,7 @@ export class ExecutorProgramService
const execError = ExecError.isExecError(e); const execError = ExecError.isExecError(e);
if (execError instanceof ExecError) { if (execError instanceof ExecError) {
execError.id = id
this.emit(Result.error(execError)); this.emit(Result.error(execError));
this.worker = undefined; this.worker = undefined;
return; return;
@ -62,6 +68,7 @@ export class ExecutorProgramService
const executorResult = ExecutorResult.isExecutorResult(e); const executorResult = ExecutorResult.isExecutorResult(e);
if (executorResult instanceof ExecutorResult) { if (executorResult instanceof ExecutorResult) {
executorResult.id = id
this.emit(Result.ok(executorResult)); this.emit(Result.ok(executorResult));
this.worker = undefined; this.worker = undefined;
return; return;
@ -85,13 +92,18 @@ export class ExecutorProgramService
if (this.worker) this.worker.kill(); if (this.worker) this.worker.kill();
this.worker = undefined; this.worker = undefined;
} }
public async call(type: EXEC_TYPE, command: string, args: Array<string> | undefined = undefined): Promise<void> { public async call(
type: EXEC_TYPE,
command: string,
args: Array<string> | undefined = undefined,
id: string | undefined = undefined
): Promise<void> {
if (type == EXEC_TYPE.EXEC) { if (type == EXEC_TYPE.EXEC) {
this.workerExecuted(command, WorkerType.EXEC); this.workerExecuted(command, WorkerType.EXEC, undefined, id);
return; return;
} }
this.workerExecuted(command, WorkerType.SPAWN, args); this.workerExecuted(command, WorkerType.SPAWN, args, id);
return; return;
} }

View file

@ -5,7 +5,7 @@ import { EXEC_TYPE, ExecError, SpawnError } from "../models/exec_error_model";
import { ExecutorResult } from "../models/executor_result"; import { ExecutorResult } from "../models/executor_result";
import { ExecutorProgramService } from "../services/executor_program_service"; import { ExecutorProgramService } from "../services/executor_program_service";
const executorProgramService = new ExecutorProgramService(""); export const executorProgramService = new ExecutorProgramService("");
export class KillLastProcessUseCase extends CallbackStrategyWithEmpty { export class KillLastProcessUseCase extends CallbackStrategyWithEmpty {
call = async (): Promise<Result<undefined, string>> => { call = async (): Promise<Result<undefined, string>> => {
executorProgramService.deleteWorker(); executorProgramService.deleteWorker();
@ -26,6 +26,7 @@ export class ExecProcessUseCase {
call = async ( call = async (
path: string, path: string,
command: string, command: string,
id:string,
watcher?: TypedEvent<Result<ExecError | SpawnError, ExecutorResult>> watcher?: TypedEvent<Result<ExecError | SpawnError, ExecutorResult>>
): Promise<Result<Error, string>> => { ): Promise<Result<Error, string>> => {
try { try {
@ -33,7 +34,7 @@ export class ExecProcessUseCase {
executorProgramService.on((event) => { executorProgramService.on((event) => {
if (watcher) watcher.emit(event); if (watcher) watcher.emit(event);
}); });
executorProgramService.call(EXEC_TYPE.EXEC, command); executorProgramService.call(EXEC_TYPE.EXEC, command, undefined ,id);
return Result.ok("ok"); return Result.ok("ok");
} catch (error) { } catch (error) {

View file

@ -6,7 +6,6 @@ import { MongoIdValidation } from "../../../core/validations/mongo_id_validation
import { DatasetDBModel } from "../models/dataset_database_model"; import { DatasetDBModel } from "../models/dataset_database_model";
import { IDatasetModel } from "../models/dataset_validation_model"; import { IDatasetModel } from "../models/dataset_validation_model";
import { ProcessWatcherAndDatabaseUpdateService } from "./create_dataset_scenario"; import { ProcessWatcherAndDatabaseUpdateService } from "./create_dataset_scenario";
import { UpdateDataBaseModelUseCase } from "../../../core/usecases/update_database_model_usecase";
export class ExecDatasetProcessScenario extends CallbackStrategyWithIdQuery { export class ExecDatasetProcessScenario extends CallbackStrategyWithIdQuery {
idValidationExpression = new MongoIdValidation(); idValidationExpression = new MongoIdValidation();
@ -18,6 +17,7 @@ export class ExecDatasetProcessScenario extends CallbackStrategyWithIdQuery {
return new ExecProcessUseCase().call( return new ExecProcessUseCase().call(
`${model.project.rootDir}/`, `${model.project.rootDir}/`,
`python3 $PYTHON_BLENDER_PROC --path '${model.project.rootDir}/${model.name}/'`, `python3 $PYTHON_BLENDER_PROC --path '${model.project.rootDir}/${model.name}/'`,
id,
new ProcessWatcherAndDatabaseUpdateService(id as unknown as ObjectId) new ProcessWatcherAndDatabaseUpdateService(id as unknown as ObjectId)
); );
}); });

View file

@ -18,6 +18,7 @@ export class UploadCadFileToProjectScenario extends CallbackStrategyWithFileUplo
async () => async () =>
await new ExecProcessUseCase().call( await new ExecProcessUseCase().call(
`${databaseModel.rootDir}/`, `${databaseModel.rootDir}/`,
'',
`python3 $PYTHON_BLENDER --path '${databaseModel.rootDir}/assets/'` `python3 $PYTHON_BLENDER --path '${databaseModel.rootDir}/assets/'`
) )
) )

View file

@ -3,10 +3,10 @@ import { App } from "./core/controllers/app";
import { SocketSubscriber } from "./core/controllers/socket_controller"; import { SocketSubscriber } from "./core/controllers/socket_controller";
import { extensions } from "./core/extensions/extensions"; import { extensions } from "./core/extensions/extensions";
import { httpRoutes } from "./core/controllers/routes"; import { httpRoutes } from "./core/controllers/routes";
import { pipelineRealTimeService } from "./features/_realtime/realtime_presentation"; import { executorProgramService } from "./core/usecases/exec_process_usecase";
extensions(); extensions();
const socketSubscribers = [new SocketSubscriber(pipelineRealTimeService, "realtime")]; const socketSubscribers = [new SocketSubscriber(executorProgramService, "realtime")];
new App(httpRoutes, socketSubscribers).listen(); new App(httpRoutes, socketSubscribers).listen();

View file

@ -26,6 +26,7 @@ declare global {
toPx(): string; toPx(): string;
unixFromDate(): string; unixFromDate(): string;
isValid(str: string): boolean; isValid(str: string): boolean;
randRange(min:number,max:number):number
} }
interface String { interface String {

View file

@ -24,4 +24,10 @@ export const NumberExtensions = () => {
return !isNaN(Number(str)); 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;
}
}
}; };

View file

@ -1,14 +1,30 @@
import { Socket, io } from "socket.io-client"; 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<any> {
serverURL = "ws://localhost:4001"; serverURL = "ws://localhost:4001";
socket: Socket | undefined; socket: Socket | undefined;
async connect() {
async connect():Promise<Result<boolean, boolean>> {
const socket = io(this.serverURL); const socket = io(this.serverURL);
this.socket = socket; this.socket = socket;
socket.connect(); socket.connect();
socket.on('realtime', (d) =>{ socket.on('realtime', (d) =>{
console.log("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()

View file

@ -1,6 +1,5 @@
import React from "react"; import * as React from "react";
import { CoreText, CoreTextType } from "../text/text"; import { CoreText, CoreTextType } from "../text/text";
import { Input } from "antd";
interface IInputProps { interface IInputProps {
label: string; label: string;
@ -10,15 +9,18 @@ interface IInputProps {
validation?: (value: string) => boolean; validation?: (value: string) => boolean;
error?: string; error?: string;
} }
export const CoreInput = (props: IInputProps) => {
const [key, setKey] = React.useState<undefined | string>(undefined);
export const CoreInput = (props: IInputProps) => {
const [value, setValue] = React.useState<string>(() => props.value ?? "");
const ref = React.useRef<HTMLDivElement>(null);
const [isAppendInnerText, setAppendInnerText] = React.useState(true);
React.useEffect(() => { React.useEffect(() => {
setKey(props.value); if (ref.current && isAppendInnerText) {
return () => { ref.current.innerText = value;
setKey(undefined); setAppendInnerText(false);
}; }
}, [key, setKey, props]); }, [ref, value, isAppendInnerText, setAppendInnerText]);
return ( return (
<div <div
@ -35,8 +37,7 @@ export const CoreInput = (props: IInputProps) => {
> >
<CoreText type={CoreTextType.small} text={props.label} /> <CoreText type={CoreTextType.small} text={props.label} />
<Input <input
key={key}
defaultValue={props.value} defaultValue={props.value}
style={{ style={{
backgroundColor: "#00008000", backgroundColor: "#00008000",
@ -46,9 +47,12 @@ export const CoreInput = (props: IInputProps) => {
color: "#1D1B20", color: "#1D1B20",
height: 24, height: 24,
width: "100%", width: "100%",
userSelect: 'none',
outline:'none'
}} }}
onChange={(e) => { onChange={(e) => {
const val = e.target.value; const val = e.target.value;
setValue(val)
if (val) { if (val) {
if (props.validation !== undefined && props.validation(val) && props.onChange) { if (props.validation !== undefined && props.validation(val) && props.onChange) {
props.onChange(val); props.onChange(val);
@ -62,9 +66,9 @@ export const CoreInput = (props: IInputProps) => {
} }
}} }}
/> />
{props.value ? ( {value ? (
props.validation ? ( props.validation ? (
props.validation(props.value) ? null : ( props.validation(value) ? null : (
<div style={{ color: "#ff1d0c" }}>{props.error ? props.error : "error"}</div> <div style={{ color: "#ff1d0c" }}>{props.error ? props.error : "error"}</div>
) )
) : null ) : null

View file

@ -62,6 +62,7 @@ export const DataSetScreen: React.FunctionComponent = observer(() => {
/> />
<Drawer <Drawer
title={DrawersDataset.FormBuilderDrawer} title={DrawersDataset.FormBuilderDrawer}
destroyOnClose={true}
onClose={() => store.editDrawer(DrawersDataset.FormBuilderDrawer, false)} onClose={() => store.editDrawer(DrawersDataset.FormBuilderDrawer, false)}
open={store.drawers.find((el) => el.name === DrawersDataset.FormBuilderDrawer)?.status ?? false} open={store.drawers.find((el) => el.name === DrawersDataset.FormBuilderDrawer)?.status ?? false}
> >
@ -84,6 +85,7 @@ export const DataSetScreen: React.FunctionComponent = observer(() => {
</Drawer> </Drawer>
<Drawer <Drawer
title={DrawersDataset.NewDataset} title={DrawersDataset.NewDataset}
destroyOnClose={true}
onClose={() => store.editDrawer(DrawersDataset.NewDataset, false)} onClose={() => store.editDrawer(DrawersDataset.NewDataset, false)}
open={store.drawers.find((el) => el.name === DrawersDataset.NewDataset)?.status} open={store.drawers.find((el) => el.name === DrawersDataset.NewDataset)?.status}
> >

View file

@ -2,9 +2,10 @@ import makeAutoObservable from "mobx-store-inheritance";
import { DataSetRepository } from "./dataset_repository"; import { DataSetRepository } from "./dataset_repository";
import { UiErrorState } from "../../core/store/base_store"; import { UiErrorState } from "../../core/store/base_store";
import { HttpError } from "../../core/repository/http_repository"; 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 { message } from "antd";
import { UUID } from "../all_projects/data/project_repository"; import { UUID } from "../all_projects/data/project_repository";
import { SocketRepository, socketRepository } from "../../core/repository/socket_repository";
export enum DrawersDataset { export enum DrawersDataset {
NewDataset = "Новый датасет", NewDataset = "Новый датасет",
@ -21,9 +22,10 @@ export class DataSetStore extends UiErrorState<HttpError> {
activeProject: UUID; activeProject: UUID;
dataSetModel = DataSetModel.empty(); dataSetModel = DataSetModel.empty();
drawers: Drawer[]; drawers: Drawer[];
socketRepository: SocketRepository;
constructor() { constructor() {
super(); super();
this.socketRepository = socketRepository;
this.dataSetRepository = new DataSetRepository(); this.dataSetRepository = new DataSetRepository();
this.drawers = Object.entries(DrawersDataset).map((k, v) => { this.drawers = Object.entries(DrawersDataset).map((k, v) => {
return { return {
@ -32,8 +34,25 @@ export class DataSetStore extends UiErrorState<HttpError> {
}; };
}); });
makeAutoObservable(this); 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() { openEmptyCard() {
this.dataSetModel = DataSetModel.empty(); this.dataSetModel = DataSetModel.empty();
this.editDrawer(DrawersDataset.NewDataset, true); this.editDrawer(DrawersDataset.NewDataset, true);
@ -74,7 +93,6 @@ export class DataSetStore extends UiErrorState<HttpError> {
editDataset(id: string) { editDataset(id: string) {
this.dataSetModel = DataSetModel.fromIDatasetModel(this.datasets?.find((el) => el._id === id) as IDatasetModel); this.dataSetModel = DataSetModel.fromIDatasetModel(this.datasets?.find((el) => el._id === id) as IDatasetModel);
console.log(this.dataSetModel.name);
this.editDrawer(DrawersDataset.NewDataset, true); this.editDrawer(DrawersDataset.NewDataset, true);
} }
@ -93,6 +111,7 @@ export class DataSetStore extends UiErrorState<HttpError> {
async (s) => { async (s) => {
(await this.dataSetRepository.execDatasetProcess(id)).fold( (await this.dataSetRepository.execDatasetProcess(id)).fold(
() => { () => {
this.updateDatasetStatus(id,ProcessStatus.RUN)
message.success("Процесс запущен"); message.success("Процесс запущен");
}, },
(e) => message.error(e.message) (e) => message.error(e.message)

View file

@ -9,7 +9,7 @@ export interface ISocketListerProps {
export const SocketLister = observer((props: ISocketListerProps) => { export const SocketLister = observer((props: ISocketListerProps) => {
return ( return (
<> <div>
{socketListerStore.socketHasDisconnect ? ( {socketListerStore.socketHasDisconnect ? (
<ReloadIcon <ReloadIcon
onClick={() => { onClick={() => {
@ -28,6 +28,6 @@ export const SocketLister = observer((props: ISocketListerProps) => {
)} )}
{props.children} {props.children}
</> </div>
); );
}); });

View file

@ -1,5 +1,5 @@
import { makeAutoObservable } from "mobx"; import { makeAutoObservable } from "mobx";
import { SocketRepository } from "../../core/repository/socket_repository"; import { SocketRepository, socketRepository } from "../../core/repository/socket_repository";
class SocketListerStore { class SocketListerStore {
repository: SocketRepository; repository: SocketRepository;
@ -8,13 +8,22 @@ class SocketListerStore {
constructor(repository: SocketRepository) { constructor(repository: SocketRepository) {
this.repository = repository; this.repository = repository;
makeAutoObservable(this); makeAutoObservable(this);
repository.connect() this.init();
}
async init() {
(await this.repository.connect()).fold(
() => {
this.socketHasDisconnect = false
},
() => {
this.socketHasDisconnect = true
}
);
} }
async reconnect() { async reconnect() {
await this.repository.connect() await this.repository.connect();
this.socketHasDisconnect = false this.socketHasDisconnect = false;
} }
} }
export const socketListerStore = new SocketListerStore(new SocketRepository()); export const socketListerStore = new SocketListerStore(socketRepository);