Merge branch '3-fix/mvp-backend' into 'main'
Resolve "MVP back end" Closes #3 See merge request robossembler/webservice!3
This commit is contained in:
commit
d89d799e8f
51 changed files with 1048 additions and 426 deletions
36
.vscode/settings.json
vendored
36
.vscode/settings.json
vendored
|
@ -1,20 +1,24 @@
|
||||||
{
|
{
|
||||||
"files.exclude": {
|
"files.exclude": {
|
||||||
"**/.git": false,
|
"server/build/src/core/*controllers.*": true,
|
||||||
"**/.svn": false,
|
"server/build/src/core/*di": true,
|
||||||
"**/.hg": false,
|
"server/build/src/core/*di.*": true,
|
||||||
"**/CVS": false,
|
"server/build/src/core/*extensions": true,
|
||||||
"**/__pycache__": false,
|
"server/build/src/core/*extensions.*": true,
|
||||||
"test/*context.*": false,
|
"server/build/src/core/*helper": true,
|
||||||
"test/*mocks": false,
|
"server/build/src/core/*helper.*": true,
|
||||||
"test/*mocks.*": false,
|
"server/build/src/core/*interfaces": true,
|
||||||
"test/*test": false,
|
"server/build/src/core/*interfaces.*": true,
|
||||||
"test/*test.*": false,
|
"server/build/src/core/*middlewares": true,
|
||||||
"test/*test.js": false,
|
"server/build/src/core/*middlewares.*": true,
|
||||||
"test/*test.js.*": false,
|
"server/build/src/core/*model": true,
|
||||||
"test/*todo": false,
|
"server/build/src/core/*model.*": true,
|
||||||
"test/*todo.*": false,
|
"server/build/src/core/*services": true,
|
||||||
"**/*.js": true,
|
"server/build/src/core/*services.*": true,
|
||||||
"**/*.map": true
|
"server/build/src/core/*usecases": true,
|
||||||
|
"server/build/src/core/*usecases.*": true,
|
||||||
|
"server/src/core/model/exec_error_model.js": true,
|
||||||
|
"**/*.map": true,
|
||||||
|
"**/*.js": true
|
||||||
}
|
}
|
||||||
}
|
}
|
2
server/.gitignore
vendored
2
server/.gitignore
vendored
|
@ -6,3 +6,5 @@ node_modules/
|
||||||
coverage
|
coverage
|
||||||
package-lock.json
|
package-lock.json
|
||||||
.*.swp
|
.*.swp
|
||||||
|
build/
|
||||||
|
model_create.ts
|
|
@ -1,18 +1,20 @@
|
||||||
{
|
{
|
||||||
"name": "step-by-step-server",
|
"name": "step-by-step-server",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"type": "module",
|
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"pretest": "tsc",
|
"pretest": "tsc",
|
||||||
"test": "node ./test/test.js",
|
"test": "ts-node ./build/test/test.js",
|
||||||
"test:watch": "tsc-watch --onSuccess 'node ./test/test.js'"
|
"test:watch": "tsc-watch --onSuccess 'ts-node ./build/test/test.js'",
|
||||||
|
"dev": "tsc-watch --onSuccess 'ts-node ./build/src/main.js'"
|
||||||
},
|
},
|
||||||
"author": "IDONTSUDO",
|
"author": "IDONTSUDO",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testdeck/mocha": "latest",
|
"@testdeck/mocha": "latest",
|
||||||
"@types/chai": "latest",
|
"@types/chai": "latest",
|
||||||
|
"@types/cors": "^2.8.14",
|
||||||
|
"@types/express": "^4.17.18",
|
||||||
"@types/md5": "^2.3.2",
|
"@types/md5": "^2.3.2",
|
||||||
"@types/mocha": "latest",
|
"@types/mocha": "latest",
|
||||||
"@types/node": "^20.4.8",
|
"@types/node": "^20.4.8",
|
||||||
|
@ -23,20 +25,30 @@
|
||||||
"mocha": "latest",
|
"mocha": "latest",
|
||||||
"nyc": "latest",
|
"nyc": "latest",
|
||||||
"source-map-support": "latest",
|
"source-map-support": "latest",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
"tslint": "latest",
|
"tslint": "latest",
|
||||||
"typescript": "^5.1.6"
|
"typescript": "^5.1.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@grpc/grpc-js": "^1.9.0",
|
"@grpc/grpc-js": "^1.9.0",
|
||||||
"babel-register": "^6.26.0",
|
"babel-register": "^6.26.0",
|
||||||
|
"class-transformer": "^0.5.1",
|
||||||
|
"class-validator": "^0.14.0",
|
||||||
"concurrently": "^8.2.0",
|
"concurrently": "^8.2.0",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"express": "^4.18.2",
|
||||||
"first-di": "^1.0.11",
|
"first-di": "^1.0.11",
|
||||||
"md5": "^2.3.0",
|
"md5": "^2.3.0",
|
||||||
|
"mongoose": "^7.6.2",
|
||||||
|
"mongoose-autopopulate": "^1.1.0",
|
||||||
"node-watch": "^0.7.4",
|
"node-watch": "^0.7.4",
|
||||||
"nodemon": "^3.0.1",
|
"nodemon": "^3.0.1",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
|
"socket.io": "^4.7.2",
|
||||||
|
"socket.io-client": "^4.7.2",
|
||||||
"spark-md5": "^3.0.2",
|
"spark-md5": "^3.0.2",
|
||||||
"ts-md5": "^1.3.1",
|
"ts-md5": "^1.3.1",
|
||||||
"tsc-watch": "^6.0.4"
|
"tsc-watch": "^6.0.4",
|
||||||
|
"typedi": "^0.10.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
82
server/src/core/controllers/app.ts
Normal file
82
server/src/core/controllers/app.ts
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
import express from "express";
|
||||||
|
import { Routes } from "../interfaces/router";
|
||||||
|
import cors from "cors";
|
||||||
|
import locator from "../di/register_di";
|
||||||
|
import { DevEnv, UnitTestEnv } from "../di/env";
|
||||||
|
import mongoose from "mongoose";
|
||||||
|
import http from "http";
|
||||||
|
// import { Server } from "socket.io";
|
||||||
|
|
||||||
|
export class App {
|
||||||
|
public app: express.Application;
|
||||||
|
public port: number;
|
||||||
|
public env: string;
|
||||||
|
public computedFolder: string;
|
||||||
|
// public io:
|
||||||
|
constructor(routes: Routes[], computedFolder: string) {
|
||||||
|
this.port = 3000;
|
||||||
|
this.env = "dev";
|
||||||
|
this.loadAppDependencies().then(() => {
|
||||||
|
this.app = express();
|
||||||
|
this.initializeMiddlewares();
|
||||||
|
this.initializeRoutes(routes);
|
||||||
|
this.computedFolder = computedFolder;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public listen() {
|
||||||
|
const httpServer = new http.Server(this.app);
|
||||||
|
// const io = new Server(httpServer);
|
||||||
|
|
||||||
|
httpServer.listen(this.port, () => {
|
||||||
|
console.info(`=================================`);
|
||||||
|
console.info(`======= ENV: ${this.env} =======`);
|
||||||
|
console.info(`🚀 HTTP http://localhost:${this.port}`);
|
||||||
|
console.info(`🚀 WS ws://localhost:${this.port}`);
|
||||||
|
console.info(`=================================`);
|
||||||
|
});
|
||||||
|
// io.on("connection", (socket) => {
|
||||||
|
// socket.on("disconnect", function (msg) {
|
||||||
|
// console.log("Disconnected");
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
// setInterval(function () {
|
||||||
|
// io.emit("goodbye");
|
||||||
|
// console.log(200);
|
||||||
|
// }, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getServer() {
|
||||||
|
return this.app;
|
||||||
|
}
|
||||||
|
|
||||||
|
private initializeMiddlewares() {
|
||||||
|
this.app.use(cors());
|
||||||
|
this.app.use(express.json());
|
||||||
|
this.app.use(express.urlencoded({ extended: true }));
|
||||||
|
}
|
||||||
|
|
||||||
|
private initializeRoutes(routes: Routes[]) {
|
||||||
|
routes.forEach((route) => {
|
||||||
|
this.app.use("/", route.router);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async loadAppDependencies() {
|
||||||
|
await locator(
|
||||||
|
this.env == "development"
|
||||||
|
? new DevEnv(this.computedFolder)
|
||||||
|
: new UnitTestEnv(this.computedFolder)
|
||||||
|
);
|
||||||
|
|
||||||
|
mongoose
|
||||||
|
.connect("mongodb://127.0.0.1:27017/test")
|
||||||
|
.then(() => console.log("Connected!"))
|
||||||
|
.catch((e) => {
|
||||||
|
console.log("ERROR:", e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
34
server/src/core/controllers/crud_controller.ts
Normal file
34
server/src/core/controllers/crud_controller.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import { IRouteModel } from "../interfaces/router";
|
||||||
|
import { CreateDataBaseModelUseCase } from "../usecases/create_database_model_usecase";
|
||||||
|
import { DeleteDataBaseModelUseCase } from "../usecases/delete_database_model_usecase";
|
||||||
|
import { PaginationDataBaseModelUseCase } from "../usecases/pagination_database_model_usecase";
|
||||||
|
import { UpdateDataBaseModelUseCase } from "../usecases/update_database_model_usecase";
|
||||||
|
|
||||||
|
import { CoreHttpController } from "./http_controller";
|
||||||
|
import mongoose from "mongoose";
|
||||||
|
|
||||||
|
export class CrudController<V, D> extends CoreHttpController<V> {
|
||||||
|
dataBaseModel: mongoose.Model<D>;
|
||||||
|
|
||||||
|
constructor(routerModel: IRouteModel) {
|
||||||
|
super(routerModel);
|
||||||
|
this.url = "/" + routerModel.url;
|
||||||
|
this.validationModel = routerModel.validationModel;
|
||||||
|
this.dataBaseModel = routerModel.databaseModel;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
init() {
|
||||||
|
this.routes["POST"] = new CreateDataBaseModelUseCase<D>(
|
||||||
|
this.dataBaseModel
|
||||||
|
).call;
|
||||||
|
this.routes["GET"] = new PaginationDataBaseModelUseCase<D>(
|
||||||
|
this.dataBaseModel
|
||||||
|
).call;
|
||||||
|
this.routes["DELETE"] = new DeleteDataBaseModelUseCase<D>(
|
||||||
|
this.dataBaseModel
|
||||||
|
).call;
|
||||||
|
this.routes["PUT"] = new UpdateDataBaseModelUseCase<V, D>(
|
||||||
|
this.dataBaseModel
|
||||||
|
).call;
|
||||||
|
}
|
||||||
|
}
|
107
server/src/core/controllers/http_controller.ts
Normal file
107
server/src/core/controllers/http_controller.ts
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
import { validationModelMiddleware } from "../middlewares/validation_model";
|
||||||
|
import { Result } from "../helper/result";
|
||||||
|
import { Router, Request, Response } from "express";
|
||||||
|
import { IRouteModel, Routes } from "../interfaces/router";
|
||||||
|
|
||||||
|
export type CallBackFunction<T> = (a: T) => Promise<Result<any, any>>;
|
||||||
|
|
||||||
|
abstract class ICoreHttpController {
|
||||||
|
abstract url: string;
|
||||||
|
public router = Router();
|
||||||
|
abstract call(): Routes;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CoreHttpController<V> implements ICoreHttpController {
|
||||||
|
url: string;
|
||||||
|
validationModel: any;
|
||||||
|
|
||||||
|
routes = {
|
||||||
|
POST: null,
|
||||||
|
GET: null,
|
||||||
|
DELETE: null,
|
||||||
|
PUT: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
public router = Router();
|
||||||
|
|
||||||
|
constructor(routerModel: IRouteModel) {
|
||||||
|
this.url = "/" + routerModel.url;
|
||||||
|
this.validationModel = routerModel.validationModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
call(): Routes {
|
||||||
|
if (this.routes["POST"] != null) {
|
||||||
|
this.router.post(
|
||||||
|
this.url,
|
||||||
|
validationModelMiddleware(this.validationModel),
|
||||||
|
(req, res) =>
|
||||||
|
this.requestResponseController<V>(req, res, this.routes["POST"])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.routes["DELETE"] != null) {
|
||||||
|
this.router.delete(this.url, (req, res) =>
|
||||||
|
this.requestResponseController<V>(req, res, this.routes["DELETE"])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.routes["PUT"] != null) {
|
||||||
|
this.router.put(
|
||||||
|
this.url,
|
||||||
|
validationModelMiddleware(this.validationModel),
|
||||||
|
(req, res) =>
|
||||||
|
this.requestResponseController<V>(req, res, this.routes["PUT"])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.routes["GET"] != null) {
|
||||||
|
this.router.get(this.url, (req, res) =>
|
||||||
|
this.requestResponseController<V>(req, res, this.routes["GET"])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
router: this.router,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public put(usecase: CallBackFunction<V>) {
|
||||||
|
this.routes["PUT"] = usecase;
|
||||||
|
}
|
||||||
|
public delete(usecase: CallBackFunction<V>) {
|
||||||
|
this.routes["DELETE"] = usecase;
|
||||||
|
}
|
||||||
|
private async requestResponseController<T>(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
usecase: CallBackFunction<T>
|
||||||
|
) {
|
||||||
|
let payload = null;
|
||||||
|
|
||||||
|
if (req["model"] != undefined) {
|
||||||
|
payload = req.body as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.query.page !== undefined) {
|
||||||
|
payload = String(req.query.page);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.query.id !== undefined) {
|
||||||
|
payload = String(req.query.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
(await usecase(payload)).fold(
|
||||||
|
(ok) => {
|
||||||
|
res.json(ok);
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
res.status(400).json(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
public post(usecase: CallBackFunction<V>) {
|
||||||
|
this.routes["POST"] = usecase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(usecase: CallBackFunction<V>) {
|
||||||
|
this.routes["GET"] = usecase;
|
||||||
|
}
|
||||||
|
}
|
15
server/src/core/controllers/socket_controller.ts
Normal file
15
server/src/core/controllers/socket_controller.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// import path from "path";
|
||||||
|
// import { TypedEvent } from "../helper/typed_event";
|
||||||
|
// import { StackService } from "../services/stack_service";
|
||||||
|
// // TODO(IDONTSUDO): up to do
|
||||||
|
|
||||||
|
// class SocketController<T>{
|
||||||
|
// emitter:TypedEvent<T>;
|
||||||
|
// constructor(emitter:TypedEvent<T>, ){
|
||||||
|
// this.emitter = emitter
|
||||||
|
// }
|
||||||
|
// call = () =>{
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { reflection } from "first-di";
|
import { Service } from "typedi";
|
||||||
|
|
||||||
@reflection
|
@Service()
|
||||||
export class IEnv{
|
export class IEnv{
|
||||||
rootFolder!: string;
|
rootFolder!: string;
|
||||||
constructor(){
|
constructor(){
|
||||||
|
@ -14,7 +14,7 @@ export class IEnv{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@reflection
|
@Service()
|
||||||
export class DevEnv implements IEnv {
|
export class DevEnv implements IEnv {
|
||||||
rootFolder:string;
|
rootFolder:string;
|
||||||
constructor(rootFolder:string){
|
constructor(rootFolder:string){
|
||||||
|
@ -28,8 +28,7 @@ export class DevEnv implements IEnv {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Service()
|
||||||
@reflection
|
|
||||||
export class UnitTestEnv implements IEnv{
|
export class UnitTestEnv implements IEnv{
|
||||||
rootFolder:string;
|
rootFolder:string;
|
||||||
constructor(rootFolder:string){
|
constructor(rootFolder:string){
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { override } from "first-di";
|
import { DevEnv, IEnv, UnitTestEnv } from "./env";
|
||||||
import { DevEnv, IEnv, UnitTestEnv } from "./env.js";
|
import { extensions } from "../extensions/extensions";
|
||||||
import { MetaDataFileManagerModel } from "../model/meta_data_file_manager_model.js";
|
// import { Container, Service } from 'typedi';
|
||||||
import { extensions } from "../extensions/extensions.js";
|
|
||||||
|
|
||||||
export default function locator(env: IEnv) {
|
export default function locator(env: IEnv) {
|
||||||
extensions();
|
extensions();
|
||||||
|
@ -9,16 +8,16 @@ export default function locator(env: IEnv) {
|
||||||
registerRepository(env);
|
registerRepository(env);
|
||||||
registerController(env);
|
registerController(env);
|
||||||
registerService(env);
|
registerService(env);
|
||||||
override(MetaDataFileManagerModel, MetaDataFileManagerModel);
|
// override(MetaDataFileManagerModel, MetaDataFileManagerModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
const envRegister = (env: IEnv) => {
|
const envRegister = (env: IEnv) => {
|
||||||
switch (env.toStringEnv()) {
|
switch (env.toStringEnv()) {
|
||||||
case UnitTestEnv.env():
|
case UnitTestEnv.env():
|
||||||
override(IEnv, UnitTestEnv);
|
// override(IEnv, UnitTestEnv);
|
||||||
return;
|
return;
|
||||||
case "DevEnv":
|
case "DevEnv":
|
||||||
override(IEnv, DevEnv);
|
// override(IEnv, DevEnv);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -26,11 +25,11 @@ const envRegister = (env: IEnv) => {
|
||||||
const registerRepository = (env: IEnv) => {
|
const registerRepository = (env: IEnv) => {
|
||||||
switch (env.toStringEnv()) {
|
switch (env.toStringEnv()) {
|
||||||
case UnitTestEnv.env():
|
case UnitTestEnv.env():
|
||||||
override(IEnv, UnitTestEnv);
|
// override(IEnv, UnitTestEnv);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case DevEnv.env():
|
case DevEnv.env():
|
||||||
override(IEnv, DevEnv);
|
// override(IEnv, DevEnv);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { ArrayEquals } from "./array.js";
|
import { ArrayEquals } from "./array";
|
||||||
|
|
||||||
export const extensions = () =>{
|
export const extensions = () =>{
|
||||||
ArrayEquals()
|
ArrayEquals()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,248 +1 @@
|
||||||
const toStringTag: typeof Symbol.toStringTag =
|
|
||||||
typeof Symbol !== 'undefined' ? Symbol.toStringTag : ('@@toStringTag' as any);
|
|
||||||
|
|
||||||
class CancelablePromiseInternal<T = any> {
|
|
||||||
#internals: Internals;
|
|
||||||
#promise: Promise<T>;
|
|
||||||
|
|
||||||
[toStringTag] = 'CancelablePromise';
|
|
||||||
|
|
||||||
constructor({
|
|
||||||
executor = () => {},
|
|
||||||
internals = defaultInternals(),
|
|
||||||
promise = new Promise<T>((resolve, reject) =>
|
|
||||||
executor(resolve, reject, (onCancel) => {
|
|
||||||
internals.onCancelList.push(onCancel);
|
|
||||||
})
|
|
||||||
),
|
|
||||||
}: {
|
|
||||||
executor?: (
|
|
||||||
resolve: (value: T | PromiseLike<T>) => void,
|
|
||||||
reject: (reason?: any) => void,
|
|
||||||
onCancel: (cancelHandler: () => void) => void
|
|
||||||
) => void;
|
|
||||||
internals?: Internals;
|
|
||||||
promise?: Promise<T>;
|
|
||||||
}) {
|
|
||||||
this.cancel = this.cancel.bind(this);
|
|
||||||
this.#internals = internals;
|
|
||||||
this.#promise =
|
|
||||||
promise ||
|
|
||||||
new Promise<T>((resolve, reject) =>
|
|
||||||
executor(resolve, reject, (onCancel) => {
|
|
||||||
internals.onCancelList.push(onCancel);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
then<TResult1 = T, TResult2 = never>(
|
|
||||||
onfulfilled?:
|
|
||||||
| ((
|
|
||||||
value: T
|
|
||||||
) => TResult1 | PromiseLike<TResult1> | CancelablePromise<TResult1>)
|
|
||||||
| undefined
|
|
||||||
| null,
|
|
||||||
onrejected?:
|
|
||||||
| ((
|
|
||||||
reason: any
|
|
||||||
) => TResult2 | PromiseLike<TResult2> | CancelablePromise<TResult2>)
|
|
||||||
| undefined
|
|
||||||
| null
|
|
||||||
): CancelablePromise<TResult1 | TResult2> {
|
|
||||||
return makeCancelable<TResult1 | TResult2>(
|
|
||||||
this.#promise.then(
|
|
||||||
createCallback(onfulfilled, this.#internals),
|
|
||||||
createCallback(onrejected, this.#internals)
|
|
||||||
),
|
|
||||||
this.#internals
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
catch<TResult = never>(
|
|
||||||
onrejected?:
|
|
||||||
| ((
|
|
||||||
reason: any
|
|
||||||
) => TResult | PromiseLike<TResult> | CancelablePromise<TResult>)
|
|
||||||
| undefined
|
|
||||||
| null
|
|
||||||
): CancelablePromise<T | TResult> {
|
|
||||||
return makeCancelable<T | TResult>(
|
|
||||||
this.#promise.catch(createCallback(onrejected, this.#internals)),
|
|
||||||
this.#internals
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
finally(
|
|
||||||
onfinally?: (() => void) | undefined | null,
|
|
||||||
runWhenCanceled?: boolean
|
|
||||||
): CancelablePromise<T> {
|
|
||||||
if (runWhenCanceled) {
|
|
||||||
this.#internals.onCancelList.push(onfinally);
|
|
||||||
}
|
|
||||||
return makeCancelable<T>(
|
|
||||||
this.#promise.finally(
|
|
||||||
createCallback(() => {
|
|
||||||
if (onfinally) {
|
|
||||||
if (runWhenCanceled) {
|
|
||||||
this.#internals.onCancelList =
|
|
||||||
this.#internals.onCancelList.filter(
|
|
||||||
(callback) => callback !== onfinally
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return onfinally();
|
|
||||||
}
|
|
||||||
}, this.#internals)
|
|
||||||
),
|
|
||||||
this.#internals
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel(): void {
|
|
||||||
this.#internals.isCanceled = true;
|
|
||||||
const callbacks = this.#internals.onCancelList;
|
|
||||||
this.#internals.onCancelList = [];
|
|
||||||
for (const callback of callbacks) {
|
|
||||||
if (typeof callback === 'function') {
|
|
||||||
try {
|
|
||||||
callback();
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isCanceled(): boolean {
|
|
||||||
return this.#internals.isCanceled === true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CancelablePromise<T = any> extends CancelablePromiseInternal<T> {
|
|
||||||
static all = function all(iterable: any) {
|
|
||||||
return makeAllCancelable(iterable, Promise.all(iterable));
|
|
||||||
} as CancelablePromiseOverloads['all'];
|
|
||||||
|
|
||||||
static allSettled = function allSettled(iterable: any) {
|
|
||||||
return makeAllCancelable(iterable, Promise.allSettled(iterable));
|
|
||||||
} as CancelablePromiseOverloads['allSettled'];
|
|
||||||
|
|
||||||
static any = function any(iterable: any) {
|
|
||||||
return makeAllCancelable(iterable, Promise.any(iterable));
|
|
||||||
} as CancelablePromiseOverloads['any'];
|
|
||||||
|
|
||||||
static race = function race(iterable) {
|
|
||||||
return makeAllCancelable(iterable, Promise.race(iterable));
|
|
||||||
} as CancelablePromiseOverloads['race'];
|
|
||||||
|
|
||||||
static resolve = function resolve(value) {
|
|
||||||
return cancelable(Promise.resolve(value));
|
|
||||||
} as CancelablePromiseOverloads['resolve'];
|
|
||||||
|
|
||||||
static reject = function reject(reason) {
|
|
||||||
return cancelable(Promise.reject(reason));
|
|
||||||
} as CancelablePromiseOverloads['reject'];
|
|
||||||
|
|
||||||
static isCancelable = isCancelablePromise;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
executor: (
|
|
||||||
resolve: (value: T | PromiseLike<T>) => void,
|
|
||||||
reject: (reason?: any) => void,
|
|
||||||
onCancel: (cancelHandler: () => void) => void
|
|
||||||
) => void
|
|
||||||
) {
|
|
||||||
super({ executor });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CancelablePromise;
|
|
||||||
|
|
||||||
export function cancelable<T = any>(promise: Promise<T>): CancelablePromise<T> {
|
|
||||||
return makeCancelable(promise, defaultInternals());
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isCancelablePromise(promise: any): boolean {
|
|
||||||
return (
|
|
||||||
promise instanceof CancelablePromise ||
|
|
||||||
promise instanceof CancelablePromiseInternal
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createCallback(onResult: any, internals: Internals):any {
|
|
||||||
if (onResult) {
|
|
||||||
return (arg?: any) => {
|
|
||||||
if (!internals.isCanceled) {
|
|
||||||
const result = onResult(arg);
|
|
||||||
if (isCancelablePromise(result)) {
|
|
||||||
internals.onCancelList.push(result.cancel);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return arg;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeCancelable<T>(promise: Promise<T>, internals: Internals) {
|
|
||||||
return new CancelablePromiseInternal<T>({
|
|
||||||
internals,
|
|
||||||
promise,
|
|
||||||
}) as CancelablePromise<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeAllCancelable(iterable: any, promise: Promise<any>) {
|
|
||||||
const internals = defaultInternals();
|
|
||||||
internals.onCancelList.push(() => {
|
|
||||||
for (const resolvable of iterable) {
|
|
||||||
if (isCancelablePromise(resolvable)) {
|
|
||||||
resolvable.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return new CancelablePromiseInternal({ internals, promise });
|
|
||||||
}
|
|
||||||
|
|
||||||
function defaultInternals(): Internals {
|
|
||||||
return { isCanceled: false, onCancelList: [] };
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Internals {
|
|
||||||
isCanceled: boolean;
|
|
||||||
onCancelList: any[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CancelablePromiseOverloads {
|
|
||||||
all<T extends readonly unknown[] | []>(
|
|
||||||
values: T
|
|
||||||
): CancelablePromise<{ -readonly [P in keyof T]: Awaited<T[P]> }>;
|
|
||||||
|
|
||||||
allSettled<T extends readonly unknown[] | []>(
|
|
||||||
values: T
|
|
||||||
): CancelablePromise<{
|
|
||||||
-readonly [P in keyof T]: PromiseSettledResult<Awaited<T[P]>>;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
allSettled<T>(
|
|
||||||
values: Iterable<T | PromiseLike<T> | CancelablePromise<T>>
|
|
||||||
): CancelablePromise<PromiseSettledResult<Awaited<T>>[]>;
|
|
||||||
|
|
||||||
any<T extends readonly unknown[] | []>(
|
|
||||||
values: T
|
|
||||||
): CancelablePromise<Awaited<T[number]>>;
|
|
||||||
|
|
||||||
any<T>(
|
|
||||||
values: Iterable<T | PromiseLike<T> | CancelablePromise<T>>
|
|
||||||
): CancelablePromise<Awaited<T>>;
|
|
||||||
|
|
||||||
race<T extends readonly unknown[] | []>(
|
|
||||||
values: T
|
|
||||||
): CancelablePromise<Awaited<T[number]>>;
|
|
||||||
|
|
||||||
resolve(): CancelablePromise<void>;
|
|
||||||
|
|
||||||
resolve<T>(
|
|
||||||
value: T | PromiseLike<T> | CancelablePromise<T>
|
|
||||||
): CancelablePromise<T>;
|
|
||||||
|
|
||||||
reject<T = never>(reason?: any): CancelablePromise<T>;
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { EXEC_EVENT, EXEC_TYPE, ExecError } from "../model/exec_error_model.js";
|
import { EXEC_EVENT, EXEC_TYPE, ExecError } from "../model/exec_error_model";
|
||||||
import * as cp from "child_process";
|
import * as cp from "child_process";
|
||||||
import { ExecutorResult } from "../model/executor_result.js";
|
import { ExecutorResult } from "../model/executor_result";
|
||||||
|
|
||||||
export enum WorkerType {
|
export enum WorkerType {
|
||||||
EXEC = "EXEC",
|
EXEC = "EXEC",
|
||||||
|
|
14
server/src/core/interfaces/payload.ts
Normal file
14
server/src/core/interfaces/payload.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
// export class Payload<T>{
|
||||||
|
// model: T | undefined
|
||||||
|
// query:string | undefined
|
||||||
|
// setModel(model:T){
|
||||||
|
// this.model = model
|
||||||
|
// }
|
||||||
|
// setQuery(query:string){
|
||||||
|
// this.query = query
|
||||||
|
// }
|
||||||
|
// isEmpty(){
|
||||||
|
// return this.model != undefined || this.query != undefined
|
||||||
|
// }
|
||||||
|
// }
|
3
server/src/core/interfaces/response.ts
Normal file
3
server/src/core/interfaces/response.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export interface ICreateObjectDataBase {
|
||||||
|
id: string;
|
||||||
|
}
|
14
server/src/core/interfaces/router.ts
Normal file
14
server/src/core/interfaces/router.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { Router } from "express";
|
||||||
|
|
||||||
|
export interface Routes {
|
||||||
|
router: Router;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRouteModel {
|
||||||
|
validationModel: any;
|
||||||
|
url: string;
|
||||||
|
databaseModel: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
12
server/src/core/middlewares/validation_auth.ts
Normal file
12
server/src/core/middlewares/validation_auth.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
// export const validationMiddleware = (
|
||||||
|
// type: any,
|
||||||
|
// value = 'body',
|
||||||
|
// skipMissingProperties = false,
|
||||||
|
// whitelist = true,
|
||||||
|
// forbidNonWhitelisted = true,
|
||||||
|
// ): RequestHandler => {
|
||||||
|
|
||||||
|
|
||||||
|
// }
|
30
server/src/core/middlewares/validation_model.ts
Normal file
30
server/src/core/middlewares/validation_model.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { plainToInstance } from 'class-transformer';
|
||||||
|
import { validate, ValidationError } from 'class-validator';
|
||||||
|
import { RequestHandler } from 'express';
|
||||||
|
|
||||||
|
export const validationModelMiddleware = (
|
||||||
|
type: any,
|
||||||
|
value = 'body',
|
||||||
|
skipMissingProperties = false,
|
||||||
|
whitelist = true,
|
||||||
|
forbidNonWhitelisted = true,
|
||||||
|
): RequestHandler => {
|
||||||
|
return (req, res, next) => {
|
||||||
|
if(type === null && type == undefined){
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const model = plainToInstance(type, req[value]);
|
||||||
|
validate(model, { skipMissingProperties, whitelist, forbidNonWhitelisted }).then((errors: ValidationError[]) => {
|
||||||
|
console.log(errors)
|
||||||
|
if (errors.length > 0) {
|
||||||
|
const message = errors.map((error: ValidationError) => Object.values(error.constraints)).join(', ');
|
||||||
|
return res.status(400).json(message)
|
||||||
|
} else {
|
||||||
|
req['model'] = model
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
import { EXEC_EVENT, EXEC_TYPE } from "./exec_error_model.js";
|
import { EXEC_EVENT, EXEC_TYPE } from "./exec_error_model";
|
||||||
|
|
||||||
|
|
||||||
export class ExecutorResult {
|
export class ExecutorResult {
|
||||||
type: EXEC_TYPE;
|
type: EXEC_TYPE;
|
||||||
event: EXEC_EVENT;
|
event: EXEC_EVENT;
|
||||||
data: any;
|
data: any;
|
||||||
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;
|
||||||
this.data = data;
|
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);
|
||||||
}
|
}
|
||||||
static isExecutorResult(value: any): void | ExecutorResult {
|
return;
|
||||||
if ("type" in value && "event" in value && "data" in value) {
|
}
|
||||||
return new ExecutorResult(value.type, value.event, value.data);
|
}
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import { EXEC_TYPE } from "./exec_error_model.js";
|
import { Trigger } from "../../features/triggers/trigger_model";
|
||||||
|
import { EXEC_TYPE } from "./exec_error_model";
|
||||||
|
|
||||||
|
export interface IPipeline {
|
||||||
export interface ProcessMetaData {
|
process: IProcess;
|
||||||
process: Process;
|
|
||||||
trigger: Trigger;
|
trigger: Trigger;
|
||||||
env: Env | null;
|
env: Env | null;
|
||||||
stackGenerateType:StackGenerateType;
|
stackGenerateType: StackGenerateType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum StackGenerateType{
|
export enum StackGenerateType {
|
||||||
MAP = 'MAP',
|
MAP = "MAP",
|
||||||
SINGLETON = 'SINGLETON'
|
SINGLETON = "SINGLETON",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Env {
|
export interface Env {
|
||||||
|
@ -19,26 +19,17 @@ export interface Env {
|
||||||
isExtends: string;
|
isExtends: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Process {
|
export interface IProcess {
|
||||||
type: EXEC_TYPE;
|
type: EXEC_TYPE;
|
||||||
command: string;
|
command: string;
|
||||||
isGenerating: boolean;
|
isGenerating: boolean;
|
||||||
isLocaleCode: boolean;
|
isLocaleCode: boolean;
|
||||||
issueType: IssueType;
|
issueType: IssueType;
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
commit?:string | undefined;
|
commit?: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum IssueType {
|
export enum IssueType {
|
||||||
WARNING = "WARNING",
|
WARNING = "WARNING",
|
||||||
ERROR = "ERROR",
|
ERROR = "ERROR",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TriggerType {
|
|
||||||
PROCESS = "PROCESS",
|
|
||||||
FILE = "FILE",
|
|
||||||
}
|
|
||||||
export interface Trigger {
|
|
||||||
type: TriggerType;
|
|
||||||
value: string[];
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import cluster, { Worker } from "node:cluster";
|
import cluster, { Worker } from "node:cluster";
|
||||||
import { TypedEvent } from "../helper/typed_event.js";
|
import { TypedEvent } from "../helper/typed_event";
|
||||||
import { Result } from "../helper/result.js";
|
import { Result } from "../helper/result";
|
||||||
import { WorkerDataExec, WorkerType } from "../helper/worker_computed.js";
|
import { WorkerDataExec, WorkerType } from "../helper/worker_computed";
|
||||||
import { delay } from "../helper/delay.js";
|
import { delay } from "../helper/delay";
|
||||||
import { ExecutorResult } from "../model/executor_result.js";
|
import { ExecutorResult } from "../model/executor_result";
|
||||||
import { EXEC_TYPE, ExecError, SpawnError } from "../model/exec_error_model.js";
|
import { EXEC_TYPE, ExecError, SpawnError } from "../model/exec_error_model";
|
||||||
|
|
||||||
abstract class IExecutorProgramService {
|
abstract class IExecutorProgramService {
|
||||||
abstract execPath: string;
|
abstract execPath: string;
|
||||||
|
@ -31,7 +31,7 @@ export class ExecutorProgramService
|
||||||
args: Array<string> | undefined = undefined
|
args: Array<string> | undefined = undefined
|
||||||
) {
|
) {
|
||||||
cluster.setupPrimary({
|
cluster.setupPrimary({
|
||||||
exec: "./src/core/helper/worker_computed.js",
|
exec: "./src/core/helper/worker_computed",
|
||||||
});
|
});
|
||||||
|
|
||||||
const worker = cluster.fork();
|
const worker = cluster.fork();
|
||||||
|
|
|
@ -7,16 +7,16 @@ import { BinaryLike } from "crypto";
|
||||||
import {
|
import {
|
||||||
EventsFileChanger,
|
EventsFileChanger,
|
||||||
MetaDataFileManagerModel,
|
MetaDataFileManagerModel,
|
||||||
} from "../model/meta_data_file_manager_model.js";
|
} from "../model/meta_data_file_manager_model";
|
||||||
import { Result } from "../helper/result.js";
|
import { Result } from "../helper/result";
|
||||||
import { TypedEvent } from "../helper/typed_event.js";
|
import { TypedEvent } from "../helper/typed_event";
|
||||||
|
|
||||||
const readFileAsync = promisify(fs.readFile);
|
const readFileAsync = promisify(fs.readFile);
|
||||||
const readdir = promisify(fs.readdir);
|
const readdir = promisify(fs.readdir);
|
||||||
const stat = promisify(fs.stat);
|
const stat = promisify(fs.stat);
|
||||||
const lsStat = promisify(fs.lstat);
|
const lsStat = promisify(fs.lstat);
|
||||||
|
|
||||||
function joinBuffers(buffers, delimiter = " ") {
|
function joinBuffers(buffers: Array<Buffer>, delimiter = " ") {
|
||||||
const d = Buffer.from(delimiter);
|
const d = Buffer.from(delimiter);
|
||||||
return buffers.reduce((prev, b) => Buffer.concat([prev, d, b]));
|
return buffers.reduce((prev, b) => Buffer.concat([prev, d, b]));
|
||||||
}
|
}
|
||||||
|
@ -44,8 +44,6 @@ export interface IHashesCache {
|
||||||
[key: string]: MetaDataFileManagerModel;
|
[key: string]: MetaDataFileManagerModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export abstract class IFilesChangeNotifierService {
|
export abstract class IFilesChangeNotifierService {
|
||||||
abstract directory: string;
|
abstract directory: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +1,40 @@
|
||||||
import {
|
import {
|
||||||
FilesChangeNotifierService,
|
FilesChangeNotifierService,
|
||||||
IHashesCache,
|
IHashesCache,
|
||||||
} from "./files_change_notifier_service.js";
|
} from "./files_change_notifier_service";
|
||||||
import { ProcessMetaData, Trigger } from "../model/process_model.js";
|
import { IPipeline } from "../model/process_model";
|
||||||
import { ExecutorProgramService } from "./executor_program_service.js";
|
import { ExecutorProgramService } from "./executor_program_service";
|
||||||
import {
|
import { EXEC_EVENT, ExecError, SpawnError } from "../model/exec_error_model";
|
||||||
EXEC_EVENT,
|
import { TypedEvent } from "../helper/typed_event";
|
||||||
ExecError,
|
import { Result } from "../helper/result";
|
||||||
SpawnError,
|
import { ExecutorResult } from "../model/executor_result";
|
||||||
} from "../model/exec_error_model.js";
|
import { delay } from "../helper/delay";
|
||||||
import { TypedEvent } from "../helper/typed_event.js";
|
import { TriggerService } from "./trigger_service";
|
||||||
import { Result } from "../helper/result.js";
|
import { Trigger } from "../../features/triggers/trigger_model";
|
||||||
import { ExecutorResult } from "../model/executor_result.js";
|
|
||||||
import { delay } from "../helper/delay.js";
|
|
||||||
import { TriggerErrorReport, TriggerService } from "./trigger_service.js";
|
|
||||||
|
|
||||||
export interface Iteration {
|
export interface Iteration {
|
||||||
hashes: IHashesCache | null;
|
hashes: IHashesCache | null;
|
||||||
process: ProcessMetaData;
|
process: IPipeline;
|
||||||
result?: ExecError | SpawnError | ExecutorResult;
|
result?: ExecError | SpawnError | ExecutorResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class IStackService {
|
export abstract class IStackService {
|
||||||
abstract callStack: Iteration[];
|
abstract callStack: Iteration[];
|
||||||
abstract path: string;
|
abstract path: string;
|
||||||
abstract init(processed: ProcessMetaData[], path: string): void;
|
abstract init(processed: IPipeline[], path: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StackService extends TypedEvent<string> implements IStackService {
|
export class StackService extends TypedEvent<string> implements IStackService {
|
||||||
callStack: Iteration[];
|
callStack: Iteration[];
|
||||||
path: string;
|
path: string;
|
||||||
constructor(processed: ProcessMetaData[], path: string) {
|
constructor(processed: IPipeline[], path: string) {
|
||||||
super();
|
super();
|
||||||
this.path = path;
|
this.path = path;
|
||||||
this.callStack = [];
|
this.callStack = [];
|
||||||
this.init(processed);
|
this.init(processed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(processed: ProcessMetaData[]) {
|
public init(processed: IPipeline[]) {
|
||||||
for (let el of processed) {
|
for (let el of processed) {
|
||||||
el = this.commandHandler(el);
|
el = this.commandHandler(el);
|
||||||
this.callStack.push({
|
this.callStack.push({
|
||||||
|
@ -46,7 +43,7 @@ export class StackService extends TypedEvent<string> implements IStackService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private commandHandler(processMetaData: ProcessMetaData) {
|
private commandHandler(processMetaData: IPipeline) {
|
||||||
processMetaData.process.command = processMetaData.process.command.replace(
|
processMetaData.process.command = processMetaData.process.command.replace(
|
||||||
"$PATH",
|
"$PATH",
|
||||||
this.path
|
this.path
|
||||||
|
@ -91,10 +88,10 @@ export class StackService extends TypedEvent<string> implements IStackService {
|
||||||
);
|
);
|
||||||
triggerResult.fold(
|
triggerResult.fold(
|
||||||
(s) => {
|
(s) => {
|
||||||
s
|
s;
|
||||||
},
|
},
|
||||||
(e) => {
|
(e) => {
|
||||||
e;
|
e;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { Trigger, TriggerType } from "../model/process_model.js";
|
|
||||||
import * as vm from "node:vm";
|
import * as vm from "node:vm";
|
||||||
import { IHashesCache } from "./files_change_notifier_service.js";
|
import { IHashesCache } from "./files_change_notifier_service";
|
||||||
import { EventsFileChanger } from "../model/meta_data_file_manager_model.js";
|
import { EventsFileChanger } from "../model/meta_data_file_manager_model";
|
||||||
import { Result } from "../helper/result.js";
|
import { Result } from "../helper/result";
|
||||||
import { TypedEvent } from "../helper/typed_event.js";
|
import { TypedEvent } from "../helper/typed_event";
|
||||||
|
import { Trigger, TriggerType } from "../../features/triggers/trigger_model";
|
||||||
|
|
||||||
export class TriggerCallResult {
|
export class TriggerCallResult {
|
||||||
results: Array<TriggerSuccessResult | TriggerErrorReport>;
|
results: Array<TriggerSuccessResult | TriggerErrorReport>;
|
||||||
|
@ -47,7 +47,7 @@ export class TriggerErrorReport extends Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class TriggerService extends TypedEvent<TriggerCallResult> {
|
export class TriggerService extends TypedEvent<TriggerCallResult> {
|
||||||
context = {};
|
context: any = {};
|
||||||
|
|
||||||
constructor(trigger: Trigger, hashes: IHashesCache, path: string) {
|
constructor(trigger: Trigger, hashes: IHashesCache, path: string) {
|
||||||
super();
|
super();
|
||||||
|
@ -61,8 +61,11 @@ export class TriggerService extends TypedEvent<TriggerCallResult> {
|
||||||
path: string;
|
path: string;
|
||||||
hashes: IHashesCache;
|
hashes: IHashesCache;
|
||||||
trigger: Trigger;
|
trigger: Trigger;
|
||||||
|
|
||||||
private init(): void {
|
private init(): void {
|
||||||
this.context["hashes"] = this.hashes;
|
if (this.context["hashes"] != undefined) {
|
||||||
|
this.context["hashes"] = this.hashes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private getAllHashesDeleteWithouts(): string[] {
|
private getAllHashesDeleteWithouts(): string[] {
|
||||||
return Object.entries(this.hashes).map(([k, v]) => {
|
return Object.entries(this.hashes).map(([k, v]) => {
|
||||||
|
|
22
server/src/core/usecases/create_database_model_usecase.ts
Normal file
22
server/src/core/usecases/create_database_model_usecase.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { Result } from "../helper/result";
|
||||||
|
import { ICreateObjectDataBase } from "../interfaces/response";
|
||||||
|
|
||||||
|
export class CreateDataBaseModelUseCase<V> {
|
||||||
|
databaseModel: any;
|
||||||
|
|
||||||
|
constructor(model) {
|
||||||
|
this.databaseModel = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
call = async (
|
||||||
|
validationModel: V
|
||||||
|
): Promise<Result<Error, ICreateObjectDataBase>> => {
|
||||||
|
try {
|
||||||
|
const result = new this.databaseModel(validationModel);
|
||||||
|
|
||||||
|
return Result.ok({ id: String((await result.save())._id) });
|
||||||
|
} catch (error) {
|
||||||
|
return Result.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
18
server/src/core/usecases/delete_database_model_usecase.ts
Normal file
18
server/src/core/usecases/delete_database_model_usecase.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { Result } from "../helper/result";
|
||||||
|
|
||||||
|
export class DeleteDataBaseModelUseCase<D> {
|
||||||
|
databaseModel: D | any;
|
||||||
|
constructor(model) {
|
||||||
|
this.databaseModel = model;
|
||||||
|
}
|
||||||
|
call = async (id: string): Promise<Result<Error, boolean>> => {
|
||||||
|
try {
|
||||||
|
const model = new this.databaseModel({ _id: id });
|
||||||
|
await model.deleteOne();
|
||||||
|
|
||||||
|
return Result.ok(true);
|
||||||
|
} catch (error) {
|
||||||
|
return Result.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { Result } from "../helper/result";
|
||||||
|
|
||||||
|
export class PaginationDataBaseModelUseCase<D> {
|
||||||
|
databaseModel: D;
|
||||||
|
perPage: number;
|
||||||
|
|
||||||
|
constructor(model: any, perPage = 10) {
|
||||||
|
this.databaseModel = model;
|
||||||
|
this.perPage = perPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
call = async (
|
||||||
|
pageNumber: number
|
||||||
|
): Promise<Result<Error, [D]>> => {
|
||||||
|
try {
|
||||||
|
const page = Math.max(0, pageNumber);
|
||||||
|
const model = this.databaseModel as any;
|
||||||
|
return Result.ok(
|
||||||
|
await model
|
||||||
|
.find()
|
||||||
|
.limit(this.perPage)
|
||||||
|
.skip(this.perPage * page)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
return Result.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
20
server/src/core/usecases/read_database_model_usecase.ts
Normal file
20
server/src/core/usecases/read_database_model_usecase.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
import { Result } from "../helper/result";
|
||||||
|
|
||||||
|
export class ReadByIdDataBaseModelUseCase<D> {
|
||||||
|
databaseModel: D;
|
||||||
|
|
||||||
|
constructor(model) {
|
||||||
|
this.databaseModel = model;
|
||||||
|
}
|
||||||
|
call = async (id: string): Promise<Result<Error, D>> => {
|
||||||
|
try {
|
||||||
|
const r = this.databaseModel as any;
|
||||||
|
|
||||||
|
const model = await r.findById(id);
|
||||||
|
return Result.ok(model);
|
||||||
|
} catch (error) {
|
||||||
|
return Result.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
27
server/src/core/usecases/update_database_model_usecase.ts
Normal file
27
server/src/core/usecases/update_database_model_usecase.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { Result } from "../helper/result";
|
||||||
|
|
||||||
|
interface uuid {
|
||||||
|
_id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdateDataBaseModelUseCase<D, T extends uuid> {
|
||||||
|
databaseModel: D;
|
||||||
|
constructor(databaseModel) {
|
||||||
|
this.databaseModel = databaseModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
call = async (updateModel: T): Promise<Result<Error, T>> => {
|
||||||
|
try {
|
||||||
|
if (updateModel["_id"] === undefined) {
|
||||||
|
return Result.error(new Error("need _id at model body"));
|
||||||
|
}
|
||||||
|
const databaseModel = this.databaseModel as any;
|
||||||
|
const model = await databaseModel.findById(updateModel._id);
|
||||||
|
Object.assign(model, updateModel);
|
||||||
|
await model.save();
|
||||||
|
return Result.ok(model as T);
|
||||||
|
} catch (error) {
|
||||||
|
return Result.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
47
server/src/features/pipelines/pipeline_model.ts
Normal file
47
server/src/features/pipelines/pipeline_model.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import { IsMongoId, IsEnum } from "class-validator";
|
||||||
|
import { Schema, model } from "mongoose";
|
||||||
|
import { StackGenerateType } from "../../core/model/process_model";
|
||||||
|
import {
|
||||||
|
TriggerModel,
|
||||||
|
triggerSchema,
|
||||||
|
} from "../triggers/trigger_model";
|
||||||
|
import { schemaProcess } from "../process/process_model";
|
||||||
|
|
||||||
|
export const PipelineSchema = new Schema({
|
||||||
|
process: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: schemaProcess,
|
||||||
|
autopopulate: true,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
trigger: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: triggerSchema,
|
||||||
|
autopopulate: true,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
command: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
}).plugin(require("mongoose-autopopulate"));
|
||||||
|
|
||||||
|
export const schemaPipeline = "Pipeline";
|
||||||
|
|
||||||
|
export const PipelineDBModel = model<PipelineModel>(
|
||||||
|
schemaPipeline,
|
||||||
|
PipelineSchema
|
||||||
|
);
|
||||||
|
|
||||||
|
export class PipelineModel {
|
||||||
|
@IsMongoId()
|
||||||
|
public process: PipelineModel;
|
||||||
|
|
||||||
|
@IsMongoId()
|
||||||
|
//TODO(IDONTSUDO):NEED OPTION DECORATOR??
|
||||||
|
public trigger: TriggerModel;
|
||||||
|
|
||||||
|
public env = null;
|
||||||
|
|
||||||
|
@IsEnum(StackGenerateType)
|
||||||
|
public stackGenerateType: StackGenerateType;
|
||||||
|
}
|
16
server/src/features/pipelines/pipeline_presentation.ts
Normal file
16
server/src/features/pipelines/pipeline_presentation.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { CrudController } from "../../core/controllers/crud_controller";
|
||||||
|
import { PipelineDBModel, PipelineModel } from "./pipeline_model";
|
||||||
|
|
||||||
|
export class PipelinePresentation extends CrudController<
|
||||||
|
PipelineModel,
|
||||||
|
typeof PipelineDBModel
|
||||||
|
> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
url: "pipeline",
|
||||||
|
validationModel: PipelineModel,
|
||||||
|
databaseModel: PipelineDBModel,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
69
server/src/features/process/process_model.ts
Normal file
69
server/src/features/process/process_model.ts
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
import {
|
||||||
|
IsString,
|
||||||
|
IsOptional,
|
||||||
|
IsEnum,
|
||||||
|
IsNumber,
|
||||||
|
IsBoolean,
|
||||||
|
} from "class-validator";
|
||||||
|
import { Schema, model } from "mongoose";
|
||||||
|
import {
|
||||||
|
IProcess,
|
||||||
|
IssueType,
|
||||||
|
} from "../../core/model/process_model";
|
||||||
|
import { EXEC_TYPE } from "../../core/model/exec_error_model";
|
||||||
|
|
||||||
|
export const ProcessSchema = new Schema({
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
command: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
isGenerating: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
isLocaleCode: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
issueType: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
timeout: {
|
||||||
|
type: Number,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
commit: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const schemaProcess = "Process";
|
||||||
|
|
||||||
|
export const ProcessDBModel = model<IProcess>(schemaProcess, ProcessSchema);
|
||||||
|
|
||||||
|
export class ProcessModel implements IProcess {
|
||||||
|
@IsEnum(EXEC_TYPE)
|
||||||
|
public type: EXEC_TYPE;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
public command: string;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
public isGenerating: boolean;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
public isLocaleCode: boolean;
|
||||||
|
|
||||||
|
@IsEnum(IssueType)
|
||||||
|
public issueType: IssueType;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber()
|
||||||
|
public timeout?: number;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
public commit?: string;
|
||||||
|
}
|
||||||
|
|
15
server/src/features/process/process_presentation.ts
Normal file
15
server/src/features/process/process_presentation.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { CrudController } from "../../core/controllers/crud_controller";
|
||||||
|
import { ProcessDBModel, ProcessModel } from "./process_model";
|
||||||
|
|
||||||
|
export class ProcessPresentation extends CrudController<
|
||||||
|
ProcessModel,
|
||||||
|
typeof ProcessDBModel
|
||||||
|
> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
url: "process",
|
||||||
|
validationModel: ProcessModel,
|
||||||
|
databaseModel: ProcessDBModel,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
31
server/src/features/projects/projects_model.ts
Normal file
31
server/src/features/projects/projects_model.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { Schema, model } from "mongoose";
|
||||||
|
import { PipelineModel, schemaPipeline } from "../pipelines/pipeline_model";
|
||||||
|
import { IsMongoId, IsString } from "class-validator";
|
||||||
|
|
||||||
|
export interface IProjectModel {
|
||||||
|
pipelines: [PipelineModel];
|
||||||
|
rootDir: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ProjectSchema = new Schema({
|
||||||
|
pipelines: {
|
||||||
|
type: Array<Schema.Types.ObjectId>,
|
||||||
|
ref: schemaPipeline,
|
||||||
|
autopopulate: true,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
rootDir: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
}).plugin(require("mongoose-autopopulate"));
|
||||||
|
|
||||||
|
const schema = "Projects";
|
||||||
|
|
||||||
|
export const ProjectDBModel = model<IProjectModel>(schema, ProjectSchema);
|
||||||
|
|
||||||
|
export class ProjectModel implements IProjectModel {
|
||||||
|
@IsMongoId()
|
||||||
|
pipelines: [PipelineModel];
|
||||||
|
@IsString()
|
||||||
|
rootDir: string;
|
||||||
|
}
|
16
server/src/features/projects/projects_presentation.ts
Normal file
16
server/src/features/projects/projects_presentation.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// import { TriggerDBModel, TriggerModel } from "./trigger_model";
|
||||||
|
import { CrudController } from "../../core/controllers/crud_controller";
|
||||||
|
import { ProjectDBModel, ProjectModel } from "./projects_model";
|
||||||
|
|
||||||
|
export class ProjectsPresentation extends CrudController<
|
||||||
|
ProjectModel,
|
||||||
|
typeof ProjectDBModel
|
||||||
|
> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
url: "project",
|
||||||
|
validationModel: ProjectModel,
|
||||||
|
databaseModel: ProjectDBModel,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
43
server/src/features/triggers/trigger_model.ts
Normal file
43
server/src/features/triggers/trigger_model.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import { IsArray, IsOptional, IsEnum} from "class-validator";
|
||||||
|
import { Schema, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface ITriggerModel {
|
||||||
|
_id?: string;
|
||||||
|
type: string;
|
||||||
|
value: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TriggerSchema = new Schema({
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
require: true,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: Array,
|
||||||
|
require: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const triggerSchema = "Trigger";
|
||||||
|
|
||||||
|
export const TriggerDBModel = model<ITriggerModel>(triggerSchema, TriggerSchema);
|
||||||
|
|
||||||
|
export enum TriggerType {
|
||||||
|
PROCESS = "PROCESS",
|
||||||
|
FILE = "FILE",
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TriggerModel implements ITriggerModel {
|
||||||
|
@IsOptional()
|
||||||
|
public _id: string;
|
||||||
|
@IsEnum(TriggerType)
|
||||||
|
public type: TriggerType;
|
||||||
|
@IsArray()
|
||||||
|
public value: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Trigger {
|
||||||
|
type: TriggerType;
|
||||||
|
value: string[];
|
||||||
|
}
|
||||||
|
|
15
server/src/features/triggers/triggers_presentation.ts
Normal file
15
server/src/features/triggers/triggers_presentation.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { TriggerDBModel, TriggerModel } from "./trigger_model";
|
||||||
|
import { CrudController } from "../../core/controllers/crud_controller";
|
||||||
|
|
||||||
|
export class TriggerPresentation extends CrudController<
|
||||||
|
TriggerModel,
|
||||||
|
typeof TriggerDBModel
|
||||||
|
> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
url: "trigger",
|
||||||
|
validationModel: TriggerModel,
|
||||||
|
databaseModel: TriggerDBModel,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
export {}
|
|
21
server/src/main.ts
Normal file
21
server/src/main.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import "reflect-metadata";
|
||||||
|
import { App } from "./core/controllers/app";
|
||||||
|
import { Routes } from "./core/interfaces/router";
|
||||||
|
import { TriggerPresentation } from "./features/triggers/triggers_presentation";
|
||||||
|
import { ProjectsPresentation } from "./features/projects/projects_presentation";
|
||||||
|
import { PipelinePresentation } from "./features/pipelines/pipeline_presentation";
|
||||||
|
import { ProcessPresentation } from "./features/process/process_presentation";
|
||||||
|
|
||||||
|
|
||||||
|
const httpRoutes: Routes[] = [
|
||||||
|
new TriggerPresentation(),
|
||||||
|
new ProjectsPresentation(),
|
||||||
|
new ProcessPresentation(),
|
||||||
|
new PipelinePresentation(),
|
||||||
|
].map((el) => el.call());
|
||||||
|
|
||||||
|
const computedFolder = "";
|
||||||
|
|
||||||
|
new App(httpRoutes, computedFolder).listen();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
import { delay } from "../../src/core/helper/delay.js";
|
import mongoose from "mongoose";
|
||||||
|
import { delay } from "../../src/core/helper/delay";
|
||||||
import { Result } from "../../src/core/helper/result";
|
import { Result } from "../../src/core/helper/result";
|
||||||
import { TypedEvent } from "../../src/core/helper/typed_event.js";
|
import { TypedEvent } from "../../src/core/helper/typed_event";
|
||||||
|
|
||||||
|
|
||||||
|
export const before = async () =>{
|
||||||
|
await mongoose.connection.dropDatabase()
|
||||||
|
}
|
||||||
|
|
||||||
export class TestCore {
|
export class TestCore {
|
||||||
allTests = 0;
|
allTests = 0;
|
||||||
|
@ -23,7 +29,7 @@ export class TestCore {
|
||||||
console.log("\x1b[31m", "❌ - " + testName);
|
console.log("\x1b[31m", "❌ - " + testName);
|
||||||
};
|
};
|
||||||
|
|
||||||
testResult = () => {
|
testResult = async () => {
|
||||||
console.log("\x1b[32m", "=============");
|
console.log("\x1b[32m", "=============");
|
||||||
|
|
||||||
if (this.allTests - this.testOk === 0) {
|
if (this.allTests - this.testOk === 0) {
|
||||||
|
@ -37,6 +43,7 @@ export class TestCore {
|
||||||
console.log("\x1b[31m", "❌ test error:" + String(this.testErr));
|
console.log("\x1b[31m", "❌ test error:" + String(this.testErr));
|
||||||
console.log("\x1b[32m", `✅ test success! ${this.testOk}`);
|
console.log("\x1b[32m", `✅ test success! ${this.testOk}`);
|
||||||
}
|
}
|
||||||
|
await before()
|
||||||
};
|
};
|
||||||
resultTest = async (
|
resultTest = async (
|
||||||
eventClass: TypedEvent<Result<any, any>> | any,
|
eventClass: TypedEvent<Result<any, any>> | any,
|
||||||
|
|
15
server/test/model/test_db_mongo_model.ts
Normal file
15
server/test/model/test_db_mongo_model.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { Schema, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface ITestModel{
|
||||||
|
_id?: string;
|
||||||
|
result: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TestSchema = new Schema({
|
||||||
|
result: String,
|
||||||
|
});
|
||||||
|
|
||||||
|
const schema = "Test";
|
||||||
|
|
||||||
|
export const TestDBModel = model<ITestModel>(schema, TestSchema);
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { delay } from "../../src/core/helper/delay.js";
|
import { delay } from "../../src/core/helper/delay";
|
||||||
import { EXEC_TYPE } from "../../src/core/model/exec_error_model.js";
|
import { EXEC_TYPE } from "../../src/core/model/exec_error_model";
|
||||||
import { ExecutorResult } from "../../src/core/model/executor_result.js";
|
import { ExecutorResult } from "../../src/core/model/executor_result";
|
||||||
import { ExecutorProgramService } from "../../src/core/services/executor_program_service.js";
|
import { ExecutorProgramService } from "../../src/core/services/executor_program_service";
|
||||||
import { TestCore } from "../core/test_core.js";
|
import { TestCore } from "../core/test_core";
|
||||||
import { resultTest as resultTest, dirname__ } from "../test.js";
|
import { resultTest as resultTest, dirname__ } from "../test";
|
||||||
import { Worker } from "node:cluster";
|
import { Worker } from "node:cluster";
|
||||||
|
|
||||||
export class ExecutorProgramServiceTest extends ExecutorProgramService {
|
export class ExecutorProgramServiceTest extends ExecutorProgramService {
|
||||||
|
@ -19,7 +19,7 @@ export class ExecutorProgramServiceTest extends ExecutorProgramService {
|
||||||
dirname__ + "/"
|
dirname__ + "/"
|
||||||
);
|
);
|
||||||
executorProgramService.call(EXEC_TYPE.SPAWN, "node", [
|
executorProgramService.call(EXEC_TYPE.SPAWN, "node", [
|
||||||
"./mocks/log_code.js",
|
"./mocks/log_code",
|
||||||
]);
|
]);
|
||||||
const test = TestCore.instance;
|
const test = TestCore.instance;
|
||||||
let testIsOk = false;
|
let testIsOk = false;
|
||||||
|
@ -45,7 +45,7 @@ export class ExecutorProgramServiceTest extends ExecutorProgramService {
|
||||||
const executorProgramService = await new ExecutorProgramService(dirname__);
|
const executorProgramService = await new ExecutorProgramService(dirname__);
|
||||||
executorProgramService.call(
|
executorProgramService.call(
|
||||||
EXEC_TYPE.EXEC,
|
EXEC_TYPE.EXEC,
|
||||||
"node ./test/mocks/log_code.js"
|
"node ./test/mocks/log_code"
|
||||||
);
|
);
|
||||||
const test = TestCore.instance;
|
const test = TestCore.instance;
|
||||||
executorProgramService.on((e) => {
|
executorProgramService.on((e) => {
|
||||||
|
@ -63,7 +63,7 @@ export class ExecutorProgramServiceTest extends ExecutorProgramService {
|
||||||
const executorProgramService = await new ExecutorProgramService("", 1000);
|
const executorProgramService = await new ExecutorProgramService("", 1000);
|
||||||
executorProgramService.call(
|
executorProgramService.call(
|
||||||
EXEC_TYPE.EXEC,
|
EXEC_TYPE.EXEC,
|
||||||
"node ./test/mocks/long_code.js"
|
"node ./test/mocks/long_code"
|
||||||
);
|
);
|
||||||
await delay(1500);
|
await delay(1500);
|
||||||
const worker = executorProgramService.worker as Worker;
|
const worker = executorProgramService.worker as Worker;
|
||||||
|
@ -73,7 +73,7 @@ export class ExecutorProgramServiceTest extends ExecutorProgramService {
|
||||||
private resultsTests = async () => {
|
private resultsTests = async () => {
|
||||||
await resultTest(
|
await resultTest(
|
||||||
new ExecutorProgramService(dirname__),
|
new ExecutorProgramService(dirname__),
|
||||||
[EXEC_TYPE.EXEC, "node ./mocks/error.js"],
|
[EXEC_TYPE.EXEC, "node ./mocks/error"],
|
||||||
"ExecutorProgramService EXEC_TYPE.EXEC on Result.error",
|
"ExecutorProgramService EXEC_TYPE.EXEC on Result.error",
|
||||||
false,
|
false,
|
||||||
4000
|
4000
|
||||||
|
@ -94,7 +94,7 @@ export class ExecutorProgramServiceTest extends ExecutorProgramService {
|
||||||
);
|
);
|
||||||
await resultTest(
|
await resultTest(
|
||||||
new ExecutorProgramService(dirname__),
|
new ExecutorProgramService(dirname__),
|
||||||
[EXEC_TYPE.SPAWN, "python3 ./mocks/s.js"],
|
[EXEC_TYPE.SPAWN, "python3 ./mocks/s"],
|
||||||
"ExecutorProgramService EXEC_TYPE.SPAWN on Result.error",
|
"ExecutorProgramService EXEC_TYPE.SPAWN on Result.error",
|
||||||
false,
|
false,
|
||||||
2000
|
2000
|
|
@ -1,8 +1,8 @@
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { FilesChangeNotifierService } from "../../src/core/services/files_change_notifier_service.js";
|
import { FilesChangeNotifierService } from "../../src/core/services/files_change_notifier_service";
|
||||||
import { EventsFileChanger } from "../../src/core/model/meta_data_file_manager_model.js";
|
import { EventsFileChanger } from "../../src/core/model/meta_data_file_manager_model";
|
||||||
import { assert, dirname__ } from "../test.js";
|
import { assert, dirname__ } from "../test";
|
||||||
import { delay } from "../../src/core/helper/delay.js";
|
import { delay } from "../../src/core/helper/delay";
|
||||||
|
|
||||||
export class FilesChangerTest extends FilesChangeNotifierService {
|
export class FilesChangerTest extends FilesChangeNotifierService {
|
||||||
directory = dirname__ + "/context/";
|
directory = dirname__ + "/context/";
|
|
@ -4,12 +4,12 @@ import * as fs from "fs";
|
||||||
import {
|
import {
|
||||||
IssueType,
|
IssueType,
|
||||||
StackGenerateType,
|
StackGenerateType,
|
||||||
TriggerType,
|
} from "../../src/core/model/process_model";
|
||||||
} from "../../src/core/model/process_model.js";
|
import { EXEC_TYPE } from "../../src/core/model/exec_error_model";
|
||||||
import { EXEC_TYPE } from "../../src/core/model/exec_error_model.js";
|
import { StackService } from "../../src/core/services/stack_service";
|
||||||
import { StackService } from "../../src/core/services/stack_service.js";
|
import { delay } from "../../src/core/helper/delay";
|
||||||
import { delay } from "../../src/core/helper/delay.js";
|
import { assert, dirname__ } from "../test";
|
||||||
import { assert, dirname__ } from "../test.js";
|
import { TriggerType } from "../../src/features/triggers/trigger_model";
|
||||||
|
|
||||||
abstract class IStackServiceTest {
|
abstract class IStackServiceTest {
|
||||||
abstract test(): Promise<boolean>;
|
abstract test(): Promise<boolean>;
|
|
@ -1,10 +1,11 @@
|
||||||
import {
|
import {
|
||||||
EventsFileChanger,
|
EventsFileChanger,
|
||||||
MetaDataFileManagerModel,
|
MetaDataFileManagerModel,
|
||||||
} from "../../src/core/model/meta_data_file_manager_model.js";
|
} from "../../src/core/model/meta_data_file_manager_model";
|
||||||
import { TriggerType } from "../../src/core/model/process_model.js";
|
|
||||||
import { TriggerService } from "../../src/core/services/trigger_service.js";
|
import { TriggerService } from "../../src/core/services/trigger_service";
|
||||||
import { assert } from "../test.js";
|
import { TriggerType } from "../../src/features/triggers/trigger_model";
|
||||||
|
import { assert } from "../test";
|
||||||
abstract class TriggerTest {
|
abstract class TriggerTest {
|
||||||
abstract test(): Promise<boolean>;
|
abstract test(): Promise<boolean>;
|
||||||
}
|
}
|
|
@ -1,17 +1,21 @@
|
||||||
import locator from "../src/core/di/register_di.js";
|
import { TestCore } from "./core/test_core";
|
||||||
import { UnitTestEnv } from "../src/core/di/env.js";
|
import { UnitTestEnv } from "../src/core/di/env";
|
||||||
import { fileURLToPath } from "url";
|
|
||||||
import { dirname } from "path";
|
import { dirname } from "path";
|
||||||
import { ExecutorProgramServiceTest } from "./features/executor_program_service_test.js";
|
import locator from "../src/core/di/register_di";
|
||||||
import { FilesChangerTest } from "./features/files_change_notifier_service_test.js";
|
import { ExecutorProgramServiceTest } from "./services/executor_program_service_test";
|
||||||
import { TestCore } from "./core/test_core.js";
|
import { FilesChangerTest } from "./services/files_change_notifier_service_test";
|
||||||
import "reflect-metadata";
|
import { TriggerServiceTest } from "./services/trigger_service_test";
|
||||||
import { StackServiceTest } from "./features/stack_service_test.js";
|
import { StackServiceTest } from "./services/stack_service_test";
|
||||||
import { TriggerServiceTest } from "./features/trigger_service_test.js";
|
import mongoose from "mongoose";
|
||||||
|
import { CreateDataBaseModelUseCaseTest } from "./usecases/create_database_model_usecase_test";
|
||||||
|
import { DeleteDataBaseModelUseCaseTest } from "./usecases/delete_database_model_usecase_test";
|
||||||
|
import { ReadDataBaseModelUseCaseTest } from "./usecases/read_database_model_usecase_test";
|
||||||
|
import { UpdateDataBaseModelUseCaseTest } from "./usecases/update_database_model_usecase";
|
||||||
|
import { PaginationDataBaseModelUseCaseTest } from "./usecases/pagination_database_model_usecase_test";
|
||||||
|
|
||||||
|
|
||||||
const testCore = TestCore.instance;
|
const testCore = TestCore.instance;
|
||||||
const __filename: string = fileURLToPath(import.meta.url);
|
|
||||||
|
|
||||||
export const dirname__: string = dirname(__filename);
|
export const dirname__: string = dirname(__filename);
|
||||||
export const assert = testCore.assert;
|
export const assert = testCore.assert;
|
||||||
export const resultTest = testCore.resultTest;
|
export const resultTest = testCore.resultTest;
|
||||||
|
@ -19,11 +23,29 @@ const env = new UnitTestEnv(dirname__);
|
||||||
|
|
||||||
locator(env);
|
locator(env);
|
||||||
|
|
||||||
const main = async () => {
|
const tests = [CreateDataBaseModelUseCaseTest, DeleteDataBaseModelUseCaseTest,ReadDataBaseModelUseCaseTest,UpdateDataBaseModelUseCaseTest, PaginationDataBaseModelUseCaseTest]
|
||||||
|
const init = async () =>{
|
||||||
|
await mongoose.connect('mongodb://127.0.0.1:27017/test')
|
||||||
|
}
|
||||||
|
|
||||||
|
const test = async () =>{
|
||||||
await new ExecutorProgramServiceTest(dirname__).test();
|
await new ExecutorProgramServiceTest(dirname__).test();
|
||||||
await new FilesChangerTest(dirname__).test();
|
await new FilesChangerTest(dirname__).test();
|
||||||
await new StackServiceTest(dirname__ + "/context/").test();
|
await new StackServiceTest(dirname__ + "/context/").test();
|
||||||
await new TriggerServiceTest().test();
|
await new TriggerServiceTest().test();
|
||||||
|
await new CreateDataBaseModelUseCaseTest().test()
|
||||||
|
|
||||||
|
await new CreateDataBaseModelUseCaseTest().test()
|
||||||
|
await new DeleteDataBaseModelUseCaseTest().test()
|
||||||
|
await new ReadDataBaseModelUseCaseTest().test()
|
||||||
|
await new UpdateDataBaseModelUseCaseTest().test()
|
||||||
|
for await (const usecase of tests) {
|
||||||
|
testCore.assert(await new usecase().test(), usecase.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const main = async () => {
|
||||||
|
await init()
|
||||||
|
await test()
|
||||||
await testCore.testResult();
|
await testCore.testResult();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
12
server/test/usecases/create_database_model_usecase_test.ts
Normal file
12
server/test/usecases/create_database_model_usecase_test.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { CreateDataBaseModelUseCase } from "../../src/core/usecases/create_database_model_usecase";
|
||||||
|
import { ITestModel, TestDBModel } from "../model/test_db_mongo_model";
|
||||||
|
|
||||||
|
export class CreateDataBaseModelUseCaseTest {
|
||||||
|
async test() {
|
||||||
|
return (
|
||||||
|
await new CreateDataBaseModelUseCase<ITestModel>(TestDBModel).call({
|
||||||
|
result: "test",
|
||||||
|
})
|
||||||
|
).isSuccess();
|
||||||
|
}
|
||||||
|
}
|
29
server/test/usecases/delete_database_model_usecase_test.ts
Normal file
29
server/test/usecases/delete_database_model_usecase_test.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { CreateDataBaseModelUseCase } from "../../src/core/usecases/create_database_model_usecase";
|
||||||
|
import { DeleteDataBaseModelUseCase } from "../../src/core/usecases/delete_database_model_usecase";
|
||||||
|
import { ITestModel, TestDBModel } from "../model/test_db_mongo_model";
|
||||||
|
|
||||||
|
export class DeleteDataBaseModelUseCaseTest {
|
||||||
|
async test() {
|
||||||
|
let testIsSuccess = false;
|
||||||
|
|
||||||
|
const result = await new CreateDataBaseModelUseCase<ITestModel>(TestDBModel).call({
|
||||||
|
result: "test",
|
||||||
|
});
|
||||||
|
|
||||||
|
await result.fold(
|
||||||
|
async (s) => {
|
||||||
|
(await new DeleteDataBaseModelUseCase(TestDBModel).call(s.id)).fold(
|
||||||
|
(_s1) => {
|
||||||
|
testIsSuccess = true;
|
||||||
|
},
|
||||||
|
(_e1) => {}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
async (_e) => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return testIsSuccess;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { PaginationDataBaseModelUseCase } from "../../src/core/usecases/pagination_database_model_usecase";
|
||||||
|
import { ITestModel, TestDBModel } from "../model/test_db_mongo_model";
|
||||||
|
|
||||||
|
export class PaginationDataBaseModelUseCaseTest {
|
||||||
|
async test() {
|
||||||
|
let testIsSuccess = false;
|
||||||
|
await (
|
||||||
|
await new PaginationDataBaseModelUseCase<ITestModel>(TestDBModel, 1).call(
|
||||||
|
1
|
||||||
|
)
|
||||||
|
).fold(
|
||||||
|
(s) => {
|
||||||
|
testIsSuccess = s.length === 1;
|
||||||
|
},
|
||||||
|
(_e) => {}
|
||||||
|
);
|
||||||
|
return testIsSuccess;
|
||||||
|
}
|
||||||
|
}
|
32
server/test/usecases/read_database_model_usecase_test.ts
Normal file
32
server/test/usecases/read_database_model_usecase_test.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import { CreateDataBaseModelUseCase } from "../../src/core/usecases/create_database_model_usecase";
|
||||||
|
import { ReadByIdDataBaseModelUseCase } from "../../src/core/usecases/read_database_model_usecase";
|
||||||
|
import { ITestModel, TestDBModel } from "../model/test_db_mongo_model";
|
||||||
|
|
||||||
|
export class ReadDataBaseModelUseCaseTest {
|
||||||
|
async test() {
|
||||||
|
let testIsSuccess = false;
|
||||||
|
|
||||||
|
const result = await new CreateDataBaseModelUseCase<ITestModel>(
|
||||||
|
TestDBModel
|
||||||
|
).call({
|
||||||
|
result: "test",
|
||||||
|
});
|
||||||
|
await result.fold(
|
||||||
|
async (s) => {
|
||||||
|
const r = await new ReadByIdDataBaseModelUseCase<ITestModel>(
|
||||||
|
TestDBModel
|
||||||
|
).call(s.id);
|
||||||
|
await r.fold(
|
||||||
|
(_s1) => {
|
||||||
|
testIsSuccess = true;
|
||||||
|
|
||||||
|
},
|
||||||
|
(_e) => {}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
async (_e) => {}
|
||||||
|
);
|
||||||
|
|
||||||
|
return testIsSuccess;
|
||||||
|
}
|
||||||
|
}
|
35
server/test/usecases/update_database_model_usecase.ts
Normal file
35
server/test/usecases/update_database_model_usecase.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import { CreateDataBaseModelUseCase } from "../../src/core/usecases/create_database_model_usecase";
|
||||||
|
import { UpdateDataBaseModelUseCase } from "../../src/core/usecases/update_database_model_usecase";
|
||||||
|
import { ITestModel, TestDBModel } from "../model/test_db_mongo_model";
|
||||||
|
|
||||||
|
export class UpdateDataBaseModelUseCaseTest {
|
||||||
|
async test() {
|
||||||
|
let testIsSuccess = false;
|
||||||
|
|
||||||
|
const model = await new CreateDataBaseModelUseCase<ITestModel>(
|
||||||
|
TestDBModel
|
||||||
|
).call({
|
||||||
|
result: "test",
|
||||||
|
});
|
||||||
|
await model.fold(
|
||||||
|
async (s) => {
|
||||||
|
(
|
||||||
|
await new UpdateDataBaseModelUseCase<any, ITestModel>(
|
||||||
|
TestDBModel
|
||||||
|
).call({
|
||||||
|
_id:s.id,
|
||||||
|
result: "complete",
|
||||||
|
})
|
||||||
|
).fold(
|
||||||
|
(s1) => {
|
||||||
|
testIsSuccess = s1.result === "complete";
|
||||||
|
},
|
||||||
|
(_e1) => {}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
async (_e) => {}
|
||||||
|
);
|
||||||
|
|
||||||
|
return testIsSuccess;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,25 +1,19 @@
|
||||||
{
|
{
|
||||||
|
"compileOnSave": false,
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2020",
|
"target": "es2017",
|
||||||
"module": "ESNext",
|
"allowSyntheticDefaultImports": true,
|
||||||
"removeComments": true,
|
"experimentalDecorators": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"experimentalDecorators": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"lib": [
|
"moduleResolution": "node",
|
||||||
"esnext",
|
"pretty": true,
|
||||||
"dom"
|
"declaration": true,
|
||||||
],
|
"outDir": "./build",
|
||||||
"moduleResolution":"node",
|
"allowJs": true,
|
||||||
"sourceMap": true,
|
"noEmit": false,
|
||||||
"noImplicitReturns": true,
|
"esModuleInterop": true,
|
||||||
"noUnusedParameters": true,
|
"resolveJsonModule": true,
|
||||||
"pretty": true,
|
"importHelpers": true,
|
||||||
"strict": true,
|
}
|
||||||
"skipLibCheck": true,
|
}
|
||||||
"noImplicitAny": false
|
|
||||||
// "moduleResolution": "node"
|
|
||||||
},
|
|
||||||
// "include": ["src/**/*.ts", "src/**/*.json", ".env"],
|
|
||||||
// "exclude": ["node_modules"]
|
|
||||||
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue