process
This commit is contained in:
parent
7ff6165882
commit
ae9842d5e1
61 changed files with 929 additions and 433 deletions
|
@ -85,7 +85,7 @@ export class App extends TypedEvent<ServerStatus> {
|
|||
this.app.use(cors());
|
||||
this.app.use(express.json());
|
||||
this.app.use(express.urlencoded({ extended: true }));
|
||||
this.app.use(express.static("public"));
|
||||
this.app.use(express.static(App.staticFilesStoreDir()));
|
||||
|
||||
this.app.use(
|
||||
fileUpload({
|
||||
|
@ -118,6 +118,7 @@ export class App extends TypedEvent<ServerStatus> {
|
|||
static staticFilesStoreDir = () => {
|
||||
const dir = dirname(__filename);
|
||||
const rootDir = dir.slice(0, dir.length - 20);
|
||||
|
||||
return rootDir + "public/";
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@ import { validationModelMiddleware } from "../middlewares/validation_model";
|
|||
import { Result } from "../helpers/result";
|
||||
import { Router, Request, Response } from "express";
|
||||
import { IRouteModel, Routes } from "../interfaces/router";
|
||||
import { CoreValidation } from "../validations/core_validation";
|
||||
|
||||
export type HttpMethodType = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "PATCH" | "HEAD";
|
||||
|
||||
export type ResponseBase = Promise<Result<any, any>>;
|
||||
|
||||
export abstract class CallbackStrategyWithEmpty {
|
||||
abstract call(): ResponseBase;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ export abstract class CallbackStrategyWithValidationModel<V> {
|
|||
abstract call(a: V): ResponseBase;
|
||||
}
|
||||
export abstract class CallbackStrategyWithIdQuery {
|
||||
abstract idValidationExpression: RegExp | null;
|
||||
abstract idValidationExpression: CoreValidation;
|
||||
abstract call(id: string): ResponseBase;
|
||||
}
|
||||
export abstract class CallBackStrategyWithQueryPage {
|
||||
|
@ -84,7 +84,24 @@ export class CoreHttpController<V> implements ICoreHttpController {
|
|||
throw Error("needs to be implimed");
|
||||
}
|
||||
if (el.fn instanceof CallbackStrategyWithIdQuery) {
|
||||
throw Error("needs to be implimed");
|
||||
if (req.query.id === undefined) {
|
||||
res.status(400).json("request query id is null, need query id ?id={id:String}");
|
||||
return;
|
||||
}
|
||||
if (el.fn.idValidationExpression !== undefined) {
|
||||
if (!el.fn.idValidationExpression.regExp.test(req.query.id)) {
|
||||
res
|
||||
.status(400)
|
||||
.json(
|
||||
`request query id must fall under the pattern: ${el.fn.idValidationExpression.regExp} message: ${el.fn.idValidationExpression.message} `
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
await this.responseHelper(res, el.fn.call(req.query.id));
|
||||
}
|
||||
} else {
|
||||
await this.responseHelper(res, el.fn.call(req["files"]["file"]));
|
||||
}
|
||||
}
|
||||
if (el.fn instanceof CallBackStrategyWithQueryPage) {
|
||||
throw Error("needs to be implimed");
|
||||
|
|
|
@ -20,6 +20,7 @@ declare global {
|
|||
lastElement(): string;
|
||||
hasPattern(pattern: string): boolean;
|
||||
hasNoPattern(pattern: string): boolean;
|
||||
pathNormalize(): string;
|
||||
}
|
||||
}
|
||||
export const extensions = () => {
|
||||
|
|
|
@ -5,6 +5,11 @@ export const StringExtensions = () => {
|
|||
return this.length === 0;
|
||||
};
|
||||
}
|
||||
if ("".pathNormalize === undefined) {
|
||||
String.prototype.pathNormalize = function () {
|
||||
return this.replace("//", "/");
|
||||
};
|
||||
}
|
||||
if ("".isNotEmpty === undefined) {
|
||||
// eslint-disable-next-line no-extend-native
|
||||
String.prototype.isNotEmpty = function () {
|
||||
|
@ -27,3 +32,6 @@ export const StringExtensions = () => {
|
|||
};
|
||||
}
|
||||
};
|
||||
// python3 /Users/idontsudo/framework/path.py --path /Users/idontsudo/webservice/server/build/public/0a3422cc-f2e3-4abc-87d8-ae13b8b6d26d/ --env /Users/idontsudo/framework/cad_generation/env.json
|
||||
// python3 /Users/idontsudo/framework/path.py --path /Users/idontsudo/webservice/server/build/public/0a3422cc-f2e3-4abc-87d8-ae13b8b6d26d/ --env /Users/idontsudo/framework/cad_generation/env.json
|
||||
// /Users/idontsudo/Desktop/FreeCAD.app/Contents/MacOS/FreeCAD /Users/idontsudo/framework/cad_generation/main.py
|
||||
|
|
|
@ -17,7 +17,9 @@ export interface WorkerDataExec {
|
|||
process.on("message", async (message) => {
|
||||
const workerData = message as WorkerDataExec;
|
||||
if (workerData.type == WorkerType.SPAWN) {
|
||||
const subprocess = cp.spawn(workerData.command, workerData.cliArgs, {
|
||||
// Maybe error
|
||||
// const subprocess = cp.spawn(workerData.command, workerData.cliArgs, {
|
||||
const subprocess = cp.spawn(workerData.command, {
|
||||
cwd: workerData.execPath,
|
||||
});
|
||||
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
import { RequestHandler } from "express";
|
||||
|
||||
export const validationMiddleware = (
|
||||
type: any,
|
||||
value = "body",
|
||||
skipMissingProperties = false,
|
||||
whitelist = true,
|
||||
forbidNonWhitelisted = true
|
||||
): RequestHandler => {
|
||||
export const validationMiddleware = (): RequestHandler => {
|
||||
// TODO:(IDONTSUDO) need TOKEN
|
||||
// return nextTick
|
||||
return (req, res, next) => {};
|
||||
|
|
|
@ -4,10 +4,15 @@ extensions();
|
|||
|
||||
export class ExecError extends Error {
|
||||
static isExecError(e: any): ExecError | void {
|
||||
if ("type" in e && "script" in e && "unixTime" in e && "error" in e) {
|
||||
return new ExecError(e.type, e.event, e.data);
|
||||
try {
|
||||
if (e) {
|
||||
if ("type" in e && "script" in e && "unixTime" in e && "error" in e) {
|
||||
return new ExecError(e.type, e.event, e.data);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
script: string;
|
||||
unixTime: number;
|
||||
|
@ -34,10 +39,15 @@ export class SpawnError extends Error {
|
|||
this.unixTime = Date.now();
|
||||
}
|
||||
static isError(errorType: any): SpawnError | void {
|
||||
if ("command" in errorType && "error" in errorType && "execPath" in errorType) {
|
||||
return new SpawnError(errorType.command, errorType.execPath, errorType.error);
|
||||
try {
|
||||
if (errorType) {
|
||||
if ("command" in errorType && "error" in errorType && "execPath" in errorType) {
|
||||
return new SpawnError(errorType.command, errorType.execPath, errorType.error);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,14 @@ export class ExecutorResult {
|
|||
this.data = data;
|
||||
}
|
||||
static isExecutorResult(value: any): void | ExecutorResult {
|
||||
if ("type" in value && "event" in value && "data" in value) {
|
||||
return new ExecutorResult(value.type, value.event, value.data);
|
||||
try {
|
||||
if (value) {
|
||||
if ("type" in value && "event" in value && "data" in value) {
|
||||
return new ExecutorResult(value.type, value.event, value.data);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
131
server/src/core/models/robossembler_assets.ts
Normal file
131
server/src/core/models/robossembler_assets.ts
Normal file
|
@ -0,0 +1,131 @@
|
|||
import { IsEnum, IsNumber, IsOptional, IsString, ValidateNested } from "class-validator";
|
||||
import { Type } from "class-transformer";
|
||||
|
||||
export enum AssetsType {
|
||||
Asset = "asset",
|
||||
Light = "light",
|
||||
}
|
||||
|
||||
export class Gravity {
|
||||
@IsNumber()
|
||||
x: number;
|
||||
@IsNumber()
|
||||
y: number;
|
||||
@IsNumber()
|
||||
z: number;
|
||||
}
|
||||
export class Pose {
|
||||
@IsNumber()
|
||||
x: number;
|
||||
@IsNumber()
|
||||
y: number;
|
||||
@IsNumber()
|
||||
z: number;
|
||||
@IsNumber()
|
||||
roll: number;
|
||||
@IsNumber()
|
||||
pitch: number;
|
||||
@IsNumber()
|
||||
yaw: number;
|
||||
}
|
||||
|
||||
export class Instance {
|
||||
@IsString()
|
||||
model_name: string;
|
||||
@IsString()
|
||||
model_id: string;
|
||||
@IsString()
|
||||
id: string;
|
||||
@ValidateNested()
|
||||
@Type(() => Pose)
|
||||
pose: Pose;
|
||||
@IsNumber()
|
||||
scale: number;
|
||||
@IsEnum(AssetsType)
|
||||
type: AssetsType;
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
parent?: string;
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
light_type?: string;
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
intencity?: number;
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
diffuse?: number[];
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
spot_angle?: number;
|
||||
}
|
||||
|
||||
export class Asset {
|
||||
@IsString()
|
||||
name: string;
|
||||
@IsString()
|
||||
ixx: string;
|
||||
@IsString()
|
||||
ixy: string;
|
||||
@IsString()
|
||||
ixz: string;
|
||||
@IsString()
|
||||
iyy: string;
|
||||
@IsString()
|
||||
izz: string;
|
||||
@IsString()
|
||||
mass: string;
|
||||
@IsString()
|
||||
posX: string;
|
||||
@IsString()
|
||||
posY: string;
|
||||
@IsString()
|
||||
posZ: string;
|
||||
@IsString()
|
||||
eulerX: string;
|
||||
@IsString()
|
||||
eulerY: string;
|
||||
@IsString()
|
||||
eulerZ: string;
|
||||
@IsString()
|
||||
iyz: string;
|
||||
@IsString()
|
||||
meshPath: string;
|
||||
@IsString()
|
||||
friction: string;
|
||||
@IsString()
|
||||
centerMassX: string;
|
||||
@IsString()
|
||||
centerMassY: string;
|
||||
@IsString()
|
||||
centerMassZ: string;
|
||||
}
|
||||
|
||||
export class Physics {
|
||||
@IsString()
|
||||
engine_name: string;
|
||||
@Type(() => Gravity)
|
||||
gravity: Gravity;
|
||||
}
|
||||
|
||||
export class RobossemblerAssets {
|
||||
@ValidateNested()
|
||||
@Type(() => Asset)
|
||||
assets: Asset[];
|
||||
|
||||
@ValidateNested()
|
||||
@Type(() => Instance)
|
||||
instances: Instance[];
|
||||
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => Physics)
|
||||
physics: Physics;
|
||||
convertLocalPathsToServerPaths(server_address: string): RobossemblerAssets {
|
||||
this.assets = this.assets.map((el) => {
|
||||
el.meshPath = server_address + el.meshPath;
|
||||
return el;
|
||||
});
|
||||
return this;
|
||||
}
|
||||
}
|
3
server/src/core/models/static_files.ts
Normal file
3
server/src/core/models/static_files.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export enum StaticFiles {
|
||||
robossembler_assets = "robossembler_assets.json",
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
import { ClassConstructor, plainToInstance } from "class-transformer";
|
||||
import { ReadFileAndParseJsonUseCase } from "../usecases/read_file_and_parse_json";
|
||||
import { Result } from "../helpers/result";
|
||||
import { validate, ValidationError } from "class-validator";
|
||||
const skipMissingProperties = false,
|
||||
whitelist = true,
|
||||
forbidNonWhitelisted = true;
|
||||
|
||||
export class ReadingJsonFileAndConvertingToInstanceClass<T> {
|
||||
model: ClassConstructor<T>;
|
||||
constructor(cls: ClassConstructor<T>) {
|
||||
this.model = cls;
|
||||
}
|
||||
call = async (path: string): Promise<Result<string, T>> => {
|
||||
const result = await new ReadFileAndParseJsonUseCase().call(path);
|
||||
if (result.isFailure()) {
|
||||
return result.forward();
|
||||
}
|
||||
const json = result.value;
|
||||
const model = plainToInstance(this.model, json);
|
||||
const errors = await validate(model as object, { skipMissingProperties, whitelist, forbidNonWhitelisted });
|
||||
if (errors.length > 0) {
|
||||
const message = errors.map((error: ValidationError) => Object.values(error.constraints)).join(", ");
|
||||
return Result.error(message);
|
||||
} else {
|
||||
return Result.ok(model as T);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -4,7 +4,7 @@ import {
|
|||
} from "../../features/project_instance/models/project_instance_database_model";
|
||||
import { pipelineRealTimeService } from "../../features/realtime/realtime_presentation";
|
||||
import { App } from "../controllers/app";
|
||||
import { CreateFolderUseCase } from "../usecases/crete_folder_usecase";
|
||||
import { CreateFolderUseCase } from "../usecases/create_folder_usecase";
|
||||
import { SearchDataBaseModelUseCase } from "../usecases/search_database_model_usecase";
|
||||
|
||||
export class SetLastActivePipelineToRealTimeServiceScenario {
|
||||
|
@ -12,12 +12,11 @@ export class SetLastActivePipelineToRealTimeServiceScenario {
|
|||
const result = await new SearchDataBaseModelUseCase<IProjectInstanceModel>(ProjectInstanceDbModel).call({
|
||||
isActive: true,
|
||||
});
|
||||
|
||||
if (result.isSuccess()) {
|
||||
const projectModel = result.value;
|
||||
const projectPath = App.staticFilesStoreDir() + result.value.rootDir + "/";
|
||||
await result.map(async (el) => {
|
||||
const projectModel = el;
|
||||
const projectPath = App.staticFilesStoreDir() + projectModel.rootDir + "/";
|
||||
await new CreateFolderUseCase().call(projectPath);
|
||||
pipelineRealTimeService.setPipelineDependency(projectModel.project.pipelines, projectPath, projectModel._id);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -21,57 +21,61 @@ export class ExecutorProgramService
|
|||
|
||||
constructor(execPath: string, maxTime: number | null = null) {
|
||||
super();
|
||||
this.execPath = execPath;
|
||||
this.execPath = execPath.pathNormalize();
|
||||
this.maxTime = maxTime;
|
||||
}
|
||||
|
||||
private async workerExecuted(command: string, workerType: WorkerType, args: Array<string> | undefined = undefined) {
|
||||
cluster.setupPrimary({
|
||||
exec: __dirname + "/../helpers/worker_computed.js",
|
||||
});
|
||||
try {
|
||||
cluster.setupPrimary({
|
||||
exec: __dirname + "/../helpers/worker_computed.js",
|
||||
});
|
||||
|
||||
const worker = cluster.fork();
|
||||
const worker = cluster.fork();
|
||||
|
||||
await delay(300);
|
||||
await delay(300);
|
||||
|
||||
this.worker = worker;
|
||||
this.worker = worker;
|
||||
|
||||
const workerDataExec: WorkerDataExec = {
|
||||
command: command,
|
||||
execPath: this.execPath,
|
||||
type: workerType,
|
||||
cliArgs: args,
|
||||
};
|
||||
worker.send(workerDataExec);
|
||||
worker.on("message", (e) => {
|
||||
const spawnError = SpawnError.isError(e);
|
||||
const workerDataExec: WorkerDataExec = {
|
||||
command: command,
|
||||
execPath: this.execPath,
|
||||
type: workerType,
|
||||
cliArgs: args,
|
||||
};
|
||||
worker.send(workerDataExec);
|
||||
worker.on("message", (e) => {
|
||||
const spawnError = SpawnError.isError(e);
|
||||
|
||||
if (spawnError instanceof SpawnError) {
|
||||
this.emit(Result.error(spawnError));
|
||||
return;
|
||||
if (spawnError instanceof SpawnError) {
|
||||
this.emit(Result.error(spawnError));
|
||||
return;
|
||||
}
|
||||
const execError = ExecError.isExecError(e);
|
||||
|
||||
if (execError instanceof ExecError) {
|
||||
this.emit(Result.error(execError));
|
||||
return;
|
||||
}
|
||||
|
||||
const executorResult = ExecutorResult.isExecutorResult(e);
|
||||
if (executorResult instanceof ExecutorResult) {
|
||||
this.emit(Result.ok(executorResult));
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (this.maxTime != null) {
|
||||
setTimeout(() => {
|
||||
this.worker.kill();
|
||||
this.emit(
|
||||
Result.error(
|
||||
WorkerType.EXEC ? new ExecError(command, "timeout err") : new SpawnError(command, "timeout err")
|
||||
)
|
||||
);
|
||||
}, this.maxTime!);
|
||||
}
|
||||
|
||||
const executorResult = ExecutorResult.isExecutorResult(e);
|
||||
|
||||
if (executorResult instanceof ExecutorResult) {
|
||||
this.emit(Result.ok(executorResult));
|
||||
return;
|
||||
}
|
||||
|
||||
const execError = ExecError.isExecError(e);
|
||||
|
||||
if (execError instanceof ExecError) {
|
||||
this.emit(Result.error(execError));
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (this.maxTime != null) {
|
||||
setTimeout(() => {
|
||||
this.worker.kill();
|
||||
this.emit(
|
||||
Result.error(WorkerType.EXEC ? new ExecError(command, "timeout err") : new SpawnError(command, "timeout err"))
|
||||
);
|
||||
}, this.maxTime!);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import { ExecError } from "../models/exec_error_model";
|
|||
import { ExecutorResult } from "../models/executor_result";
|
||||
import { ActivePipeline } from "../models/active_pipeline_model";
|
||||
import { IPipeline } from "../models/process_model";
|
||||
import { Iteration } from "./stack_service";
|
||||
import { Iteration, StackService } from "./stack_service";
|
||||
|
||||
export class PipelineRealTimeService extends TypedEvent<ActivePipeline> {
|
||||
status: ActivePipeline;
|
||||
|
@ -65,9 +65,10 @@ export class PipelineRealTimeService extends TypedEvent<ActivePipeline> {
|
|||
this.status["path"] = path;
|
||||
}
|
||||
runPipeline(): void {
|
||||
// const stack = new StackService(this.pipelineModels, this.path);
|
||||
// this.status["pipelineIsRunning"] = true;
|
||||
// stack.on(this.pipelineSubscriber);
|
||||
// stack.call();
|
||||
const stack = new StackService(this.pipelineModels, this.status.path);
|
||||
|
||||
this.status["pipelineIsRunning"] = true;
|
||||
stack.on(this.pipelineSubscriber);
|
||||
stack.call();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import { Trigger } from "../../features/triggers/models/trigger_database_model";
|
|||
|
||||
export interface Iteration {
|
||||
hashes: IHashesCache | null;
|
||||
process: IPipeline;
|
||||
pipeline: IPipeline;
|
||||
result?: ExecError | SpawnError | ExecutorResult;
|
||||
}
|
||||
|
||||
|
@ -36,12 +36,12 @@ export class StackService extends TypedEvent<Iteration[]> implements IStackServi
|
|||
el = this.commandHandler(el);
|
||||
this.callStack.push({
|
||||
hashes: null,
|
||||
process: el,
|
||||
pipeline: el,
|
||||
});
|
||||
}
|
||||
}
|
||||
private commandHandler(processMetaData: IPipeline) {
|
||||
processMetaData.process.command = processMetaData.process.command.replace("$PATH", this.path);
|
||||
processMetaData.process.command = processMetaData.process.command.replace("$PATH", this.path).pathNormalize();
|
||||
return processMetaData;
|
||||
}
|
||||
public async call() {
|
||||
|
@ -52,10 +52,7 @@ export class StackService extends TypedEvent<Iteration[]> implements IStackServi
|
|||
}
|
||||
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);
|
||||
executorService.on((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
executorService.call(stackLayer.pipeline.process.type, stackLayer.pipeline.process.command);
|
||||
const filesChangeNotifierService = new FilesChangeNotifierService(this.path);
|
||||
|
||||
filesChangeNotifierService.call();
|
||||
|
@ -73,7 +70,7 @@ export class StackService extends TypedEvent<Iteration[]> implements IStackServi
|
|||
result.map(async (el) => {
|
||||
this.callStack.at(stackNumber).result = el;
|
||||
this.callStack.at(stackNumber).hashes = filesChangeNotifierService.hashes;
|
||||
(await this.triggerExec(stackLayer.process.trigger, stackNumber)).map(() => {
|
||||
(await this.triggerExec(stackLayer.pipeline.trigger, stackNumber)).map(() => {
|
||||
filesChangeNotifierService.cancel();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { App } from "../controllers/app";
|
||||
import { FileSystemRepository } from "../repository/file_system_repository";
|
||||
import { CreateFolderUseCase } from "./crete_folder_usecase";
|
||||
import { CreateFolderUseCase } from "./create_folder_usecase";
|
||||
|
||||
export class CheckAndCreateStaticFilesFolderUseCase {
|
||||
fileSystemRepository: FileSystemRepository;
|
||||
|
|
|
@ -9,7 +9,7 @@ export class CreateFolderUseCase {
|
|||
call = async (path: string): Promise<Result<Error, string>> => {
|
||||
try {
|
||||
if (await this.fileSystemRepository.dirIsExists(path)) {
|
||||
return Result.error(new Error("createFolderUseCase create dir "));
|
||||
return Result.ok("ok");
|
||||
}
|
||||
await this.fileSystemRepository.createDir(path);
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
export class FindPredicateModelAndUpdateDatabaseModelUseCase<D> {
|
||||
databaseModel: D;
|
||||
|
||||
constructor(model) {
|
||||
this.databaseModel = model;
|
||||
}
|
||||
async call(conditions: Partial<D>, update: Partial<D>) {
|
||||
const dbModel = this.databaseModel as any;
|
||||
dbModel.findOneAndUpdate(conditions, update);
|
||||
}
|
||||
}
|
7
server/src/core/usecases/get_server_address_usecase.ts
Normal file
7
server/src/core/usecases/get_server_address_usecase.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { Result } from "../helpers/result";
|
||||
|
||||
export class GetServerAddressUseCase {
|
||||
call = (): Result<string, string> => {
|
||||
return Result.ok("http://localhost:4001");
|
||||
};
|
||||
}
|
21
server/src/core/usecases/read_file_and_parse_json.ts
Normal file
21
server/src/core/usecases/read_file_and_parse_json.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { Result } from "../helpers/result";
|
||||
import { FileSystemRepository } from "../repository/file_system_repository";
|
||||
|
||||
export class ReadFileAndParseJsonUseCase {
|
||||
fileSystemRepository: FileSystemRepository;
|
||||
|
||||
constructor() {
|
||||
this.fileSystemRepository = new FileSystemRepository();
|
||||
}
|
||||
async call<T>(path: string): Promise<Result<string, T>> {
|
||||
try {
|
||||
if (RegExp(path).test("^(.+)/([^/]+)$")) {
|
||||
return Result.error(`ReadFileAndParseJsonUseCase got the bad way: ${path}`);
|
||||
}
|
||||
const file = await this.fileSystemRepository.readFileAsync(path);
|
||||
return Result.ok(JSON.parse(file.toString()));
|
||||
} catch (error) {
|
||||
return Result.error(`ReadFileAndParseJsonUseCase is not json type file parse path:${path}`);
|
||||
}
|
||||
}
|
||||
}
|
4
server/src/core/validations/core_validation.ts
Normal file
4
server/src/core/validations/core_validation.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export abstract class CoreValidation {
|
||||
abstract regExp: RegExp;
|
||||
abstract message: string;
|
||||
}
|
6
server/src/core/validations/mongo_id_validation.ts
Normal file
6
server/src/core/validations/mongo_id_validation.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { CoreValidation } from "./core_validation";
|
||||
|
||||
export class MongoIdValidation extends CoreValidation {
|
||||
regExp = RegExp("^[0-9a-fA-F]{24}$");
|
||||
message = "is do not mongo db object uuid";
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import { App } from "../../../core/controllers/app";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { CreateDataBaseModelUseCase } from "../../../core/usecases/create_database_model_usecase";
|
||||
import { CreateFolderUseCase } from "../../../core/usecases/crete_folder_usecase";
|
||||
import { CreateFolderUseCase } from "../../../core/usecases/create_folder_usecase";
|
||||
import { ProjectInstanceDbModel } from "../models/project_instance_database_model";
|
||||
import { ProjectInstanceValidationModel } from "../models/project_instance_validation_model";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { RobossemblerAssets } from "../../../core/models/robossembler_assets";
|
||||
import { StaticFiles } from "../../../core/models/static_files";
|
||||
import { ReadingJsonFileAndConvertingToInstanceClass } from "../../../core/scenarios/read_file_and_json_to_plain_instance_class_scenario";
|
||||
import { GetServerAddressUseCase } from "../../../core/usecases/get_server_address_usecase";
|
||||
import { PipelineStatusUseCase } from "../../realtime/domain/pipeline_status_usecase";
|
||||
|
||||
export class RobossemblerAssetsNetworkMapperScenario extends CallbackStrategyWithEmpty {
|
||||
async call(): ResponseBase {
|
||||
try {
|
||||
const result = await new PipelineStatusUseCase().call();
|
||||
|
||||
return await result.map(async (activeInstanceModel) => {
|
||||
return (
|
||||
await new ReadingJsonFileAndConvertingToInstanceClass(RobossemblerAssets).call(
|
||||
`${activeInstanceModel.path}${StaticFiles.robossembler_assets}`
|
||||
)
|
||||
).map((robossemblerAssets) => {
|
||||
return new GetServerAddressUseCase().call().map((address) => {
|
||||
return Result.ok(
|
||||
robossemblerAssets.convertLocalPathsToServerPaths(`${address}/${activeInstanceModel.projectUUID}`)
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
return Result.error(error);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
import { App } from "../../../core/controllers/app";
|
||||
import { CallbackStrategyWithIdQuery, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { CreateFolderUseCase } from "../../../core/usecases/create_folder_usecase";
|
||||
import { FindPredicateModelAndUpdateDatabaseModelUseCase } from "../../../core/usecases/find_and_update_database_model_usecase";
|
||||
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_by_id_database_model_usecase";
|
||||
import { UpdateDataBaseModelUseCase } from "../../../core/usecases/update_database_model_usecase";
|
||||
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
|
||||
import { IProjectInstanceModel, ProjectInstanceDbModel } from "../models/project_instance_database_model";
|
||||
|
||||
export class SetActiveProjectScenario extends CallbackStrategyWithIdQuery {
|
||||
idValidationExpression = new MongoIdValidation();
|
||||
|
||||
async call(id: string): ResponseBase {
|
||||
const result = await new ReadByIdDataBaseModelUseCase<IProjectInstanceModel>(ProjectInstanceDbModel).call(id);
|
||||
|
||||
if (result.isFailure()) {
|
||||
return result.forward();
|
||||
}
|
||||
|
||||
const model = result.value;
|
||||
return (await new CreateFolderUseCase().call(App.staticFilesStoreDir() + model.rootDir)).map(async () => {
|
||||
model.isActive = true;
|
||||
new FindPredicateModelAndUpdateDatabaseModelUseCase(ProjectInstanceDbModel).call({}, {});
|
||||
return (await new UpdateDataBaseModelUseCase(ProjectInstanceDbModel).call(model)).map(() => {
|
||||
return Result.ok(`project ${id} is active`);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
import { CrudController } from "../../core/controllers/crud_controller";
|
||||
|
||||
import { CreateNewProjectInstanceScenario } from "./domain/create_new_project_scenario";
|
||||
import { RobossemblerAssetsNetworkMapperScenario } from "./domain/robossembler_assets_network_mapper_scenario";
|
||||
import { SetActiveProjectScenario } from "./domain/set_active_project_use_scenario";
|
||||
import { UploadCadFileToProjectScenario } from "./domain/upload_file_to_to_project_scenario";
|
||||
import { ProjectInstanceDbModel } from "./models/project_instance_database_model";
|
||||
import { ProjectInstanceValidationModel } from "./models/project_instance_validation_model";
|
||||
|
@ -14,12 +17,25 @@ export class ProjectInstancePresentation extends CrudController<
|
|||
url: "project_instance",
|
||||
databaseModel: ProjectInstanceDbModel,
|
||||
});
|
||||
|
||||
super.post(new CreateNewProjectInstanceScenario().call);
|
||||
|
||||
this.subRoutes.push({
|
||||
method: "POST",
|
||||
subUrl: "set/active/project",
|
||||
fn: new SetActiveProjectScenario(),
|
||||
});
|
||||
|
||||
this.subRoutes.push({
|
||||
method: "POST",
|
||||
subUrl: "upload",
|
||||
fn: new UploadCadFileToProjectScenario(),
|
||||
});
|
||||
|
||||
this.subRoutes.push({
|
||||
method: "GET",
|
||||
subUrl: "assets",
|
||||
fn: new RobossemblerAssetsNetworkMapperScenario(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ export class PipelineStatusUseCase {
|
|||
if (status.projectUUID !== null) {
|
||||
return Result.ok(status);
|
||||
}
|
||||
|
||||
if (status.projectUUID === null) {
|
||||
return Result.error(new Error("pipelineRealTimeService does not have an active project instance"));
|
||||
}
|
||||
|
|
|
@ -1,39 +1,55 @@
|
|||
import { App } from "../../../core/controllers/app";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { IPipeline } from "../../../core/models/process_model";
|
||||
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_by_id_database_model_usecase";
|
||||
import { UpdateDataBaseModelUseCase } from "../../../core/usecases/update_database_model_usecase";
|
||||
import { PipelineValidationModel } from "../../pipelines/models/pipeline_validation_model";
|
||||
import {
|
||||
IProjectInstanceModel,
|
||||
ProjectInstanceDbModel,
|
||||
} from "../../project_instance/models/project_instance_database_model";
|
||||
import { RealTimeValidationModel, pipelineRealTimeService } from "../realtime_presentation";
|
||||
import { pipelineRealTimeService } from "../realtime_presentation";
|
||||
import { PipelineStatusUseCase } from "./pipeline_status_usecase";
|
||||
|
||||
const mongoPipelineModelMapper = (el: PipelineValidationModel): IPipeline => {
|
||||
const mapObj: IPipeline = {
|
||||
process: {
|
||||
type: el.process.type,
|
||||
command: el.process.command,
|
||||
isGenerating: Boolean(el.process.isGenerating),
|
||||
isLocaleCode: Boolean(el.process.isLocaleCode),
|
||||
issueType: el.process.issueType,
|
||||
},
|
||||
trigger: {
|
||||
type: el.trigger.type,
|
||||
value: el.trigger.value.map((el) => String(el)),
|
||||
},
|
||||
env: null,
|
||||
stackGenerateType: el.stackGenerateType,
|
||||
};
|
||||
return mapObj;
|
||||
};
|
||||
export class RunInstancePipelineUseCase {
|
||||
async call(model: RealTimeValidationModel): Promise<Result<Error, any>> {
|
||||
const { id } = model;
|
||||
async call(): Promise<Result<Error, any>> {
|
||||
const r = await new PipelineStatusUseCase().call();
|
||||
if (r.isFailure()) {
|
||||
return r;
|
||||
}
|
||||
const readByIdDataBaseModelUseCase = await new ReadByIdDataBaseModelUseCase<IProjectInstanceModel>(
|
||||
ProjectInstanceDbModel
|
||||
).call(id);
|
||||
).call(r.value.projectUUID);
|
||||
|
||||
if (readByIdDataBaseModelUseCase.isFailure()) {
|
||||
return readByIdDataBaseModelUseCase.forward();
|
||||
}
|
||||
|
||||
const projectModel = readByIdDataBaseModelUseCase.value;
|
||||
projectModel.isActive = true;
|
||||
const resultMapper = projectModel.project.pipelines.map((el) => mongoPipelineModelMapper(el));
|
||||
|
||||
const updateDataBaseModelUseCase = await new UpdateDataBaseModelUseCase<IProjectInstanceModel, any>(
|
||||
ProjectInstanceDbModel
|
||||
).call(projectModel);
|
||||
|
||||
if (updateDataBaseModelUseCase.isFailure()) {
|
||||
return updateDataBaseModelUseCase.forward();
|
||||
}
|
||||
pipelineRealTimeService.setPipelineDependency(
|
||||
projectModel.project.pipelines,
|
||||
resultMapper,
|
||||
App.staticFilesStoreDir() + projectModel.rootDir + "/",
|
||||
projectModel._id
|
||||
);
|
||||
|
||||
pipelineRealTimeService.runPipeline();
|
||||
|
||||
return Result.ok({ status: "ok" });
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue