This commit is contained in:
IDONTSUDO 2024-11-27 19:29:49 +03:00
parent 3f951d1c09
commit 28c36ae710
31 changed files with 495 additions and 65 deletions

26
server/command.json Normal file
View file

@ -0,0 +1,26 @@
{
"tensorBoard": {
"execCommand": "nix run github:nixos/nixpkgs#python312Packages.tensorboard -- --logdir ${dir_path}",
"date": null,
"status": "Fail,Ok",
"delay": 200,
"checkCommand": null,
"filter": null
},
"simulationProcess": {
"execCommand": "nix run github:nixos/nixpkgs#python312Packages.tensorboard -- --logdir ${dir_path}",
"date": null,
"status": null,
"delay": 0,
"checkCommand": null,
"filter": null
},
"btBuilderProcess": {
"execCommand": "nix run github:nixos/nixpkgs#python312Packages.tensorboard -- --logdir ${dir_path}",
"date": null,
"status": null,
"delay": 0,
"checkCommand": null,
"filter": null
}
}

View file

@ -34,6 +34,33 @@ export abstract class CallbackStrategyWithFilesUploads {
abstract call(files: File[]): ResponseBase;
}
export class SubRouter<A> implements ISubSetFeatureRouter<A> {
method: HttpMethodType;
subUrl: string;
fn:
| CallbackStrategyWithValidationModel<A>
| CallbackStrategyWithEmpty
| CallbackStrategyWithIdQuery
| CallBackStrategyWithQueryPage
| CallbackStrategyWithFileUpload
| CallbackStrategyWithFilesUploads;
constructor(
method: HttpMethodType,
subUrl: string,
fn:
| CallbackStrategyWithValidationModel<A>
| CallbackStrategyWithEmpty
| CallbackStrategyWithIdQuery
| CallBackStrategyWithQueryPage
| CallbackStrategyWithFileUpload
| CallbackStrategyWithFilesUploads
) {
this.fn = fn;
this.subUrl = subUrl;
this.method = method;
}
}
interface ISubSetFeatureRouter<A> {
method: HttpMethodType;
subUrl: string;
@ -118,7 +145,7 @@ export class CoreHttpController<V> implements ICoreHttpController {
await this.responseHelper(res, el.fn.call());
return;
}
if (el.fn instanceof CallbackStrategyWithFileUpload) {
if (req["files"] === undefined) {
res.status(400).json("need files to form-data request");

View file

@ -10,6 +10,7 @@ import { DigitalTwinsInstancePresentation } from "../../features/digital_twins_i
import { DigitalTwinsTemplatePresentation } from "../../features/digital_twins_template/digital_twins_template_presentation";
import { TopicsPresentation } from "../../features/topics/topics_presentation";
import { SkillsPresentation } from "../../features/skills/skill_presentation";
import { RunTimePresentation } from "../../features/runtime/runtime_presentation";
extensions();
@ -24,4 +25,5 @@ export const httpRoutes: Routes[] = [
new DigitalTwinsInstancePresentation(),
new TopicsPresentation(),
new SkillsPresentation(),
new RunTimePresentation(),
].map((el) => el.call());

View file

@ -41,7 +41,7 @@ export class ExecutorProgramService
await delay(300);
this.worker = worker;
const workerDataExec: WorkerDataExec = {
command: command,
execPath: this.execPath,
@ -50,6 +50,7 @@ export class ExecutorProgramService
};
worker.send(workerDataExec);
worker.on("message", (e) => {
console.log(JSON.stringify(e));
const spawnError = SpawnError.isError(e);
if (spawnError instanceof SpawnError) {
@ -60,7 +61,7 @@ export class ExecutorProgramService
const execError = ExecError.isExecError(e);
if (execError instanceof ExecError) {
execError.id = id
execError.id = id;
this.emit(Result.error(execError));
this.worker = undefined;
return;
@ -68,7 +69,7 @@ export class ExecutorProgramService
const executorResult = ExecutorResult.isExecutorResult(e);
if (executorResult instanceof ExecutorResult) {
executorResult.id = id
executorResult.id = id;
this.emit(Result.ok(executorResult));
this.worker = undefined;
return;
@ -103,7 +104,8 @@ export class ExecutorProgramService
return;
}
this.workerExecuted(command, WorkerType.SPAWN, args, id);
const commands = command.split(" ");
this.workerExecuted(commands.at(0), WorkerType.SPAWN, commands.slice(1, commands.length), id);
return;
}

View file

@ -1,7 +1,8 @@
import * as cp from "child_process";
import { CallbackStrategyWithEmpty } from "../controllers/http_controller";
import { Result } from "../helpers/result";
import { TypedEvent } from "../helpers/typed_event";
import { EXEC_TYPE, ExecError, SpawnError } from "../models/exec_error_model";
import { EXEC_EVENT, EXEC_TYPE, ExecError, SpawnError } from "../models/exec_error_model";
import { ExecutorResult } from "../models/executor_result";
import { ExecutorProgramService } from "../services/executor_program_service";
@ -26,7 +27,7 @@ export class ExecProcessUseCase {
call = async (
path: string,
command: string,
id:string,
id: string,
watcher?: TypedEvent<Result<ExecError | SpawnError, ExecutorResult>>
): Promise<Result<Error, string>> => {
try {
@ -34,7 +35,7 @@ export class ExecProcessUseCase {
executorProgramService.on((event) => {
if (watcher) watcher.emit(event);
});
executorProgramService.call(EXEC_TYPE.EXEC, command, undefined ,id);
executorProgramService.call(EXEC_TYPE.EXEC, command, undefined, id);
return Result.ok("ok");
} catch (error) {
@ -42,3 +43,38 @@ export class ExecProcessUseCase {
}
};
}
export class SpawnProcessUseCase {
call = async (
path: string,
command: string,
id: string,
watcher?: TypedEvent<Result<ExecError | SpawnError, ExecutorResult>>
): Promise<Result<Error, string>> => {
try {
const commands = command.split(" ");
const subprocess = cp.spawn(commands.at(0), commands.slice(1, commands.length), {
cwd: path,
});
const sendWatcher = (event: Buffer) => {
if (watcher) {
watcher.emit(Result.ok(new ExecutorResult(EXEC_TYPE.SPAWN, EXEC_EVENT.PROGRESS, event.toString())));
}
};
subprocess.stdout.on("data", (data) => sendWatcher(data));
subprocess.stderr.on("data", (data) => sendWatcher(data));
subprocess.on("error", (error) => {
console.error(`Ошибка: ${error.message}`);
});
subprocess.on("close", (code) => {
console.log(`Процесс завершился с кодом: ${code}`);
});
} catch (error) {
return Result.error(error);
}
};
}

View file

@ -15,8 +15,7 @@ export class ExecCalculationInstanceProcessScenario extends CallbackStrategyWith
return (await new IsHaveActiveProcessUseCase().call()).map(async () => {
const execCommand = `${model.script} --form '${JSON.stringify(
model.formBuilder
)}' --path ${model.instancePath.normalize()}`;
console.log(execCommand);
)}' --path ${model.instancePath.pathNormalize()}`;
await CalculationInstanceDBModel.findById(id).updateOne({
processStatus: "RUN",
lastProcessExecCommand: execCommand,

View file

@ -21,10 +21,13 @@ export class ExecInstanceScenario extends CallbackStrategyWithIdQuery {
await new ReadByIdDataBaseModelUseCase<IDigitalTwinsInstanceModel>(DigitalTwinsInstanceDatabaseModel).call(id)
).map(
(document) => (
console.log(JSON.stringify(document)),
console.log('DOCUMeNT PATH'),
console.log(document.instancePath.pathNormalize()),
new ExecProcessUseCase().call(
document.instancePath,
`python3 $GET_INTERFACES --path ${document.instancePath.pathNormalize()} --package '${JSON.stringify(document)}'`,
`python3 $GET_INTERFACES --path ${document.instancePath.pathNormalize()} --package '${JSON.stringify(
document
)}'`,
"",
new ExecInstanceTwinsProcessService(document.instancePath, document)
)

View file

@ -27,10 +27,11 @@ export class RobossemblerAssetsLocaleMapperScenario extends CallbackStrategyWith
)
).map(async (projectModel) => {
const { rootDir } = projectModel[0];
return (await new ReadFileAndParseJsonUseCase().call<Parts[]>(rootDir + StaticFilesProject.parts)).map(
(model) => {
return (await new ReadFileAndParseJsonUseCase().call<Parts[]>(rootDir + StaticFilesProject.parts)).map((model) =>
Result.ok(
model.map((el) => {
const assetLibsAddress = rootDir + "/libs/objects/" + el.name;
const assetLibsAddress = rootDir + "/assets/libs/objects/" + el.name;
console.log(assetLibsAddress);
el.fbx = `${assetLibsAddress}.fbx`;
el.stlUrl = `${assetLibsAddress}${el.part_path}`;
el.glUrl = `${assetLibsAddress}.glb`;
@ -38,11 +39,11 @@ export class RobossemblerAssetsLocaleMapperScenario extends CallbackStrategyWith
el.objUrl = `${assetLibsAddress}.obj`;
el.image = `${assetLibsAddress}.png`;
el.solidType = "active";
return el;
});
return Result.ok(model);
}
})
)
);
// );
});
}

View file

@ -34,8 +34,8 @@ export class RobossemblerAssetsNetworkMapperScenario extends CallbackStrategyWit
rootDir.match(new RegExp(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gm))[0] +
"/assets/";
model.map((el) => {
const assetLibsAddress = assetAddress + "libs/objects/" + el.name;
const assetLibsAddress = assetAddress + "/libs/objects/" + el.name;
console.log(assetLibsAddress);
el.stlUrl = `${assetAddress}${el.part_path}`;
el.glUrl = `${assetLibsAddress}.glb`;
el.daeUrl = `${assetLibsAddress}.dae`;

View file

@ -0,0 +1,7 @@
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
export class ExecBtBuilderUseCase extends CallbackStrategyWithEmpty {
call(): ResponseBase {
throw new Error("Method not implemented.");
}
}

View file

@ -0,0 +1,21 @@
import { App } from "../../../core/controllers/app";
import { CallbackStrategyWithValidationModel, ResponseBase } from "../../../core/controllers/http_controller";
import { Result } from "../../../core/helpers/result";
import { SpawnProcessUseCase } from "../../../core/usecases/exec_process_usecase";
import { ExecProcesssss } from "../model/exec_process";
import { ProcessWatcher } from "../service/process_watcher";
import { GetCommandScenario } from "./get_command_scenario";
export class ExecSimulationUseCase extends CallbackStrategyWithValidationModel<ExecProcesssss> {
validationModel = new ExecProcesssss();
call = async (): ResponseBase =>
(await new GetCommandScenario().call("btBuilderProcess")).map((el) => {
new SpawnProcessUseCase().call(
App.staticFilesStoreDir(),
el.execCommand.replace("${dir_path}", "/Users/idontsudo/train"),
"btBuilder",
new ProcessWatcher(2000, "localhost")
);
return Result.ok("200");
});
}

View file

@ -0,0 +1,7 @@
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
export class GetBtBuilderStateUseCase extends CallbackStrategyWithEmpty {
call(): ResponseBase {
throw new Error("Method not implemented.");
}
}

View file

@ -0,0 +1,14 @@
import { ReadFileAndParseJsonUseCase } from "../../../core/usecases/read_file_and_parse_json";
import { Result } from "../../../core/helpers/result";
import { Command, ExecProcess } from "../model/command";
export class GetCommandScenario {
call = async (command: string): Promise<Result<unknown, ExecProcess>> =>
(
await new ReadFileAndParseJsonUseCase().call<Command>(
__filename.slice(0, __filename.lastIndexOf("/")).replace("/build/src/features/runtime/domain", "") +
"/" +
"command.json"
)
).map((el) => Result.ok(el[command]));
}

View file

@ -0,0 +1,10 @@
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
import { Result } from "../../../core/helpers/result";
import { SpawnProcessUseCase } from "../../../core/usecases/exec_process_usecase";
import { GetCommandScenario } from "./get_command_scenario";
import { ProcessWatcher } from "../service/process_watcher";
import { App } from "../../../core/controllers/app";
export class GetSimulationStateScenario extends CallbackStrategyWithEmpty {
call = async (): ResponseBase => Result.ok("");
}

View file

@ -0,0 +1,14 @@
export interface Command {
tensorBoard: ExecProcess;
simulationProcess: ExecProcess;
btBuilderProcess: ExecProcess;
}
export interface ExecProcess {
execCommand: string;
date: null;
status: null | string;
delay: number;
checkCommand: null;
filter: null;
}

View file

@ -0,0 +1,3 @@
export class ExecProcesssss{
}

View file

@ -0,0 +1,23 @@
import { Schema, model } from "mongoose";
import { ExecRunTimeCommandValidationModel as ExecRunTimeCommandValidationModel } from "./run_time_validation_model";
export interface IDigitalTwinsInstanceModel {
instancePath: string;
status?: string;
}
export const ExecRunTimeDataBaseSchema = new Schema({
execCommand: String,
date: String,
status: String,
delay: Number,
checkCommand: String,
filter: Array,
}).plugin(require("mongoose-autopopulate"));
export const ExecRuntimeSchema = "digital_twins_instance";
export const ExecRuntimeDatabaseModel = model<ExecRunTimeCommandValidationModel>(
ExecRuntimeSchema,
ExecRunTimeDataBaseSchema
);

View file

@ -0,0 +1,21 @@
import { IsArray, IsEnum, IsNumber, IsString } from "class-validator";
export enum Status {
OK = "Ok",
ERROR = "Error",
}
export class ExecRunTimeCommandValidationModel {
@IsString()
execCommand: string;
@IsString()
date: string = Date();
@IsEnum(Status)
status: Status;
@IsNumber()
delay: number;
@IsString()
checkCommand: string;
@IsArray()
filter: string[] = [];
}

View file

@ -0,0 +1,25 @@
import { CrudController } from "../../core/controllers/crud_controller";
import { ExecRunTimeCommandValidationModel } from "./model/run_time_validation_model";
import { ExecRuntimeDatabaseModel } from "./model/run_time_database_model";
import { CoreHttpController, SubRouter, HttpMethodType } from "../../core/controllers/http_controller";
import { ExecBtBuilderUseCase } from "./domain/exec_bt_builder_usecase";
import { ExecSimulationUseCase } from "./domain/exec_simulation_usecase";
import { GetBtBuilderStateUseCase } from "./domain/get_bt_builder_status_usecase";
import { GetSimulationStateScenario } from "./domain/get_simulation_state_usecase";
export class RunTimePresentation extends CoreHttpController<ExecRunTimeCommandValidationModel> {
constructor() {
super({
url: "run_time",
});
this.subRoutes.push(new SubRouter("POST", "/exec/bt/builder", new ExecBtBuilderUseCase()));
this.subRoutes.push(new SubRouter("POST", "/get/bt/builder/state", new GetBtBuilderStateUseCase()));
this.subRoutes.push(new SubRouter("POST", "/get/simulator/state", new GetSimulationStateScenario()));
this.subRoutes.push({
method: "POST",
subUrl: "/exec/simulation/",
fn: new ExecSimulationUseCase(),
});
}
}

View file

@ -0,0 +1,22 @@
import { Result } from "../../../core/helpers/result";
import { TypedEvent } from "../../../core/helpers/typed_event";
import { ExecError, SpawnError } from "../../../core/models/exec_error_model";
import { ExecutorResult } from "../../../core/models/executor_result";
export class ProcessWatcher extends TypedEvent<Result<ExecError | SpawnError, ExecutorResult>> {
logs = "";
delay: number;
constructor(delay: number, pattern: string) {
super();
this.on(this.lister);
setTimeout(() => {
console.log(this.logs);
}, delay);
}
lister = (event: Result<ExecError | SpawnError, ExecutorResult>) => {
event.map(async (success) => {
this.logs += success.data;
});
};
}

10
server/src/p.json Normal file
View file

@ -0,0 +1,10 @@
{
"execCommand": "string",
"date": "date",
"status": "Fail,Ok",
"delay": 1000,
"checkCommand": "string",
"filter": [
"/assembly_config"
]
}