Refactoring
This commit is contained in:
parent
11ca9cdb5e
commit
7ff6165882
22 changed files with 172 additions and 327 deletions
3
server/.vscode/settings.json
vendored
Normal file
3
server/.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"cSpell.words": ["fileupload", "Metadatas", "readir"]
|
||||||
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import { Routes } from "../interfaces/router";
|
|
||||||
import cors from "cors";
|
import cors from "cors";
|
||||||
|
import fileUpload from "express-fileupload";
|
||||||
|
import { Routes } from "../interfaces/router";
|
||||||
import { Server } from "socket.io";
|
import { Server } from "socket.io";
|
||||||
import { createServer } from "http";
|
import { createServer } from "http";
|
||||||
import { SocketSubscriber } from "./socket_controller";
|
import { SocketSubscriber } from "./socket_controller";
|
||||||
import { dirname } from "path";
|
import { dirname } from "path";
|
||||||
import fileUpload from "express-fileupload";
|
|
||||||
import { SetLastActivePipelineToRealTimeServiceScenario } from "../scenarios/set_active_pipeline_to_realtime_service_scenario";
|
import { SetLastActivePipelineToRealTimeServiceScenario } from "../scenarios/set_active_pipeline_to_realtime_service_scenario";
|
||||||
import { CheckAndCreateStaticFilesFolderUseCase } from "../usecases/check_and_create_static_files_folder_usecase";
|
import { CheckAndCreateStaticFilesFolderUseCase } from "../usecases/check_and_create_static_files_folder_usecase";
|
||||||
import { DataBaseConnectUseCase } from "../usecases/database_connect_usecase";
|
import { DataBaseConnectUseCase } from "../usecases/database_connect_usecase";
|
||||||
|
@ -13,7 +13,7 @@ import { TypedEvent } from "../helpers/typed_event";
|
||||||
|
|
||||||
export enum ServerStatus {
|
export enum ServerStatus {
|
||||||
init = "init",
|
init = "init",
|
||||||
finished = "finshed",
|
finished = "finished",
|
||||||
error = "error",
|
error = "error",
|
||||||
}
|
}
|
||||||
export enum Environment {
|
export enum Environment {
|
||||||
|
|
8
server/src/core/extensions/buffer.ts
Normal file
8
server/src/core/extensions/buffer.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
export const BufferExtensions = () => {
|
||||||
|
if (Buffer.joinBuffers === undefined) {
|
||||||
|
Buffer.prototype.joinBuffers = function (buffers: Array<Buffer>, delimiter = " ") {
|
||||||
|
const d = Buffer.from(delimiter);
|
||||||
|
return buffers.reduce((prev, b) => Buffer.concat([prev, d, b]));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,4 +1,5 @@
|
||||||
import { ArrayExtensions } from "./array";
|
import { ArrayExtensions } from "./array";
|
||||||
|
import { BufferExtensions } from "./buffer";
|
||||||
import { StringExtensions } from "./string";
|
import { StringExtensions } from "./string";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -10,6 +11,9 @@ declare global {
|
||||||
isEmpty(): boolean;
|
isEmpty(): boolean;
|
||||||
isNotEmpty(): boolean;
|
isNotEmpty(): boolean;
|
||||||
}
|
}
|
||||||
|
interface BufferConstructor {
|
||||||
|
joinBuffers(buffers: Array<Buffer>, delimiter?: string);
|
||||||
|
}
|
||||||
interface String {
|
interface String {
|
||||||
isEmpty(): boolean;
|
isEmpty(): boolean;
|
||||||
isNotEmpty(): boolean;
|
isNotEmpty(): boolean;
|
||||||
|
@ -21,4 +25,5 @@ declare global {
|
||||||
export const extensions = () => {
|
export const extensions = () => {
|
||||||
ArrayExtensions();
|
ArrayExtensions();
|
||||||
StringExtensions();
|
StringExtensions();
|
||||||
|
BufferExtensions();
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,8 +8,19 @@ export interface Disposable {
|
||||||
|
|
||||||
export class TypedEvent<T> {
|
export class TypedEvent<T> {
|
||||||
private listeners: Listener<T>[] = [];
|
private listeners: Listener<T>[] = [];
|
||||||
|
|
||||||
public listenersOnces: Listener<T>[] = [];
|
public listenersOnces: Listener<T>[] = [];
|
||||||
|
|
||||||
|
waitedEvent(predicate: (e: T) => boolean) {
|
||||||
|
return new Promise<T>((resolve, _reject) => {
|
||||||
|
this.on((e) => {
|
||||||
|
const isContinueWatching = predicate(e);
|
||||||
|
if (!isContinueWatching) {
|
||||||
|
resolve(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
on = (listener: Listener<T>): Disposable => {
|
on = (listener: Listener<T>): Disposable => {
|
||||||
this.listeners.push(listener);
|
this.listeners.push(listener);
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
// 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
|
|
||||||
// }
|
|
||||||
// }
|
|
43
server/src/core/repository/file_system_repository.ts
Normal file
43
server/src/core/repository/file_system_repository.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { promisify } from "node:util";
|
||||||
|
|
||||||
|
export class FileSystemRepository {
|
||||||
|
public createDir = promisify(fs.mkdir);
|
||||||
|
public lsStat = promisify(fs.lstat);
|
||||||
|
public writeFileAsync = promisify(fs.writeFile);
|
||||||
|
public dirIsExists = promisify(fs.exists);
|
||||||
|
public stat = promisify(fs.stat);
|
||||||
|
public readFileAsync = promisify(fs.readFile);
|
||||||
|
public readdir = promisify(fs.readdir);
|
||||||
|
|
||||||
|
async readFileAtBuffer(path: string): Promise<Buffer> {
|
||||||
|
if ((await this.lsStat(path)).isDirectory()) {
|
||||||
|
return (
|
||||||
|
await this.readdir(path, {
|
||||||
|
encoding: "buffer",
|
||||||
|
})
|
||||||
|
).reduce((accumulator, currentValue) => Buffer.joinBuffers([accumulator, currentValue]), Buffer.from(""));
|
||||||
|
}
|
||||||
|
return await this.readFileAsync(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
readDirRecursive(path: string, filesToDir: string[] = []): string[] {
|
||||||
|
const files = fs.readdirSync(path);
|
||||||
|
files.forEach((file) => {
|
||||||
|
let filePath = "";
|
||||||
|
if (path[path.length - 1] !== "/") {
|
||||||
|
filePath = `${path}/${file}`;
|
||||||
|
} else {
|
||||||
|
filePath = `${path}${file}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stats = fs.statSync(filePath);
|
||||||
|
if (stats.isDirectory()) {
|
||||||
|
this.readDirRecursive(filePath, filesToDir);
|
||||||
|
} else {
|
||||||
|
filesToDir.push(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return filesToDir;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,31 +0,0 @@
|
||||||
import * as fs from "fs";
|
|
||||||
import { promisify } from "node:util";
|
|
||||||
|
|
||||||
export const readFileAsync = promisify(fs.readFile);
|
|
||||||
export const readdir = promisify(fs.readdir);
|
|
||||||
export const stat = promisify(fs.stat);
|
|
||||||
export const lsStat = promisify(fs.lstat);
|
|
||||||
export const createDir = promisify(fs.mkdir);
|
|
||||||
export const dirIsExists = promisify(fs.exists);
|
|
||||||
|
|
||||||
export const writeFileAsync = promisify(fs.writeFile);
|
|
||||||
|
|
||||||
export function readDirRecursive(path: string, filesToDir: string[] = []) {
|
|
||||||
const files = fs.readdirSync(path);
|
|
||||||
files.forEach((file) => {
|
|
||||||
let filePath = "";
|
|
||||||
if (path[path.length - 1] !== "/") {
|
|
||||||
filePath = `${path}/${file}`;
|
|
||||||
} else {
|
|
||||||
filePath = `${path}${file}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const stats = fs.statSync(filePath);
|
|
||||||
if (stats.isDirectory()) {
|
|
||||||
readDirRecursive(filePath, filesToDir);
|
|
||||||
} else {
|
|
||||||
filesToDir.push(file);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return filesToDir;
|
|
||||||
}
|
|
|
@ -27,7 +27,7 @@ export class ExecutorProgramService
|
||||||
|
|
||||||
private async workerExecuted(command: string, workerType: WorkerType, args: Array<string> | undefined = undefined) {
|
private async workerExecuted(command: string, workerType: WorkerType, args: Array<string> | undefined = undefined) {
|
||||||
cluster.setupPrimary({
|
cluster.setupPrimary({
|
||||||
exec: "/Users/idontsudo/Desktop/testdeck-mocha-seed/server/build/src/core/helpers/worker_computed.js",
|
exec: __dirname + "/../helpers/worker_computed.js",
|
||||||
});
|
});
|
||||||
|
|
||||||
const worker = cluster.fork();
|
const worker = cluster.fork();
|
||||||
|
@ -45,17 +45,21 @@ export class ExecutorProgramService
|
||||||
worker.send(workerDataExec);
|
worker.send(workerDataExec);
|
||||||
worker.on("message", (e) => {
|
worker.on("message", (e) => {
|
||||||
const spawnError = SpawnError.isError(e);
|
const spawnError = SpawnError.isError(e);
|
||||||
|
|
||||||
if (spawnError instanceof SpawnError) {
|
if (spawnError instanceof SpawnError) {
|
||||||
this.emit(Result.error(spawnError));
|
this.emit(Result.error(spawnError));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const executorResult = ExecutorResult.isExecutorResult(e);
|
const executorResult = ExecutorResult.isExecutorResult(e);
|
||||||
|
|
||||||
if (executorResult instanceof ExecutorResult) {
|
if (executorResult instanceof ExecutorResult) {
|
||||||
this.emit(Result.ok(executorResult));
|
this.emit(Result.ok(executorResult));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const execError = ExecError.isExecError(e);
|
const execError = ExecError.isExecError(e);
|
||||||
|
|
||||||
if (execError instanceof ExecError) {
|
if (execError instanceof ExecError) {
|
||||||
this.emit(Result.error(execError));
|
this.emit(Result.error(execError));
|
||||||
return;
|
return;
|
||||||
|
@ -78,6 +82,7 @@ export class ExecutorProgramService
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.workerExecuted(command, WorkerType.SPAWN, args);
|
this.workerExecuted(command, WorkerType.SPAWN, args);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,23 +5,7 @@ import { BinaryLike } from "crypto";
|
||||||
import { EventsFileChanger, MetaDataFileManagerModel } from "../models/meta_data_file_manager_model";
|
import { EventsFileChanger, MetaDataFileManagerModel } from "../models/meta_data_file_manager_model";
|
||||||
import { Result } from "../helpers/result";
|
import { Result } from "../helpers/result";
|
||||||
import { TypedEvent } from "../helpers/typed_event";
|
import { TypedEvent } from "../helpers/typed_event";
|
||||||
import { lsStat, readFileAsync, readdir, stat } from "../repository/fs";
|
import { FileSystemRepository } from "../repository/file_system_repository";
|
||||||
|
|
||||||
function joinBuffers(buffers: Array<Buffer>, delimiter = " ") {
|
|
||||||
const d = Buffer.from(delimiter);
|
|
||||||
return buffers.reduce((prev, b) => Buffer.concat([prev, d, b]));
|
|
||||||
}
|
|
||||||
|
|
||||||
async function readFileAtBuffer(path: string): Promise<Buffer> {
|
|
||||||
if ((await lsStat(path)).isDirectory()) {
|
|
||||||
return (
|
|
||||||
await readdir(path, {
|
|
||||||
encoding: "buffer",
|
|
||||||
})
|
|
||||||
).reduce((accumulator, currentValue) => joinBuffers([accumulator, currentValue]), Buffer.from(""));
|
|
||||||
}
|
|
||||||
return await readFileAsync(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
function md5(content: Buffer | BinaryLike): Promise<string> {
|
function md5(content: Buffer | BinaryLike): Promise<string> {
|
||||||
return new Promise((resolve, _reject) => {
|
return new Promise((resolve, _reject) => {
|
||||||
|
@ -41,12 +25,14 @@ export class FilesChangeNotifierService
|
||||||
extends TypedEvent<Result<Error, IHashesCache>>
|
extends TypedEvent<Result<Error, IHashesCache>>
|
||||||
implements IFilesChangeNotifierService
|
implements IFilesChangeNotifierService
|
||||||
{
|
{
|
||||||
|
fileSystemRepository: FileSystemRepository;
|
||||||
watcher!: fs.FSWatcher;
|
watcher!: fs.FSWatcher;
|
||||||
directory: string;
|
directory: string;
|
||||||
constructor(directory: string) {
|
constructor(directory: string) {
|
||||||
super();
|
super();
|
||||||
this.directory = directory;
|
this.directory = directory;
|
||||||
this.init();
|
this.init();
|
||||||
|
this.fileSystemRepository = new FileSystemRepository();
|
||||||
}
|
}
|
||||||
hashes: IHashesCache = {};
|
hashes: IHashesCache = {};
|
||||||
async init() {
|
async init() {
|
||||||
|
@ -56,18 +42,18 @@ export class FilesChangeNotifierService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async setHash(file: string) {
|
async setHash(file: string) {
|
||||||
const data = await readFileAsync(file);
|
const data = await this.fileSystemRepository.readFileAsync(file);
|
||||||
const md5Current = await md5(data);
|
const md5Current = await md5(data);
|
||||||
|
|
||||||
this.hashes[file] = new MetaDataFileManagerModel(file, md5Current, EventsFileChanger.static);
|
this.hashes[file] = new MetaDataFileManagerModel(file, md5Current, EventsFileChanger.static);
|
||||||
this.emit(Result.ok(this.hashes));
|
this.emit(Result.ok(this.hashes));
|
||||||
}
|
}
|
||||||
async getFiles(dir: string): Promise<string | any[]> {
|
async getFiles(dir: string): Promise<string | any[]> {
|
||||||
const subdirs = await readdir(dir);
|
const subdirs = await new FileSystemRepository().readdir(dir);
|
||||||
const files = await Promise.all(
|
const files = await Promise.all(
|
||||||
subdirs.map(async (subdir) => {
|
subdirs.map(async (subdir) => {
|
||||||
const res = resolve(dir, subdir);
|
const res = resolve(dir, subdir);
|
||||||
return (await stat(res)).isDirectory() ? this.getFiles(res) : res;
|
return (await this.fileSystemRepository.stat(res)).isDirectory() ? this.getFiles(res) : res;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return files.reduce((a: string | any[], f: any) => a.concat(f), []);
|
return files.reduce((a: string | any[], f: any) => a.concat(f), []);
|
||||||
|
@ -85,7 +71,7 @@ export class FilesChangeNotifierService
|
||||||
fsWait = false;
|
fsWait = false;
|
||||||
}, 100);
|
}, 100);
|
||||||
try {
|
try {
|
||||||
const file = await readFileAtBuffer(filePath);
|
const file = await this.fileSystemRepository.readFileAtBuffer(filePath);
|
||||||
const md5Current = await md5(file);
|
const md5Current = await md5(file);
|
||||||
if (md5Current === md5Previous) {
|
if (md5Current === md5Previous) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -45,71 +45,55 @@ export class StackService extends TypedEvent<Iteration[]> implements IStackServi
|
||||||
return processMetaData;
|
return processMetaData;
|
||||||
}
|
}
|
||||||
public async call() {
|
public async call() {
|
||||||
let inc = 0;
|
this.callStack.map(async (el, index) => {
|
||||||
|
await this.execStack(index, el);
|
||||||
for await (const el of this.callStack!) {
|
|
||||||
await this.execStack(inc, el);
|
|
||||||
inc += 1;
|
|
||||||
this.emit(this.callStack);
|
this.emit(this.callStack);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
async execStack(stackNumber: number, stackLayer: Iteration): Promise<void | boolean> {
|
async execStack(stackNumber: number, stackLayer: Iteration): Promise<void | boolean> {
|
||||||
const executorService = new ExecutorProgramService(this.path);
|
const executorService = new ExecutorProgramService(this.path);
|
||||||
executorService.call(stackLayer.process.process.type, stackLayer.process.process.command);
|
executorService.call(stackLayer.process.process.type, stackLayer.process.process.command);
|
||||||
|
executorService.on((e) => {
|
||||||
|
console.log(e);
|
||||||
|
});
|
||||||
const filesChangeNotifierService = new FilesChangeNotifierService(this.path);
|
const filesChangeNotifierService = new FilesChangeNotifierService(this.path);
|
||||||
|
|
||||||
filesChangeNotifierService.call();
|
filesChangeNotifierService.call();
|
||||||
const result = await this.waitEvent<Result<ExecError | SpawnError, ExecutorResult>>(executorService);
|
|
||||||
await delay(100);
|
|
||||||
if (result.isSuccess()) {
|
|
||||||
this.callStack[stackNumber].result = result.value;
|
|
||||||
this.callStack[stackNumber].hashes = filesChangeNotifierService.hashes;
|
|
||||||
|
|
||||||
const triggerResult = await this.triggerExec(stackLayer.process.trigger, stackNumber);
|
const result = await executorService.waitedEvent((event: Result<ExecError | SpawnError, ExecutorResult>) => {
|
||||||
triggerResult.fold(
|
event.map((value) => {
|
||||||
(s) => {
|
if (value.event === EXEC_EVENT.END) {
|
||||||
s;
|
return true;
|
||||||
},
|
|
||||||
(e) => {
|
|
||||||
e;
|
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
}
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
await delay(100);
|
||||||
|
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(() => {
|
||||||
|
filesChangeNotifierService.cancel();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
filesChangeNotifierService.cancel();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
public waitEvent<T>(stream: TypedEvent<T>): Promise<T> {
|
|
||||||
const promise = new Promise<T>((resolve, reject) => {
|
|
||||||
const addListener = () => {
|
|
||||||
stream.on((e) => {
|
|
||||||
const event = e as Result<ExecError | SpawnError, ExecutorResult>;
|
|
||||||
event.fold(
|
|
||||||
(s) => {
|
|
||||||
if (s.event === EXEC_EVENT.END) {
|
|
||||||
resolve(e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(e) => {
|
|
||||||
reject(e);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
addListener();
|
|
||||||
});
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
private async triggerExec(trigger: Trigger | null, stackNumber: number): Promise<Result<boolean, boolean>> {
|
|
||||||
if (trigger !== null) {
|
|
||||||
const hashes = this.callStack[stackNumber].hashes;
|
|
||||||
|
|
||||||
if (hashes != null) {
|
private async triggerExec(trigger: Trigger | null, stackNumber: number): Promise<Result<Error, void>> {
|
||||||
return await new TriggerService(trigger, hashes, this.path).call();
|
try {
|
||||||
|
if (trigger !== null) {
|
||||||
|
const hashes = this.callStack[stackNumber].hashes;
|
||||||
|
|
||||||
|
if (hashes != null) {
|
||||||
|
await new TriggerService(trigger, hashes, this.path).call();
|
||||||
|
}
|
||||||
|
throw new Error("Hashes is null");
|
||||||
}
|
}
|
||||||
throw new Error("Hashes is null");
|
return Result.ok();
|
||||||
|
} catch (error) {
|
||||||
|
return Result.error(error);
|
||||||
}
|
}
|
||||||
return Result.ok();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
import { App } from "../controllers/app";
|
import { App } from "../controllers/app";
|
||||||
import { dirIsExists } from "../repository/fs";
|
import { FileSystemRepository } from "../repository/file_system_repository";
|
||||||
import { CreateFolderUseCase } from "./crete_folder_usecase";
|
import { CreateFolderUseCase } from "./crete_folder_usecase";
|
||||||
|
|
||||||
export class CheckAndCreateStaticFilesFolderUseCase {
|
export class CheckAndCreateStaticFilesFolderUseCase {
|
||||||
|
fileSystemRepository: FileSystemRepository;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.fileSystemRepository = new FileSystemRepository();
|
||||||
|
}
|
||||||
call = async (): Promise<void> => {
|
call = async (): Promise<void> => {
|
||||||
if (await dirIsExists(App.staticFilesStoreDir())) {
|
if (await this.fileSystemRepository.dirIsExists(App.staticFilesStoreDir())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const createFolderUseCase = await new CreateFolderUseCase().call(App.staticFilesStoreDir());
|
const createFolderUseCase = await new CreateFolderUseCase().call(App.staticFilesStoreDir());
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
import { Result } from "../helpers/result";
|
import { Result } from "../helpers/result";
|
||||||
import { writeFileAsync } from "../repository/fs";
|
import { FileSystemRepository } from "../repository/file_system_repository";
|
||||||
|
|
||||||
export class CreateFileUseCase {
|
export class CreateFileUseCase {
|
||||||
|
fileSystemRepository: FileSystemRepository;
|
||||||
|
constructor() {
|
||||||
|
this.fileSystemRepository = new FileSystemRepository();
|
||||||
|
}
|
||||||
async call(path: string, buffer: Buffer): Promise<Result<Error, void>> {
|
async call(path: string, buffer: Buffer): Promise<Result<Error, void>> {
|
||||||
try {
|
try {
|
||||||
await writeFileAsync(path, buffer);
|
await this.fileSystemRepository.writeFileAsync(path, buffer);
|
||||||
return Result.ok();
|
return Result.ok();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return Result.error(err as Error);
|
return Result.error(err as Error);
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
import { Result } from "../helpers/result";
|
import { Result } from "../helpers/result";
|
||||||
import { dirIsExists, createDir } from "../repository/fs";
|
import { FileSystemRepository } from "../repository/file_system_repository";
|
||||||
|
|
||||||
export class CreateFolderUseCase {
|
export class CreateFolderUseCase {
|
||||||
|
fileSystemRepository: FileSystemRepository;
|
||||||
|
constructor() {
|
||||||
|
this.fileSystemRepository = new FileSystemRepository();
|
||||||
|
}
|
||||||
call = async (path: string): Promise<Result<Error, string>> => {
|
call = async (path: string): Promise<Result<Error, string>> => {
|
||||||
try {
|
try {
|
||||||
if (await dirIsExists(path)) {
|
if (await this.fileSystemRepository.dirIsExists(path)) {
|
||||||
return Result.error(new Error("createFolderUseCase create dir "));
|
return Result.error(new Error("createFolderUseCase create dir "));
|
||||||
}
|
}
|
||||||
await createDir(path);
|
await this.fileSystemRepository.createDir(path);
|
||||||
|
|
||||||
return Result.ok("ok");
|
return Result.ok("ok");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
import { IsMongoId, IsEnum } from "class-validator";
|
|
||||||
import { Schema, model } from "mongoose";
|
|
||||||
import { TriggerModel, triggerSchema } from "../triggers/trigger_model";
|
|
||||||
import { schemaProcess } from "../process/process_model";
|
|
||||||
import { StackGenerateType } from "../../core/models/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;
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
import { IsString, IsOptional, IsEnum, IsNumber, IsBoolean } from "class-validator";
|
|
||||||
import { Schema, model } from "mongoose";
|
|
||||||
import { IProcess, IssueType } from "../../core/models/process_model";
|
|
||||||
import { EXEC_TYPE } from "../../core/models/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;
|
|
||||||
}
|
|
|
@ -16,12 +16,10 @@ export class ProjectInstancePresentation extends CrudController<
|
||||||
});
|
});
|
||||||
super.post(new CreateNewProjectInstanceScenario().call);
|
super.post(new CreateNewProjectInstanceScenario().call);
|
||||||
|
|
||||||
super.subRoutes = [
|
this.subRoutes.push({
|
||||||
{
|
method: "POST",
|
||||||
method: "POST",
|
subUrl: "upload",
|
||||||
subUrl: "upload",
|
fn: new UploadCadFileToProjectScenario(),
|
||||||
fn: new UploadCadFileToProjectScenario(),
|
});
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
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[];
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import { CrudController } from "../../core/controllers/crud_controller";
|
import { CrudController } from "../../core/controllers/crud_controller";
|
||||||
import { TriggerDBModel } from "./models/trigger_database_model";
|
import { TriggerDBModel } from "./models/trigger_database_model";
|
||||||
import { TriggerModelValidationModel as TriggerValidationMode } from "./models/trigger_validation_model";
|
import { TriggerModelValidationModel } from "./models/trigger_validation_model";
|
||||||
|
|
||||||
export class TriggerPresentation extends CrudController<TriggerValidationMode, typeof TriggerDBModel> {
|
export class TriggerPresentation extends CrudController<TriggerModelValidationModel, typeof TriggerDBModel> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
url: "trigger",
|
url: "trigger",
|
||||||
validationModel: TriggerValidationMode,
|
validationModel: TriggerModelValidationModel,
|
||||||
databaseModel: TriggerDBModel,
|
databaseModel: TriggerDBModel,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"".isEmpty();
|
||||||
|
|
|
@ -3,19 +3,23 @@ import { StackService } from "../../src/core/services/stack_service";
|
||||||
import { delay } from "../../src/core/helpers/delay";
|
import { delay } from "../../src/core/helpers/delay";
|
||||||
import { assert, dirname__ } from "../test";
|
import { assert, dirname__ } from "../test";
|
||||||
import { mockSimplePipeline } from "../model/mock_pipelines";
|
import { mockSimplePipeline } from "../model/mock_pipelines";
|
||||||
import { readDirRecursive } from "../../src/core/repository/fs";
|
import { FileSystemRepository } from "../../src/core/repository/file_system_repository";
|
||||||
|
import { CreateFolderUseCase } from "../../src/core/usecases/crete_folder_usecase";
|
||||||
|
|
||||||
abstract class IStackServiceTest {
|
abstract class IStackServiceTest {
|
||||||
abstract test(): Promise<boolean>;
|
abstract test(): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
class SimpleTestStackServiceTest extends StackService implements IStackServiceTest {
|
class SimpleTestStackServiceTest extends StackService implements IStackServiceTest {
|
||||||
|
fileSystemRepository: FileSystemRepository;
|
||||||
constructor() {
|
constructor() {
|
||||||
super(mockSimplePipeline, dirname__ + "/context/");
|
super(mockSimplePipeline, dirname__ + "/context/");
|
||||||
|
this.fileSystemRepository = new FileSystemRepository();
|
||||||
}
|
}
|
||||||
async test(): Promise<boolean> {
|
async test(): Promise<boolean> {
|
||||||
await this.call();
|
await this.call();
|
||||||
const testResult = readDirRecursive(this.path).equals(["1.txt", "test.txt"], true);
|
console.log(this.path);
|
||||||
|
const testResult = this.fileSystemRepository.readDirRecursive(this.path).equals(["1.txt", "test.txt"], true);
|
||||||
await delay(100);
|
await delay(100);
|
||||||
rmSync(this.path + "example/", { recursive: true });
|
rmSync(this.path + "example/", { recursive: true });
|
||||||
return testResult;
|
return testResult;
|
||||||
|
@ -24,12 +28,15 @@ class SimpleTestStackServiceTest extends StackService implements IStackServiceTe
|
||||||
|
|
||||||
export class StackServiceTest {
|
export class StackServiceTest {
|
||||||
dirName: string;
|
dirName: string;
|
||||||
|
fileSystemRepository: FileSystemRepository;
|
||||||
constructor(dirName: string) {
|
constructor(dirName: string) {
|
||||||
this.dirName = dirName;
|
this.dirName = dirName;
|
||||||
|
this.fileSystemRepository = new FileSystemRepository();
|
||||||
}
|
}
|
||||||
public async test() {
|
public async test() {
|
||||||
const tests = [new SimpleTestStackServiceTest()];
|
const tests = [new SimpleTestStackServiceTest()];
|
||||||
|
await new CreateFolderUseCase().call(this.dirName + "/context/");
|
||||||
|
|
||||||
for await (const el of tests) {
|
for await (const el of tests) {
|
||||||
assert((await el.test()) === true, el.constructor.name);
|
assert((await el.test()) === true, el.constructor.name);
|
||||||
await delay(3000);
|
await delay(3000);
|
||||||
|
|
|
@ -37,24 +37,23 @@ const init = async () => {
|
||||||
|
|
||||||
const unitTest = async () => {
|
const unitTest = async () => {
|
||||||
await init();
|
await init();
|
||||||
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__).test();
|
||||||
await new TriggerServiceTest().test();
|
// await new TriggerServiceTest().test();
|
||||||
await new CreateDataBaseModelUseCaseTest().test();
|
// await new CreateDataBaseModelUseCaseTest().test();
|
||||||
await new CreateDataBaseModelUseCaseTest().test();
|
// await new CreateDataBaseModelUseCaseTest().test();
|
||||||
await new DeleteDataBaseModelUseCaseTest().test();
|
// await new DeleteDataBaseModelUseCaseTest().test();
|
||||||
await new ReadDataBaseModelUseCaseTest().test();
|
// await new ReadDataBaseModelUseCaseTest().test();
|
||||||
await new UpdateDataBaseModelUseCaseTest().test();
|
// await new UpdateDataBaseModelUseCaseTest().test();
|
||||||
// await new PipelineRealTimeServiceTest().test()
|
|
||||||
for await (const usecase of tests) {
|
// for await (const usecase of tests) {
|
||||||
testCore.assert(await new usecase().test(), usecase.name);
|
// testCore.assert(await new usecase().test(), usecase.name);
|
||||||
}
|
// }
|
||||||
};
|
};
|
||||||
const presentationCrudControllers = [new TriggerPresentation()];
|
const presentationCrudControllers = [new TriggerPresentation()];
|
||||||
const e2eTest = async () => {
|
const e2eTest = async () => {
|
||||||
const app = new App(httpRoutes, [], Environment.E2E_TEST);
|
const app = new App(httpRoutes, [], Environment.E2E_TEST);
|
||||||
app.listen();
|
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
app.on(async (e) => {
|
app.on(async (e) => {
|
||||||
if (e === ServerStatus.finished) {
|
if (e === ServerStatus.finished) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue