Compare commits
136 commits
Author | SHA1 | Date | |
---|---|---|---|
4ceae093f3 | |||
f0e09812ee | |||
ccc1e2da4b | |||
c85784f3dc | |||
![]() |
7d3b8ff0cb | ||
![]() |
d7e8c825cb | ||
![]() |
40eebf9dd8 | ||
![]() |
564866393f | ||
![]() |
2afed3a4f0 | ||
470a7ef43e | |||
7c01c61194 | |||
![]() |
3044540814 | ||
![]() |
dfe7b20f8d | ||
![]() |
c2b91ee4d7 | ||
![]() |
c2da1d8f4c | ||
![]() |
d7ea79935e | ||
![]() |
a94d84ba69 | ||
![]() |
d3a07a5c11 | ||
![]() |
12c09c4461 | ||
![]() |
8696d99194 | ||
bad5c4d8a0 | |||
![]() |
88e40f7bdb | ||
![]() |
58b22d294d | ||
![]() |
f39f69a440 | ||
![]() |
ea1ebe0e95 | ||
![]() |
2024834d06 | ||
![]() |
300a5005ba | ||
![]() |
e163f0698b | ||
cad230eee9 | |||
![]() |
aaa4257920 | ||
![]() |
3accb5af61 | ||
![]() |
6190869d8d | ||
![]() |
28c36ae710 | ||
![]() |
3f951d1c09 | ||
![]() |
29dcfb6ac1 | ||
![]() |
00c553ecd7 | ||
![]() |
3f88ceebe4 | ||
![]() |
2d59388494 | ||
![]() |
23c39cbae2 | ||
![]() |
059b2e3e64 | ||
![]() |
f019c3a1c4 | ||
![]() |
2f15b86a42 | ||
![]() |
15cb712c3d | ||
![]() |
1ec2a3ff7a | ||
![]() |
7693377ad1 | ||
![]() |
1cc489fc72 | ||
![]() |
139f012803 | ||
![]() |
0dbc04f09b | ||
![]() |
c19e4c684e | ||
![]() |
2b4795dfc2 | ||
![]() |
04b1c2bfc7 | ||
![]() |
3369306451 | ||
![]() |
15930c5f85 | ||
![]() |
da883edb64 | ||
![]() |
c135bca77a | ||
![]() |
4657652dd0 | ||
![]() |
314e070bee | ||
![]() |
d47d555061 | ||
![]() |
50d239a4eb | ||
![]() |
5eb588a709 | ||
![]() |
ba5394107a | ||
![]() |
fb4fa52c14 | ||
![]() |
4e6132a872 | ||
![]() |
d804aa2edf | ||
![]() |
e2cd7af032 | ||
![]() |
c0a23c31f7 | ||
![]() |
193e884e40 | ||
![]() |
401080d78e | ||
![]() |
3b8d9e4298 | ||
![]() |
25e57c1a56 | ||
![]() |
a920f5fb45 | ||
![]() |
cac5fad8ce | ||
![]() |
d6702185f0 | ||
![]() |
1287625107 | ||
![]() |
e748debd2f | ||
![]() |
7063e93c75 | ||
![]() |
cf75b4220a | ||
![]() |
ca3a1cfed9 | ||
![]() |
48be3e6d33 | ||
![]() |
d41310196f | ||
![]() |
0b3eefec2d | ||
![]() |
17ed2905c2 | ||
![]() |
6e6a1c0c1d | ||
![]() |
6003cfde04 | ||
![]() |
9120729d41 | ||
![]() |
318d0a7893 | ||
![]() |
d8b5018cb2 | ||
![]() |
50822a031d | ||
![]() |
559262db34 | ||
![]() |
b5750b12ef | ||
![]() |
50d0c4c12b | ||
![]() |
0a4eea19c5 | ||
![]() |
81238c5182 | ||
![]() |
53fe9bf51a | ||
![]() |
4e726be376 | ||
![]() |
814eb485eb | ||
![]() |
8f8fc3107d | ||
![]() |
61118a7423 | ||
![]() |
c5ae89d18a | ||
![]() |
5162612a77 | ||
![]() |
4585d079f6 | ||
![]() |
89d4226ea6 | ||
![]() |
a0cee0b394 | ||
![]() |
e0a6cd0af1 | ||
![]() |
c49beb8218 | ||
![]() |
8bc943de2c | ||
![]() |
f0ed478b36 | ||
![]() |
c4ddb3dc8c | ||
![]() |
e155b4a2a1 | ||
![]() |
e005a42254 | ||
![]() |
c628cdb9af | ||
![]() |
7e25cc216a | ||
![]() |
810eb5926e | ||
![]() |
94b40bf24c | ||
![]() |
38ffde1d77 | ||
![]() |
e85dc14fc8 | ||
![]() |
f11dfa7e57 | ||
![]() |
2b8d0fa88b | ||
![]() |
a2066ce5cd | ||
![]() |
776b6e540e | ||
![]() |
78ebb748ea | ||
![]() |
c10cdb8158 | ||
![]() |
27763fc8d2 | ||
![]() |
0c03906518 | ||
![]() |
c17515d571 | ||
![]() |
6840402b1f | ||
![]() |
dffc73c30f | ||
![]() |
c43c192a3e | ||
![]() |
0d825f7f63 | ||
![]() |
de5b493c77 | ||
![]() |
acc79df97d | ||
![]() |
5dec799002 | ||
![]() |
9028186a74 | ||
![]() |
2adb939f37 | ||
![]() |
ae9842d5e1 | ||
![]() |
7ff6165882 |
541 changed files with 42237 additions and 31591 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
p.py
|
p.py
|
||||||
|
__pycache__
|
1205
.vscode/PythonImportHelper-v2-Completion.json
vendored
Normal file
1205
.vscode/PythonImportHelper-v2-Completion.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
72
.vscode/launch.json
vendored
72
.vscode/launch.json
vendored
|
@ -1,40 +1,36 @@
|
||||||
{
|
{
|
||||||
// Use IntelliSense to learn about possible attributes.
|
"version": "0.2.0",
|
||||||
// Hover to view descriptions of existing attributes.
|
"configurations": [
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
{
|
||||||
"version": "0.2.0",
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
"configurations": [
|
"name": "server-dev",
|
||||||
|
"runtimeExecutable": "npm",
|
||||||
{
|
"runtimeArgs": ["run-script", "dev"],
|
||||||
"type": "node",
|
"cwd": "${workspaceRoot}/server/"
|
||||||
"request": "launch",
|
},
|
||||||
"name": "server-dev",
|
{
|
||||||
"runtimeExecutable": "npm",
|
"type": "node",
|
||||||
"runtimeArgs": [
|
"request": "launch",
|
||||||
"run-script", "dev"
|
"name": "server-test-watch",
|
||||||
],
|
"runtimeExecutable": "npm",
|
||||||
"cwd": "${workspaceRoot}/server/",
|
"runtimeArgs": ["run-script", "test:watch"],
|
||||||
},
|
"cwd": "${workspaceRoot}/server/"
|
||||||
{
|
},
|
||||||
"type": "node",
|
{
|
||||||
"request": "launch",
|
"type": "node",
|
||||||
"name": "server-test-watch",
|
"request": "launch",
|
||||||
"runtimeExecutable": "npm",
|
"name": "ui-dev",
|
||||||
"runtimeArgs": [
|
"runtimeExecutable": "npm",
|
||||||
"run-script", "test:watch"
|
"runtimeArgs": ["run-script", "dev"],
|
||||||
],
|
"cwd": "${workspaceRoot}/ui/"
|
||||||
"cwd": "${workspaceRoot}/server/",
|
},
|
||||||
},
|
{
|
||||||
{
|
"type": "chrome",
|
||||||
"type": "node",
|
"request": "launch",
|
||||||
"request": "launch",
|
"name": "Launch debug chrome",
|
||||||
"name": "ui-dev",
|
"url": "http://localhost:3000",
|
||||||
"runtimeExecutable": "npm",
|
"webRoot": "${workspaceFolder}"
|
||||||
"runtimeArgs": [
|
}
|
||||||
"run-script", "dev"
|
]
|
||||||
],
|
|
||||||
"cwd": "${workspaceRoot}/ui/",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
34
.vscode/settings.json
vendored
34
.vscode/settings.json
vendored
|
@ -1,6 +1,36 @@
|
||||||
{
|
{
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
|
"введите",
|
||||||
"Ведите",
|
"Ведите",
|
||||||
"typedataset"
|
"дерево",
|
||||||
]
|
"Количество",
|
||||||
|
"модели",
|
||||||
|
"может",
|
||||||
|
"навык",
|
||||||
|
"Новое",
|
||||||
|
"отрицательное",
|
||||||
|
"принимать",
|
||||||
|
"скила",
|
||||||
|
"создано",
|
||||||
|
"число",
|
||||||
|
"эпох",
|
||||||
|
"эпоха",
|
||||||
|
"Collada",
|
||||||
|
"Contolls",
|
||||||
|
"GLTF",
|
||||||
|
"grau",
|
||||||
|
"idontsudo",
|
||||||
|
"Pids",
|
||||||
|
"raycaster",
|
||||||
|
"skils",
|
||||||
|
"typedataset",
|
||||||
|
"URDF",
|
||||||
|
"usecases"
|
||||||
|
],
|
||||||
|
"files.exclude": {
|
||||||
|
"**/.git": false,
|
||||||
|
"**/.svn": false,
|
||||||
|
"**/.hg": false,
|
||||||
|
"**/CVS": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
81
README.md
81
README.md
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
Каждая фаза жизненного цикла имеет своё представление в виде страницы в веб-сервисе:
|
Каждая фаза жизненного цикла имеет своё представление в виде страницы в веб-сервисе:
|
||||||
|
|
||||||
1. Создание проекта сборки, загрузка CAD-проекта изделия - "Проекты", вкладки "Детали", "Сборки"
|
1. Создание проекта сборки, загрузка CAD-проекта изделия - "Проекты"
|
||||||
2. Подготовка и генерация датасета для навыков машинного зрения - Вкладка "Датасеты"
|
2. Подготовка и генерация датасета для навыков машинного зрения - Вкладка "Датасеты"
|
||||||
3. Конфигурация сцены - Scene Builder - Вкладка "Сцена"
|
3. Конфигурация сцены - Scene Builder - Вкладка "Сцена"
|
||||||
4. Создание дерева поведения из навыков - Вкладка "Поведение"
|
4. Создание дерева поведения из навыков - Вкладка "Поведение"
|
||||||
|
@ -23,37 +23,74 @@
|
||||||
|
|
||||||
## Требования
|
## Требования
|
||||||
|
|
||||||
- Node.js
|
- Node.js (версия >= 20.11.1)
|
||||||
- MongoDB
|
- MongoDB (версия >= 7.0.15)
|
||||||
- BlenderProc (для генерации датасетов)
|
- BlenderProc (для генерации датасетов)
|
||||||
|
|
||||||
## Клонирование проекта
|
## Последовательность команд для установки зависимостей
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# установка nvm
|
||||||
|
curl --silent -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.2/install.sh | bash
|
||||||
|
source ~/.bashrc
|
||||||
|
# установка Node.js
|
||||||
|
nvm install 20.11.1
|
||||||
|
nvm alias default 20.11.1
|
||||||
|
nvm use default
|
||||||
|
|
||||||
|
# MongoDB
|
||||||
|
# импортировать открытый ключ для MongoDB
|
||||||
|
curl -fsSL https://pgp.mongodb.com/server-7.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor
|
||||||
|
# добавить репозиторий MongoDB 7.0 в директорию /etc/apt/sources.list.d
|
||||||
|
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
|
||||||
|
# установка MongoDB
|
||||||
|
apt-get update && apt-get install -y mongodb-org
|
||||||
|
# запуск
|
||||||
|
sudo systemctl start mongod
|
||||||
|
```
|
||||||
|
Убедиться в том, что сервер MongoDB работает, можно посмотрев его состояние:
|
||||||
|
```bash
|
||||||
|
sudo systemctl status mongod
|
||||||
|
```
|
||||||
|
Статус должен быть 'active'
|
||||||
|
```
|
||||||
|
● mongod.service - MongoDB Database Server
|
||||||
|
Loaded: loaded (/lib/systemd/system/mongod.service; enabled; vendor preset: enabled)
|
||||||
|
Active: active (running) since Wed 2024-12-11 10:34:58 MSK; 1h 24min ago
|
||||||
|
Docs: https://docs.mongodb.org/manual
|
||||||
|
Main PID: 2439 (mongod)
|
||||||
|
Memory: 256.7M
|
||||||
|
CPU: 24.168s
|
||||||
|
CGroup: /system.slice/mongod.service
|
||||||
|
└─2439 /usr/bin/mongod --config /etc/mongod.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
## Установка веб-сервиса
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# клонирование исходников
|
||||||
|
cd ~/
|
||||||
git clone https://gitlab.com/robossembler/webservice
|
git clone https://gitlab.com/robossembler/webservice
|
||||||
|
# сборка сервера
|
||||||
|
cd webservice/server
|
||||||
|
npm i tsc-watch -g
|
||||||
|
npm i
|
||||||
|
# сборка фронтэнда
|
||||||
|
cd ..
|
||||||
|
cd ui
|
||||||
|
npm i
|
||||||
```
|
```
|
||||||
|
|
||||||
## Настройка переменных окружения
|
## Запуск веб-сервиса
|
||||||
|
|
||||||
Для работы Генератора Датасетов нужно задать следующие переменные в окружении `bash`
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export PYTHON_BLENDER="путь_к_директории_с_файлами_из_rcg_pipeline"
|
|
||||||
export PYTHON_BLENDER_PROC="путь_к_генератору_датасетов_renderBOPdataset.py"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Запуск сервера
|
|
||||||
|
|
||||||
Из директории `server` в корне репозитория
|
|
||||||
|
|
||||||
|
Необходимо открыть два терминала. В первом нужно запустить сервер:
|
||||||
```bash
|
```bash
|
||||||
|
cd ~/webservice/server
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
Во втором запустить UI:
|
||||||
## Сборка и запуск UI
|
|
||||||
|
|
||||||
Из директории `ui` в корне репозитория
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm i && npm run build && npm run deploy
|
cd ~/webservice/ui
|
||||||
|
npm run dev
|
||||||
```
|
```
|
||||||
|
Если установка была успешной, откроется браузер, на странице http://localhost:3000/ "Проекты".
|
||||||
|
|
82
p.json
Normal file
82
p.json
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
{
|
||||||
|
"process": {
|
||||||
|
"type": "OBJECT_DETECTION",
|
||||||
|
"selectProcess": {
|
||||||
|
"value": {
|
||||||
|
"_id": "675db885429ef25f8d2efaa2",
|
||||||
|
"script": "ls -l -a",
|
||||||
|
"formBuilder": {
|
||||||
|
"result": "",
|
||||||
|
"context": "",
|
||||||
|
"form": [],
|
||||||
|
"output": "",
|
||||||
|
"type": "formBuilder"
|
||||||
|
},
|
||||||
|
"type": "OBJECT_DETECTION",
|
||||||
|
"instanceName": "ls -l -a",
|
||||||
|
"name": "ls",
|
||||||
|
"isEnd": true,
|
||||||
|
"createDate": "1734195300981",
|
||||||
|
"card": "pose_estimate",
|
||||||
|
"path": "/Users/idontsudo/webservice/server/build/public//process/ls",
|
||||||
|
"instancePath": "/Users/idontsudo/webservice/server/build/public//process/ls/ls -l -a",
|
||||||
|
"project": {
|
||||||
|
"_id": "675eb125281cf9253681efa3",
|
||||||
|
"description": "e1wq",
|
||||||
|
"rootDir": "/Users/idontsudo/webservice/server/build/public/f49f8f47-5427-48aa-8aff-c5e7ae4e6efe",
|
||||||
|
"isActive": true,
|
||||||
|
"__v": 0
|
||||||
|
},
|
||||||
|
"__v": 0,
|
||||||
|
"lastProcessExecCommand": "ls -l -a --path /Users/idontsudo/webservice/server/build/public/process/ls/ls -l -a --form /Users/idontsudo/webservice/server/build/public/process/ls/ls -l -a/form.json",
|
||||||
|
"processStatus": "endError",
|
||||||
|
"lastProcessLogs": "ls: unrecognized option `--path'nnusage: ls [-@ABCFGHILOPRSTUWabcdefghiklmnopqrstuvwxy1%,] [--color=when] [-D format] [file ...]n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"datasetObjects": {
|
||||||
|
"details": []
|
||||||
|
},
|
||||||
|
"typedataset": "ObjectDetection",
|
||||||
|
"models_randomization": {
|
||||||
|
"loc_range_low": [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"loc_range_high": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scene": {
|
||||||
|
"objects": [],
|
||||||
|
"lights": []
|
||||||
|
},
|
||||||
|
"camera_position": {
|
||||||
|
"center_shell": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"radius_range": [
|
||||||
|
1,
|
||||||
|
1.4
|
||||||
|
],
|
||||||
|
"elevation_range": [
|
||||||
|
10,
|
||||||
|
90
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"generation": {
|
||||||
|
"n_cam_pose": 5,
|
||||||
|
"n_sample_on_pose": 3,
|
||||||
|
"n_series": 100,
|
||||||
|
"image_format": "JPEG",
|
||||||
|
"image_size_wh": [
|
||||||
|
640,
|
||||||
|
480
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ module.exports = {
|
||||||
"@typescript-eslint/no-var-requires": "off",
|
"@typescript-eslint/no-var-requires": "off",
|
||||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||||
"@typescript-eslint/no-unused-vars": [
|
"@typescript-eslint/no-unused-vars": [
|
||||||
"warn", // or "error"
|
"warn",
|
||||||
{
|
{
|
||||||
"argsIgnorePattern": "^_",
|
"argsIgnorePattern": "^_",
|
||||||
"varsIgnorePattern": "^_",
|
"varsIgnorePattern": "^_",
|
||||||
|
|
1
server/.gitignore
vendored
1
server/.gitignore
vendored
|
@ -9,3 +9,4 @@ build/
|
||||||
model_create.ts
|
model_create.ts
|
||||||
public
|
public
|
||||||
p.ts
|
p.ts
|
||||||
|
package-lock.json
|
|
@ -1 +1,14 @@
|
||||||
Веб-сервис для отладки Robossembler Framework
|
Веб-сервис для отладки Robossembler Framework
|
||||||
|
|
||||||
|
### Миграция данных веб-сервиса
|
||||||
|
|
||||||
|
Имеется ввиду перенос данных, хранящихся в БД MongoDB.
|
||||||
|
|
||||||
|
Для этого вначале создаётся копия БД с именем `dev` в папке `my_copy`:
|
||||||
|
```sh
|
||||||
|
mongodump --host localhost --port 27017 --db dev --out my_copy
|
||||||
|
```
|
||||||
|
Затем папка `my_copy` переносится в нужное место (например, на другой сервер). И запускается её восстановление в новом месте (копия БД с именем `dev`):
|
||||||
|
```sh
|
||||||
|
mongorestore --host localhost --port 27017 --db dev my_copy/dev
|
||||||
|
```
|
||||||
|
|
26
server/command.json
Normal file
26
server/command.json
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"tensorBoard": {
|
||||||
|
"execCommand": "nix run github:nixos/nixpkgs#python312Packages.tensorboard -- --logdir ${dir_path}",
|
||||||
|
"date": null,
|
||||||
|
"status": "Fail,Ok",
|
||||||
|
"delay": 200,
|
||||||
|
"checkCommand": null,
|
||||||
|
"filter": null
|
||||||
|
},
|
||||||
|
"simulationProcess": {
|
||||||
|
"execCommand": "nix run github:nixos/nixpkgs#python312Packages.tensorboard -- --logdir ${dir_path}",
|
||||||
|
"date": null,
|
||||||
|
"status": null,
|
||||||
|
"delay": 0,
|
||||||
|
"checkCommand": null,
|
||||||
|
"filter": null
|
||||||
|
},
|
||||||
|
"btRuntimeProcess": {
|
||||||
|
"execCommand": "cd ~/robossembler-ws && source ./install/local_setup.bash; ros2 launch rbs_bt_executor rbs_bt_web.launch.py bt_path:=${bt_path}",
|
||||||
|
"date": null,
|
||||||
|
"status": null,
|
||||||
|
"delay": 0,
|
||||||
|
"checkCommand": null,
|
||||||
|
"filter": null
|
||||||
|
}
|
||||||
|
}
|
8576
server/package-lock.json
generated
8576
server/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -7,8 +7,7 @@
|
||||||
"test:dev": "NODE_ENV=test_dev tsc-watch --onSuccess 'ts-node ./build/test/test.js'",
|
"test:dev": "NODE_ENV=test_dev tsc-watch --onSuccess 'ts-node ./build/test/test.js'",
|
||||||
"test:unit": "NODE_ENV=unit tsc-watch --onSuccess 'ts-node ./build/test/test.js'",
|
"test:unit": "NODE_ENV=unit tsc-watch --onSuccess 'ts-node ./build/test/test.js'",
|
||||||
"test:e2e": "NODE_ENV=e2e tsc-watch --onSuccess 'ts-node ./build/test/test.js'",
|
"test:e2e": "NODE_ENV=e2e tsc-watch --onSuccess 'ts-node ./build/test/test.js'",
|
||||||
"dev": "NODE_ENV=dev tsc-watch --onSuccess 'ts-node ./build/src/main.js'",
|
"dev": "NODE_ENV=dev tsc-watch --onSuccess 'ts-node ./build/src/main.js'"
|
||||||
"build:stand": " "
|
|
||||||
},
|
},
|
||||||
"author": "IDONTSUDO",
|
"author": "IDONTSUDO",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -24,34 +23,28 @@
|
||||||
"chai": "latest",
|
"chai": "latest",
|
||||||
"eslint": "^8.47.0",
|
"eslint": "^8.47.0",
|
||||||
"mocha": "latest",
|
"mocha": "latest",
|
||||||
"nyc": "latest",
|
"node-watch": "^0.7.4",
|
||||||
"source-map-support": "latest",
|
"source-map-support": "latest",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"tslint": "latest",
|
"tslint": "latest",
|
||||||
"typescript": "^5.1.6",
|
"typescript": "^5.1.6"
|
||||||
"node-watch": "^0.7.4",
|
|
||||||
"nodemon": "^3.0.1"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@grpc/grpc-js": "^1.9.0",
|
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
"babel-register": "^6.26.0",
|
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.0",
|
"class-validator": "^0.14.0",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"express-fileupload": "^1.4.2",
|
"express-fileupload": "^1.4.2",
|
||||||
"first-di": "^1.0.11",
|
|
||||||
"md5": "^2.3.0",
|
|
||||||
"mongoose": "^7.6.2",
|
"mongoose": "^7.6.2",
|
||||||
"mongoose-autopopulate": "^1.1.0",
|
"mongoose-autopopulate": "^1.1.0",
|
||||||
|
"pattern-matching-ts": "^2.0.0",
|
||||||
"pm2": "^5.3.1",
|
"pm2": "^5.3.1",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"socket.io": "^4.7.2",
|
"socket.io": "^4.7.2",
|
||||||
"socket.io-client": "^4.7.2",
|
"socket.io-client": "^4.7.2",
|
||||||
"spark-md5": "^3.0.2",
|
"ts-pattern": "^5.1.1",
|
||||||
"ts-md5": "^1.3.1",
|
|
||||||
"tsc-watch": "^6.0.4",
|
"tsc-watch": "^6.0.4",
|
||||||
"uuid": "^9.0.1"
|
"uuid": "^9.0.1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,12 @@ 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 { 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";
|
||||||
import { TypedEvent } from "../helpers/typed_event";
|
import { TypedEvent } from "../helpers/typed_event";
|
||||||
|
import { CalculationInstanceDBModel } from "../../features/calculations_instance/models/calculations_instance_database_model";
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { WriteFileSystemFileUseCase } from "../usecases/write_file_system_file_usecase";
|
||||||
|
|
||||||
export enum ServerStatus {
|
export enum ServerStatus {
|
||||||
init = "init",
|
init = "init",
|
||||||
|
@ -58,8 +60,6 @@ export class App extends TypedEvent<ServerStatus> {
|
||||||
io.on("connection", (socket) => {
|
io.on("connection", (socket) => {
|
||||||
this.socketSubscribers.map((el) => {
|
this.socketSubscribers.map((el) => {
|
||||||
el.emitter.on((e) => {
|
el.emitter.on((e) => {
|
||||||
console.log(el.event)
|
|
||||||
console.log(e)
|
|
||||||
socket.emit(el.event, e);
|
socket.emit(el.event, e);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -88,7 +88,25 @@ export class App extends TypedEvent<ServerStatus> {
|
||||||
this.app.use(express.json());
|
this.app.use(express.json());
|
||||||
this.app.use(express.urlencoded({ extended: true }));
|
this.app.use(express.urlencoded({ extended: true }));
|
||||||
this.app.use(express.static(App.staticFilesStoreDir()));
|
this.app.use(express.static(App.staticFilesStoreDir()));
|
||||||
|
this.app.get('/logs', async (req, res) => {
|
||||||
|
const id = req.query.id;
|
||||||
|
|
||||||
|
if (id === undefined) {
|
||||||
|
return res.status(400).json('need req query id?=')
|
||||||
|
}
|
||||||
|
|
||||||
|
const calculationInstanceDBModel = await CalculationInstanceDBModel.findById(id)
|
||||||
|
if (calculationInstanceDBModel === null) {
|
||||||
|
return res.status(400).json("calcultaion db model is null");
|
||||||
|
}
|
||||||
|
const p = App.staticFilesStoreDir() + '/log.txt';
|
||||||
|
|
||||||
|
(await new WriteFileSystemFileUseCase().call(p, calculationInstanceDBModel.lastProcessLogs)).map(() => {
|
||||||
|
return res.sendFile(p);
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
this.app.use(
|
this.app.use(
|
||||||
fileUpload({
|
fileUpload({
|
||||||
createParentPath: true,
|
createParentPath: true,
|
||||||
|
@ -109,6 +127,7 @@ export class App extends TypedEvent<ServerStatus> {
|
||||||
await result.fold(
|
await result.fold(
|
||||||
async (_s) => {
|
async (_s) => {
|
||||||
await new CheckAndCreateStaticFilesFolderUseCase().call();
|
await new CheckAndCreateStaticFilesFolderUseCase().call();
|
||||||
|
|
||||||
// await new SetLastActivePipelineToRealTimeServiceScenario().call();
|
// await new SetLastActivePipelineToRealTimeServiceScenario().call();
|
||||||
},
|
},
|
||||||
async (_e) => {
|
async (_e) => {
|
||||||
|
@ -124,3 +143,5 @@ export class App extends TypedEvent<ServerStatus> {
|
||||||
return rootDir + "public/";
|
return rootDir + "public/";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { Result } from "../helpers/result";
|
||||||
import { Router, Request, Response } from "express";
|
import { Router, Request, Response } from "express";
|
||||||
import { IRouteModel, Routes } from "../interfaces/router";
|
import { IRouteModel, Routes } from "../interfaces/router";
|
||||||
import { CoreValidation } from "../validations/core_validation";
|
import { CoreValidation } from "../validations/core_validation";
|
||||||
|
import { plainToInstance } from "class-transformer";
|
||||||
|
|
||||||
export type HttpMethodType = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "PATCH" | "HEAD";
|
export type HttpMethodType = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "PATCH" | "HEAD";
|
||||||
|
|
||||||
|
@ -28,16 +29,48 @@ export abstract class CallbackStrategyWithFileUpload {
|
||||||
abstract idValidationExpression: CoreValidation;
|
abstract idValidationExpression: CoreValidation;
|
||||||
abstract call(file: File, id: string): ResponseBase;
|
abstract call(file: File, id: string): ResponseBase;
|
||||||
}
|
}
|
||||||
|
export abstract class CallbackStrategyWithFilesUploads {
|
||||||
|
abstract chuckingFileExpressions: RegExp[];
|
||||||
|
abstract call(files: File[]): ResponseBase;
|
||||||
|
}
|
||||||
|
|
||||||
interface ISubSetFeatureRouter<T> {
|
export class SubRouter<A> implements ISubSetFeatureRouter<A> {
|
||||||
method: HttpMethodType;
|
method: HttpMethodType;
|
||||||
subUrl: string;
|
subUrl: string;
|
||||||
fn:
|
fn:
|
||||||
| CallbackStrategyWithValidationModel<T>
|
| CallbackStrategyWithValidationModel<A>
|
||||||
| CallbackStrategyWithEmpty
|
| CallbackStrategyWithEmpty
|
||||||
| CallbackStrategyWithIdQuery
|
| CallbackStrategyWithIdQuery
|
||||||
| CallBackStrategyWithQueryPage
|
| CallBackStrategyWithQueryPage
|
||||||
| CallbackStrategyWithFileUpload;
|
| CallbackStrategyWithFileUpload
|
||||||
|
| CallbackStrategyWithFilesUploads;
|
||||||
|
constructor(
|
||||||
|
method: HttpMethodType,
|
||||||
|
subUrl: string,
|
||||||
|
fn:
|
||||||
|
| CallbackStrategyWithValidationModel<A>
|
||||||
|
| CallbackStrategyWithEmpty
|
||||||
|
| CallbackStrategyWithIdQuery
|
||||||
|
| CallBackStrategyWithQueryPage
|
||||||
|
| CallbackStrategyWithFileUpload
|
||||||
|
| CallbackStrategyWithFilesUploads
|
||||||
|
) {
|
||||||
|
this.fn = fn;
|
||||||
|
this.subUrl = subUrl;
|
||||||
|
this.method = method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISubSetFeatureRouter<A> {
|
||||||
|
method: HttpMethodType;
|
||||||
|
subUrl: string;
|
||||||
|
fn:
|
||||||
|
| CallbackStrategyWithValidationModel<A>
|
||||||
|
| CallbackStrategyWithEmpty
|
||||||
|
| CallbackStrategyWithIdQuery
|
||||||
|
| CallBackStrategyWithQueryPage
|
||||||
|
| CallbackStrategyWithFileUpload
|
||||||
|
| CallbackStrategyWithFilesUploads;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class ICoreHttpController {
|
abstract class ICoreHttpController {
|
||||||
|
@ -78,11 +111,11 @@ export class CoreHttpController<V> implements ICoreHttpController {
|
||||||
}
|
}
|
||||||
call(): Routes {
|
call(): Routes {
|
||||||
if (this.subRoutes.isNotEmpty()) {
|
if (this.subRoutes.isNotEmpty()) {
|
||||||
this.subRoutes.map((el) => {
|
this.subRoutes.map(async (el) => {
|
||||||
this.router[el.method.toLowerCase()](this.mainURL + "/" + el.subUrl, async (req, res) => {
|
this.router[el.method.toLowerCase()](this.mainURL + "/" + el.subUrl, async (req, res) => {
|
||||||
if (el.fn instanceof CallbackStrategyWithValidationModel) {
|
if (el.fn instanceof CallbackStrategyWithValidationModel) {
|
||||||
// TODO(IDONTSUDO):
|
this.responseHelper(res, el.fn.call(req.body));
|
||||||
throw Error("needs to be implimed");
|
return;
|
||||||
}
|
}
|
||||||
if (el.fn instanceof CallbackStrategyWithIdQuery) {
|
if (el.fn instanceof CallbackStrategyWithIdQuery) {
|
||||||
if (req.query.id === undefined) {
|
if (req.query.id === undefined) {
|
||||||
|
@ -104,6 +137,7 @@ export class CoreHttpController<V> implements ICoreHttpController {
|
||||||
await this.responseHelper(res, el.fn.call(req["files"]["file"]));
|
await this.responseHelper(res, el.fn.call(req["files"]["file"]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.fn instanceof CallBackStrategyWithQueryPage) {
|
if (el.fn instanceof CallBackStrategyWithQueryPage) {
|
||||||
throw Error("needs to be implimed");
|
throw Error("needs to be implimed");
|
||||||
}
|
}
|
||||||
|
@ -142,6 +176,7 @@ export class CoreHttpController<V> implements ICoreHttpController {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.responseHelper(res, el.fn.call(req["files"]["file"], req.query.id));
|
await this.responseHelper(res, el.fn.call(req["files"]["file"], req.query.id));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -171,10 +206,10 @@ export class CoreHttpController<V> implements ICoreHttpController {
|
||||||
router: this.router,
|
router: this.router,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public put(usecase: CallbackStrategyWithValidationModel<V>) {
|
public put(usecase: any) {
|
||||||
this.routes["PUT"] = usecase;
|
this.routes["PUT"] = usecase;
|
||||||
}
|
}
|
||||||
public delete(usecase: CallbackStrategyWithValidationModel<V>) {
|
public delete(usecase: any) {
|
||||||
this.routes["DELETE"] = usecase;
|
this.routes["DELETE"] = usecase;
|
||||||
}
|
}
|
||||||
public async requestResponseController<T>(
|
public async requestResponseController<T>(
|
||||||
|
@ -191,7 +226,6 @@ export class CoreHttpController<V> implements ICoreHttpController {
|
||||||
if (req.query.page !== undefined) {
|
if (req.query.page !== undefined) {
|
||||||
payload = String(req.query.page);
|
payload = String(req.query.page);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.query.id !== undefined) {
|
if (req.query.id !== undefined) {
|
||||||
payload = String(req.query.id);
|
payload = String(req.query.id);
|
||||||
}
|
}
|
||||||
|
@ -200,6 +234,7 @@ export class CoreHttpController<V> implements ICoreHttpController {
|
||||||
return res.json(ok);
|
return res.json(ok);
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
|
|
||||||
return res.status(400).json({ error: String(err) });
|
return res.status(400).json({ error: String(err) });
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,9 +1,29 @@
|
||||||
|
import { BehaviorTreesPresentation } from "../../features/behavior_trees/behavior_trees_presentation";
|
||||||
import { DatasetsPresentation } from "../../features/datasets/datasets_presentation";
|
import { DatasetsPresentation } from "../../features/datasets/datasets_presentation";
|
||||||
|
import { CalculationsTemplatePresentation } from "../../features/calculations_templates/calculations_template_presentation";
|
||||||
import { ProjectsPresentation } from "../../features/projects/projects_presentation";
|
import { ProjectsPresentation } from "../../features/projects/projects_presentation";
|
||||||
// import { ProjectsPresentation } from "../../features/_projects/projects_presentation";
|
|
||||||
import { extensions } from "../extensions/extensions";
|
import { extensions } from "../extensions/extensions";
|
||||||
import { Routes } from "../interfaces/router";
|
import { Routes } from "../interfaces/router";
|
||||||
|
import { ScenesPresentation } from "../../features/scenes/scenes_presentation";
|
||||||
|
import { CalculationsInstancesPresentation } from "../../features/calculations_instance/calculations_instance_presentation";
|
||||||
|
import { DigitalTwinsInstancePresentation } from "../../features/digital_twins_instance/digital_twins_instance_presentation";
|
||||||
|
import { DigitalTwinsTemplatePresentation } from "../../features/digital_twins_template/digital_twins_template_presentation";
|
||||||
|
import { TopicsPresentation } from "../../features/topics/topics_presentation";
|
||||||
|
import { SkillsPresentation } from "../../features/skills/skill_presentation";
|
||||||
|
import { RunTimePresentation } from "../../features/runtime/runtime_presentation";
|
||||||
|
|
||||||
extensions();
|
extensions();
|
||||||
|
|
||||||
export const httpRoutes: Routes[] = [new ProjectsPresentation(), new DatasetsPresentation()].map((el) => el.call());
|
export const httpRoutes: Routes[] = [
|
||||||
|
new ProjectsPresentation(),
|
||||||
|
new DatasetsPresentation(),
|
||||||
|
new ScenesPresentation(),
|
||||||
|
new BehaviorTreesPresentation(),
|
||||||
|
new CalculationsTemplatePresentation(),
|
||||||
|
new CalculationsInstancesPresentation(),
|
||||||
|
new DigitalTwinsTemplatePresentation(),
|
||||||
|
new DigitalTwinsInstancePresentation(),
|
||||||
|
new TopicsPresentation(),
|
||||||
|
new SkillsPresentation(),
|
||||||
|
new RunTimePresentation(),
|
||||||
|
].map((el) => el.call());
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
// import { Service } from "typedi";
|
|
||||||
|
|
||||||
// @Service()
|
|
||||||
// export class IEnv{
|
|
||||||
// rootFolder!: string;
|
|
||||||
// constructor(){
|
|
||||||
|
|
||||||
// }
|
|
||||||
// toStringEnv(){
|
|
||||||
// return ''
|
|
||||||
// }
|
|
||||||
// static env(){
|
|
||||||
// return ''
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @Service()
|
|
||||||
// export class DevEnv implements IEnv {
|
|
||||||
// rootFolder:string;
|
|
||||||
// constructor(rootFolder:string){
|
|
||||||
// this.rootFolder = rootFolder
|
|
||||||
// }
|
|
||||||
// toStringEnv(): string {
|
|
||||||
// return DevEnv.env()
|
|
||||||
// }
|
|
||||||
// static env(){
|
|
||||||
// return 'DevEnv'
|
|
||||||
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// @Service()
|
|
||||||
// export class UnitTestEnv implements IEnv{
|
|
||||||
// rootFolder:string;
|
|
||||||
// constructor(rootFolder:string){
|
|
||||||
// this.rootFolder = rootFolder
|
|
||||||
// }
|
|
||||||
// toStringEnv(): string {
|
|
||||||
// return UnitTestEnv.env()
|
|
||||||
// }
|
|
||||||
// static env(){
|
|
||||||
// return 'UnitTestEnv'
|
|
||||||
|
|
||||||
// }
|
|
||||||
// }
|
|
|
@ -1,53 +0,0 @@
|
||||||
// import { DevEnv, IEnv, UnitTestEnv } from "./env";
|
|
||||||
// import { extensions } from "../extensions/extensions";
|
|
||||||
// // import { Container, Service } from 'typedi';
|
|
||||||
|
|
||||||
// export default function locator(env: IEnv) {
|
|
||||||
// extensions();
|
|
||||||
// envRegister(env);
|
|
||||||
// registerRepository(env);
|
|
||||||
// registerController(env);
|
|
||||||
// registerService(env);
|
|
||||||
// // override(MetaDataFileManagerModel, MetaDataFileManagerModel);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const envRegister = (env: IEnv) => {
|
|
||||||
// switch (env.toStringEnv()) {
|
|
||||||
// case UnitTestEnv.env():
|
|
||||||
// // override(IEnv, UnitTestEnv);
|
|
||||||
// return;
|
|
||||||
// case "DevEnv":
|
|
||||||
// // override(IEnv, DevEnv);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const registerRepository = (env: IEnv) => {
|
|
||||||
// switch (env.toStringEnv()) {
|
|
||||||
// case UnitTestEnv.env():
|
|
||||||
// // override(IEnv, UnitTestEnv);
|
|
||||||
|
|
||||||
// return;
|
|
||||||
// case DevEnv.env():
|
|
||||||
// // override(IEnv, DevEnv);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const registerController = (env: IEnv) => {
|
|
||||||
// switch (env.toStringEnv()) {
|
|
||||||
// case UnitTestEnv.env():
|
|
||||||
// return;
|
|
||||||
// case DevEnv.env():
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const registerService = (env: IEnv) => {
|
|
||||||
// switch (env.toStringEnv()) {
|
|
||||||
// case UnitTestEnv.env():
|
|
||||||
// return;
|
|
||||||
// case DevEnv.env():
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// };
|
|
|
@ -6,7 +6,6 @@ export const ArrayExtensions = () => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if ([].equals === undefined) {
|
if ([].equals === undefined) {
|
||||||
// eslint-disable-next-line no-extend-native
|
|
||||||
Array.prototype.equals = function (array, strict = true) {
|
Array.prototype.equals = function (array, strict = true) {
|
||||||
if (!array) return false;
|
if (!array) return false;
|
||||||
|
|
||||||
|
@ -27,7 +26,6 @@ export const ArrayExtensions = () => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if ([].lastElement === undefined) {
|
if ([].lastElement === undefined) {
|
||||||
// eslint-disable-next-line no-extend-native
|
|
||||||
Array.prototype.lastElement = function () {
|
Array.prototype.lastElement = function () {
|
||||||
const instanceCheck = this;
|
const instanceCheck = this;
|
||||||
if (instanceCheck === undefined) {
|
if (instanceCheck === undefined) {
|
||||||
|
@ -39,7 +37,6 @@ export const ArrayExtensions = () => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if ([].isEmpty === undefined) {
|
if ([].isEmpty === undefined) {
|
||||||
// eslint-disable-next-line no-extend-native
|
|
||||||
Array.prototype.isEmpty = function () {
|
Array.prototype.isEmpty = function () {
|
||||||
return this.length === 0;
|
return this.length === 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,8 @@ declare global {
|
||||||
hasPattern(pattern: string): boolean;
|
hasPattern(pattern: string): boolean;
|
||||||
hasNoPattern(pattern: string): boolean;
|
hasNoPattern(pattern: string): boolean;
|
||||||
pathNormalize(): string;
|
pathNormalize(): string;
|
||||||
|
isEqual(str: string): boolean;
|
||||||
|
isEqualMany(str: string[]): boolean;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const extensions = () => {
|
export const extensions = () => {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
export const StringExtensions = () => {
|
export const StringExtensions = () => {
|
||||||
if ("".isEmpty === undefined) {
|
if ("".isEmpty === undefined) {
|
||||||
// eslint-disable-next-line no-extend-native
|
|
||||||
String.prototype.isEmpty = function () {
|
String.prototype.isEmpty = function () {
|
||||||
return this.length === 0;
|
return this.length === 0;
|
||||||
};
|
};
|
||||||
|
@ -11,7 +10,6 @@ export const StringExtensions = () => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if ("".isNotEmpty === undefined) {
|
if ("".isNotEmpty === undefined) {
|
||||||
// eslint-disable-next-line no-extend-native
|
|
||||||
String.prototype.isNotEmpty = function () {
|
String.prototype.isNotEmpty = function () {
|
||||||
return this.length !== 0;
|
return this.length !== 0;
|
||||||
};
|
};
|
||||||
|
@ -31,4 +29,19 @@ export const StringExtensions = () => {
|
||||||
return !this.hasPattern(pattern);
|
return !this.hasPattern(pattern);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if ("".isEqual === undefined) {
|
||||||
|
String.prototype.isEqual = function (str: string) {
|
||||||
|
return this === str;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if ("".isEqualMany === undefined) {
|
||||||
|
String.prototype.isEqualMany = function (str: string[]) {
|
||||||
|
for (const el of str) {
|
||||||
|
if (el === this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,11 +10,13 @@ export const validationModelMiddleware = (
|
||||||
forbidNonWhitelisted = true
|
forbidNonWhitelisted = true
|
||||||
): RequestHandler => {
|
): RequestHandler => {
|
||||||
return (req, res, next) => {
|
return (req, res, next) => {
|
||||||
|
|
||||||
if (type === null && type == undefined) {
|
if (type === null && type == undefined) {
|
||||||
next();
|
next();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const model = plainToInstance(type, req[value]);
|
const model = plainToInstance(type, req[value]);
|
||||||
|
|
||||||
validate(model, { skipMissingProperties, whitelist, forbidNonWhitelisted }).then((errors: ValidationError[]) => {
|
validate(model, { skipMissingProperties, whitelist, forbidNonWhitelisted }).then((errors: ValidationError[]) => {
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
const message = errors.map((error: ValidationError) => Object.values(error.constraints)).join(", ");
|
const message = errors.map((error: ValidationError) => Object.values(error.constraints)).join(", ");
|
||||||
|
|
5
server/src/core/models/instance.ts
Normal file
5
server/src/core/models/instance.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export interface Instance {
|
||||||
|
instanceName: string;
|
||||||
|
path: string;
|
||||||
|
instancePath: string;
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import { Trigger } from "../../features/_triggers/models/trigger_database_model";
|
|
||||||
import { EXEC_TYPE } from "./exec_error_model";
|
import { EXEC_TYPE } from "./exec_error_model";
|
||||||
|
|
||||||
|
export interface Trigger {}
|
||||||
export interface IPipeline {
|
export interface IPipeline {
|
||||||
process: IProcess;
|
process: IProcess;
|
||||||
trigger?: Trigger;
|
trigger?: Trigger;
|
||||||
|
|
|
@ -21,3 +21,4 @@ export class RobossemblerAssets {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
189
server/src/core/models/skill_model.ts
Normal file
189
server/src/core/models/skill_model.ts
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
import { IsArray, IsEnum, IsNotEmpty, IsString, ValidateNested } from "class-validator";
|
||||||
|
import { Type } from "class-transformer";
|
||||||
|
export class TopicViewModel {
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
name: string;
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
type: string;
|
||||||
|
constructor(name: string, type: string) {
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
static empty() {
|
||||||
|
return new TopicViewModel("", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IParam {
|
||||||
|
type: string;
|
||||||
|
dependency: object;
|
||||||
|
}
|
||||||
|
export interface Skill {
|
||||||
|
SkillPackage: ISkillPackage;
|
||||||
|
Module: IModule;
|
||||||
|
Launch: ILaunch;
|
||||||
|
ROS2: IRos2;
|
||||||
|
BTAction: IBTAction[];
|
||||||
|
Interface: IInterface;
|
||||||
|
Settings: ISetting[];
|
||||||
|
xxx: IXxx;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IBTAction {
|
||||||
|
name: string;
|
||||||
|
format: string;
|
||||||
|
type: string;
|
||||||
|
param: IParam[];
|
||||||
|
result: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IInterface {
|
||||||
|
Input: IPut[];
|
||||||
|
Output: IPut[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPut {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILaunch {
|
||||||
|
executable: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IModule {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRos2 {
|
||||||
|
node_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISetting {
|
||||||
|
name: string;
|
||||||
|
value: number | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISkillPackage {
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
format: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IXxx {
|
||||||
|
cameraLink: string;
|
||||||
|
topicImage: string;
|
||||||
|
topicCameraInfo: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SkillPackage implements ISkillPackage {
|
||||||
|
@IsString()
|
||||||
|
name: string;
|
||||||
|
@IsString()
|
||||||
|
version: string;
|
||||||
|
@IsString()
|
||||||
|
format: string;
|
||||||
|
}
|
||||||
|
export class Module implements IModule {
|
||||||
|
@IsString()
|
||||||
|
name: string;
|
||||||
|
@IsString()
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
export class BTAction implements IBTAction {
|
||||||
|
@IsString()
|
||||||
|
name: string;
|
||||||
|
@IsString()
|
||||||
|
format: string;
|
||||||
|
@IsString()
|
||||||
|
type: string;
|
||||||
|
@IsArray()
|
||||||
|
param: IParam[];
|
||||||
|
@IsArray()
|
||||||
|
result: string[];
|
||||||
|
}
|
||||||
|
export class Launch implements ILaunch {
|
||||||
|
@IsString()
|
||||||
|
executable: string;
|
||||||
|
}
|
||||||
|
export class Ros2 implements IRos2 {
|
||||||
|
@IsString()
|
||||||
|
node_name: string;
|
||||||
|
}
|
||||||
|
export class Put implements IPut {
|
||||||
|
@IsString()
|
||||||
|
name: string;
|
||||||
|
@IsString()
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
export class Interface implements IInterface {
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => Put)
|
||||||
|
Input: IPut[];
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => Put)
|
||||||
|
Output: IPut[];
|
||||||
|
}
|
||||||
|
export class Setting implements ISetting {
|
||||||
|
name: string;
|
||||||
|
value: string | number;
|
||||||
|
}
|
||||||
|
export class Xxx implements IXxx {
|
||||||
|
cameraLink: string;
|
||||||
|
topicImage: string;
|
||||||
|
topicCameraInfo: string;
|
||||||
|
}
|
||||||
|
export class SkillModel implements Skill {
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => SkillPackage)
|
||||||
|
SkillPackage: ISkillPackage;
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => Module)
|
||||||
|
Module: IModule;
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => Launch)
|
||||||
|
Launch: ILaunch;
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => Ros2)
|
||||||
|
ROS2: IRos2;
|
||||||
|
@ValidateNested()
|
||||||
|
@IsArray()
|
||||||
|
@Type(() => BTAction)
|
||||||
|
BTAction: IBTAction[];
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => Interface)
|
||||||
|
Interface: IInterface;
|
||||||
|
@ValidateNested()
|
||||||
|
@IsArray()
|
||||||
|
@Type(() => Setting)
|
||||||
|
Settings: ISetting[];
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => Xxx)
|
||||||
|
xxx: IXxx;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum BtAction {
|
||||||
|
ACTION = "ACTION",
|
||||||
|
CONDITION = "CONDITION",
|
||||||
|
}
|
||||||
|
export class BtActionViewModel implements IBTAction {
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
name: string;
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
format: string;
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
type: string;
|
||||||
|
param: IParam[];
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
result: string[];
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsEnum(BtAction)
|
||||||
|
typeAction: BtAction;
|
||||||
|
}
|
|
@ -1,4 +1,13 @@
|
||||||
export enum StaticFiles {
|
export enum StaticFilesProject {
|
||||||
robossembler_assets = "robossembler_assets.json",
|
robossembler_assets = "robossembler_assets.json",
|
||||||
assets = "/assets/assets.json",
|
assets = "/assets/assets.json",
|
||||||
|
parts = "/assets/parts.json",
|
||||||
|
scenes = "/scenes/",
|
||||||
|
behaviorTrees = "behavior_trees",
|
||||||
|
robots = 'robots'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum StaticFilesServer {
|
||||||
|
process = "/process/",
|
||||||
|
digitalTwins = "/digital_twins/",
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { promisify } from "node:util";
|
import { promisify } from "node:util";
|
||||||
import { rimraf } from 'rimraf'
|
import { rimraf } from "rimraf";
|
||||||
|
|
||||||
export class FileSystemRepository {
|
export class FileSystemRepository {
|
||||||
public createDir = promisify(fs.mkdir);
|
public createDir = promisify(fs.mkdir);
|
||||||
|
@ -8,6 +8,7 @@ export class FileSystemRepository {
|
||||||
public writeFileAsync = promisify(fs.writeFile);
|
public writeFileAsync = promisify(fs.writeFile);
|
||||||
public dirIsExists = promisify(fs.exists);
|
public dirIsExists = promisify(fs.exists);
|
||||||
public stat = promisify(fs.stat);
|
public stat = promisify(fs.stat);
|
||||||
|
public deleteDir = promisify(fs.unlink);
|
||||||
public readFileAsync = promisify(fs.readFile);
|
public readFileAsync = promisify(fs.readFile);
|
||||||
public readdir = promisify(fs.readdir);
|
public readdir = promisify(fs.readdir);
|
||||||
public deleteDirRecursive = rimraf;
|
public deleteDirRecursive = rimraf;
|
||||||
|
@ -21,7 +22,9 @@ export class FileSystemRepository {
|
||||||
}
|
}
|
||||||
return await this.readFileAsync(path);
|
return await this.readFileAsync(path);
|
||||||
}
|
}
|
||||||
|
delete = async (path: string) => {
|
||||||
|
return await this.deleteDir(path);
|
||||||
|
};
|
||||||
readDirRecursive(path: string, filesToDir: string[] = []): string[] {
|
readDirRecursive(path: string, filesToDir: string[] = []): string[] {
|
||||||
const files = fs.readdirSync(path);
|
const files = fs.readdirSync(path);
|
||||||
files.forEach((file) => {
|
files.forEach((file) => {
|
||||||
|
@ -41,5 +44,4 @@ export class FileSystemRepository {
|
||||||
});
|
});
|
||||||
return filesToDir;
|
return filesToDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
16
server/src/core/scenarios/create_intance_scenario.ts
Normal file
16
server/src/core/scenarios/create_intance_scenario.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { CallbackStrategyWithValidationModel, ResponseBase } from "../controllers/http_controller";
|
||||||
|
import { Instance } from "../models/instance";
|
||||||
|
import { CreateDataBaseModelUseCase } from "../usecases/create_database_model_usecase";
|
||||||
|
import { CreateFolderUseCase } from "../usecases/create_folder_usecase";
|
||||||
|
|
||||||
|
export abstract class CreateInstanceScenario<V extends Instance> extends CallbackStrategyWithValidationModel<V> {
|
||||||
|
abstract validationModel: V;
|
||||||
|
abstract databaseModel: any;
|
||||||
|
call = async (model: V): ResponseBase => {
|
||||||
|
model.instancePath = `${model.path.pathNormalize()}/${model.instanceName}`.pathNormalize();
|
||||||
|
model.path = model.path.pathNormalize();
|
||||||
|
return (await new CreateFolderUseCase().call(model.instancePath)).map(
|
||||||
|
async () => await new CreateDataBaseModelUseCase(this.databaseModel).call(model)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
16
server/src/core/scenarios/create_many_folder_scenario.ts
Normal file
16
server/src/core/scenarios/create_many_folder_scenario.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { Result } from "../helpers/result";
|
||||||
|
import { CreateFolderUseCase } from "../usecases/create_folder_usecase";
|
||||||
|
|
||||||
|
export class CreateManyFolderScenario {
|
||||||
|
call = async (path: string, foldersNames: string[]): Promise<Result<Error, string>> => {
|
||||||
|
try {
|
||||||
|
foldersNames.forEach(async (folder) => {
|
||||||
|
await new CreateFolderUseCase().call(`${path}${folder}`.normalize());
|
||||||
|
});
|
||||||
|
return Result.ok("many folder created");
|
||||||
|
} catch (error) {
|
||||||
|
return Result.error(new Error(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
22
server/src/core/scenarios/create_template_scenario.ts
Normal file
22
server/src/core/scenarios/create_template_scenario.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { App } from "../controllers/app";
|
||||||
|
import { CallbackStrategyWithValidationModel, ResponseBase } from "../controllers/http_controller";
|
||||||
|
import { StaticFilesServer } from "../models/static_files";
|
||||||
|
import { CreateDataBaseModelUseCase } from "../usecases/create_database_model_usecase";
|
||||||
|
import { CreateFolderUseCase } from "../usecases/create_folder_usecase";
|
||||||
|
|
||||||
|
interface IModel {
|
||||||
|
path: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class CreateTemplateScenario<V extends IModel> extends CallbackStrategyWithValidationModel<V> {
|
||||||
|
validationModel: V;
|
||||||
|
abstract databaseModel: any;
|
||||||
|
abstract path: string;
|
||||||
|
call = async (model: V): ResponseBase => {
|
||||||
|
model.path = App.staticFilesStoreDir() + StaticFilesServer.process + model.name;
|
||||||
|
return (await new CreateFolderUseCase().call(model.path)).map(() => {
|
||||||
|
return new CreateDataBaseModelUseCase(this.databaseModel).call(model);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
20
server/src/core/scenarios/delete_instance_scenario.ts
Normal file
20
server/src/core/scenarios/delete_instance_scenario.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { CallbackStrategyWithIdQuery, ResponseBase } from "../controllers/http_controller";
|
||||||
|
import { Instance } from "../models/instance";
|
||||||
|
import { DeleteDataBaseModelUseCase } from "../usecases/delete_database_model_usecase";
|
||||||
|
import { DeleteRecursiveFolderUseCase } from "../usecases/delete_recursive_folder_usecase";
|
||||||
|
import { ReadByIdDataBaseModelUseCase } from "../usecases/read_by_id_database_model_usecase";
|
||||||
|
import { CoreValidation } from "../validations/core_validation";
|
||||||
|
import { MongoIdValidation } from "../validations/mongo_id_validation";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export abstract class DeleteInstanceScenario<D extends Instance> extends CallbackStrategyWithIdQuery {
|
||||||
|
abstract databaseModel: any;
|
||||||
|
idValidationExpression: CoreValidation = new MongoIdValidation();
|
||||||
|
call = async (id: string): ResponseBase =>
|
||||||
|
(await new ReadByIdDataBaseModelUseCase<D>(this.databaseModel).call(id)).map(async (model) => {
|
||||||
|
return (await new DeleteRecursiveFolderUseCase().call(model.instancePath)).map(
|
||||||
|
async () => await new DeleteDataBaseModelUseCase(this.databaseModel).call(id)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
20
server/src/core/scenarios/delete_template_scenario.ts
Normal file
20
server/src/core/scenarios/delete_template_scenario.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { CalculationsTemplateValidationModel } from "../../features/calculations_templates/models/calculations_template_validation_model";
|
||||||
|
import { CallbackStrategyWithIdQuery, ResponseBase } from "../controllers/http_controller";
|
||||||
|
import { DeleteDataBaseModelUseCase } from "../usecases/delete_database_model_usecase";
|
||||||
|
import { DeleteRecursiveFolderUseCase } from "../usecases/delete_recursive_folder_usecase";
|
||||||
|
import { ReadByIdDataBaseModelUseCase } from "../usecases/read_by_id_database_model_usecase";
|
||||||
|
import { CoreValidation } from "../validations/core_validation";
|
||||||
|
import { MongoIdValidation } from "../validations/mongo_id_validation";
|
||||||
|
|
||||||
|
export abstract class DeleteTemplateScenario extends CallbackStrategyWithIdQuery {
|
||||||
|
abstract databaseModel: any;
|
||||||
|
idValidationExpression: CoreValidation = new MongoIdValidation();
|
||||||
|
call = async (id: string): ResponseBase =>
|
||||||
|
(await new ReadByIdDataBaseModelUseCase<CalculationsTemplateValidationModel>(this.databaseModel).call(id)).map(
|
||||||
|
async (model) => {
|
||||||
|
return (await new DeleteRecursiveFolderUseCase().call(model.path)).map(
|
||||||
|
async () => await new DeleteDataBaseModelUseCase(this.databaseModel).call(id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
72
server/src/core/scenarios/exec_process_scenario_v2.ts
Normal file
72
server/src/core/scenarios/exec_process_scenario_v2.ts
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import { Disposable, Listener, TypedEvent } from "../helpers/typed_event";
|
||||||
|
import { GetRootDirUseCase } from "../usecases/get_root_dir_usecase"
|
||||||
|
import { exec } from 'child_process';
|
||||||
|
|
||||||
|
export const activeProcessPids: { [name: string]: { pid: number, status: ProcessStatus } } = {}
|
||||||
|
|
||||||
|
export enum ProcessStatus {
|
||||||
|
run = 'run',
|
||||||
|
endError = 'endError',
|
||||||
|
endOk = 'endOk',
|
||||||
|
userDelete = 'userDelete',
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExecutorProgramServiceV2 extends TypedEvent<{ [name: string]: { pid: number, status: ProcessStatus } }> {}
|
||||||
|
|
||||||
|
export const executorProgramServiceV2 = new ExecutorProgramServiceV2();
|
||||||
|
class ProcessData {
|
||||||
|
log: string | undefined;
|
||||||
|
status: ProcessStatus;
|
||||||
|
constructor(log: string | undefined, status: ProcessStatus) {
|
||||||
|
|
||||||
|
if (log !== undefined) {
|
||||||
|
this.log = log;
|
||||||
|
}
|
||||||
|
this.status = status;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
abstract class Watcher {
|
||||||
|
}
|
||||||
|
export abstract class ExecProcessWatcher extends TypedEvent<ProcessData> implements Watcher {
|
||||||
|
logs: string[] = [];
|
||||||
|
status: ProcessStatus;
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.on((event) => {
|
||||||
|
if (event.log !== undefined) {
|
||||||
|
this.logs.push(event.log);
|
||||||
|
}
|
||||||
|
this.status = event.status;
|
||||||
|
if (event.status.isEqualMany([ProcessStatus.endError, ProcessStatus.endOk])) {
|
||||||
|
this.result()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
abstract result(): Promise<any>
|
||||||
|
|
||||||
|
}
|
||||||
|
export class ExecProcessScenarioV2 {
|
||||||
|
call = (command: string, watcher: ExecProcessWatcher, name?: string): void => {
|
||||||
|
const process = exec(command, { cwd: new GetRootDirUseCase().call() });
|
||||||
|
if (process.pid) {
|
||||||
|
activeProcessPids[name ?? command] = { pid: process.pid, status: ProcessStatus.run };
|
||||||
|
executorProgramServiceV2.emit(activeProcessPids);
|
||||||
|
}
|
||||||
|
process.stdout.on('data', (data) => watcher.emit(new ProcessData(data, ProcessStatus.run)))
|
||||||
|
process.stderr.on('data', (data) => watcher.emit(new ProcessData(data, ProcessStatus.run)));
|
||||||
|
process.on('close', (code) => {
|
||||||
|
if (code === 0) {
|
||||||
|
watcher.emit(new ProcessData(undefined, ProcessStatus.endOk))
|
||||||
|
activeProcessPids[name ?? command] = { pid: process.pid ?? 0, status: ProcessStatus.endOk }
|
||||||
|
executorProgramServiceV2.emit(activeProcessPids);
|
||||||
|
} else {
|
||||||
|
watcher.emit(new ProcessData(undefined, ProcessStatus.endError))
|
||||||
|
activeProcessPids[name ?? command] = { pid: process.pid ?? 0, status: ProcessStatus.endError };
|
||||||
|
executorProgramServiceV2.emit(activeProcessPids);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('error', (err) => watcher.emit(new ProcessData(err.message, ProcessStatus.endError)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { CallbackStrategyWithIdQuery } from "../controllers/http_controller";
|
||||||
|
import { Result } from "../helpers/result";
|
||||||
|
import { ReadByIdDataBaseModelUseCase } from "../usecases/read_by_id_database_model_usecase";
|
||||||
|
import { CoreValidation } from "../validations/core_validation";
|
||||||
|
import { MongoIdValidation } from "../validations/mongo_id_validation";
|
||||||
|
|
||||||
|
export class ReadByIdDataBaseModelScenario<D> extends CallbackStrategyWithIdQuery {
|
||||||
|
idValidationExpression: CoreValidation = new MongoIdValidation();
|
||||||
|
databaseModel: D;
|
||||||
|
|
||||||
|
constructor(model) {
|
||||||
|
super();
|
||||||
|
this.databaseModel = model;
|
||||||
|
}
|
||||||
|
call = async (id: string): Promise<Result<Error, D>> => {
|
||||||
|
try {
|
||||||
|
return new ReadByIdDataBaseModelUseCase<D>(this.databaseModel).call(id);
|
||||||
|
} catch (error) {
|
||||||
|
return Result.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,28 +1,26 @@
|
||||||
import {
|
|
||||||
IProjectInstanceModel,
|
|
||||||
ProjectInstanceDbModel,
|
import { IProjectModel, ProjectDBModel } from "../../features/projects/models/project_model_database_model";
|
||||||
} from "../../features/projects/models/project_instance_database_model";
|
|
||||||
import { pipelineRealTimeService } from "../../features/_realtime/realtime_presentation";
|
|
||||||
import { App } from "../controllers/app";
|
import { App } from "../controllers/app";
|
||||||
|
import { PipelineRealTimeService } from "../services/pipeline_real_time_service";
|
||||||
import { CreateFolderUseCase } from "../usecases/create_folder_usecase";
|
import { CreateFolderUseCase } from "../usecases/create_folder_usecase";
|
||||||
import { SearchDataBaseModelUseCase } from "../usecases/search_database_model_usecase";
|
import { SearchOneDataBaseModelUseCase } from "../usecases/search_database_model_usecase";
|
||||||
|
|
||||||
|
export const pipelineRealTimeService = new PipelineRealTimeService();
|
||||||
|
|
||||||
|
|
||||||
export class SetLastActivePipelineToRealTimeServiceScenario {
|
export class SetLastActivePipelineToRealTimeServiceScenario {
|
||||||
call = async (): Promise<void> => {
|
call = async (): Promise<void> => {
|
||||||
return (
|
return (
|
||||||
await new SearchDataBaseModelUseCase<IProjectInstanceModel>(ProjectInstanceDbModel).call({
|
await new SearchOneDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call({
|
||||||
isActive: true,
|
isActive: true,
|
||||||
})
|
})
|
||||||
).fold(
|
).fold(
|
||||||
async (projectModel) => {
|
async (projectModel) => {
|
||||||
if (projectModel.project === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const projectPath = App.staticFilesStoreDir() + projectModel.rootDir + "/";
|
const projectPath = App.staticFilesStoreDir() + projectModel.rootDir + "/";
|
||||||
await new CreateFolderUseCase().call(projectPath);
|
await new CreateFolderUseCase().call(projectPath);
|
||||||
pipelineRealTimeService.setPipelineDependency(
|
pipelineRealTimeService.setPipelineDependency(
|
||||||
projectModel.project.pipelines,
|
|
||||||
projectPath,
|
projectPath,
|
||||||
projectModel._id,
|
projectModel._id,
|
||||||
projectModel.rootDir
|
projectModel.rootDir
|
||||||
|
|
|
@ -60,7 +60,7 @@ export class ExecutorProgramService
|
||||||
const execError = ExecError.isExecError(e);
|
const execError = ExecError.isExecError(e);
|
||||||
|
|
||||||
if (execError instanceof ExecError) {
|
if (execError instanceof ExecError) {
|
||||||
execError.id = id
|
execError.id = id;
|
||||||
this.emit(Result.error(execError));
|
this.emit(Result.error(execError));
|
||||||
this.worker = undefined;
|
this.worker = undefined;
|
||||||
return;
|
return;
|
||||||
|
@ -68,7 +68,7 @@ export class ExecutorProgramService
|
||||||
|
|
||||||
const executorResult = ExecutorResult.isExecutorResult(e);
|
const executorResult = ExecutorResult.isExecutorResult(e);
|
||||||
if (executorResult instanceof ExecutorResult) {
|
if (executorResult instanceof ExecutorResult) {
|
||||||
executorResult.id = id
|
executorResult.id = id;
|
||||||
this.emit(Result.ok(executorResult));
|
this.emit(Result.ok(executorResult));
|
||||||
this.worker = undefined;
|
this.worker = undefined;
|
||||||
return;
|
return;
|
||||||
|
@ -103,7 +103,8 @@ export class ExecutorProgramService
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.workerExecuted(command, WorkerType.SPAWN, args, id);
|
const commands = command.split(" ");
|
||||||
|
this.workerExecuted(commands.at(0), WorkerType.SPAWN, commands.slice(1, commands.length), id);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,9 +58,8 @@ export class PipelineRealTimeService extends TypedEvent<ActivePipeline> {
|
||||||
this.status.pipelineIsRunning = false;
|
this.status.pipelineIsRunning = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setPipelineDependency(pipelineModels: IPipeline[], path: string, projectId: string, rootDir: string) {
|
setPipelineDependency(path: string, projectId: string, rootDir: string) {
|
||||||
this.pipelineModels = pipelineModels;
|
this.status["projectId"] = projectId;
|
||||||
this.status["projectId"] = projectId;
|
|
||||||
this.status["path"] = path;
|
this.status["path"] = path;
|
||||||
this.status["rootDir"] = rootDir;
|
this.status["rootDir"] = rootDir;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { FilesChangeNotifierService, IHashesCache } from "./files_change_notifier_service";
|
import { FilesChangeNotifierService, IHashesCache } from "./files_change_notifier_service";
|
||||||
import { IPipeline } from "../models/process_model";
|
import { IPipeline, Trigger } from "../models/process_model";
|
||||||
import { ExecutorProgramService } from "./executor_program_service";
|
import { ExecutorProgramService } from "./executor_program_service";
|
||||||
import { EXEC_EVENT, ExecError, SpawnError } from "../models/exec_error_model";
|
import { EXEC_EVENT, ExecError, SpawnError } from "../models/exec_error_model";
|
||||||
import { TypedEvent } from "../helpers/typed_event";
|
import { TypedEvent } from "../helpers/typed_event";
|
||||||
|
@ -7,7 +7,6 @@ import { Result } from "../helpers/result";
|
||||||
import { ExecutorResult } from "../models/executor_result";
|
import { ExecutorResult } from "../models/executor_result";
|
||||||
import { delay } from "../helpers/delay";
|
import { delay } from "../helpers/delay";
|
||||||
import { TriggerService } from "./trigger_service";
|
import { TriggerService } from "./trigger_service";
|
||||||
import { Trigger } from "../../features/_triggers/models/trigger_database_model";
|
|
||||||
|
|
||||||
export interface Iteration {
|
export interface Iteration {
|
||||||
hashes: IHashesCache | null;
|
hashes: IHashesCache | null;
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
// @ts-nocheck
|
||||||
import * as vm from "node:vm";
|
import * as vm from "node:vm";
|
||||||
import { IHashesCache } from "./files_change_notifier_service";
|
import { IHashesCache } from "./files_change_notifier_service";
|
||||||
import { EventsFileChanger } from "../models/meta_data_file_manager_model";
|
import { EventsFileChanger } 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 { Trigger, TriggerType } from "../../features/_triggers/models/trigger_database_model";
|
import { Trigger } from "../models/process_model";
|
||||||
|
|
||||||
export class TriggerCallResult {
|
export class TriggerCallResult {
|
||||||
results: Array<TriggerSuccessResult | TriggerErrorReport>;
|
results: Array<TriggerSuccessResult | TriggerErrorReport>;
|
||||||
|
|
|
@ -1,24 +1,19 @@
|
||||||
import { App } from "../controllers/app";
|
import { App } from "../controllers/app";
|
||||||
|
import { StaticFilesServer } from "../models/static_files";
|
||||||
import { FileSystemRepository } from "../repository/file_system_repository";
|
import { FileSystemRepository } from "../repository/file_system_repository";
|
||||||
import { CreateFolderUseCase } from "./create_folder_usecase";
|
import { CreateFolderUseCase } from "./create_folder_usecase";
|
||||||
|
|
||||||
export class CheckAndCreateStaticFilesFolderUseCase {
|
export class CheckAndCreateStaticFilesFolderUseCase {
|
||||||
fileSystemRepository: FileSystemRepository;
|
fileSystemRepository: FileSystemRepository = new FileSystemRepository();
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.fileSystemRepository = new FileSystemRepository();
|
|
||||||
}
|
|
||||||
call = async (): Promise<void> => {
|
call = async (): Promise<void> => {
|
||||||
|
Object.keys(StaticFilesServer).forEach(async (key) => {
|
||||||
|
if (!(await this.fileSystemRepository.dirIsExists(App.staticFilesStoreDir() + key))) {
|
||||||
|
await new CreateFolderUseCase().call(App.staticFilesStoreDir() + key);
|
||||||
|
}
|
||||||
|
});
|
||||||
if (await this.fileSystemRepository.dirIsExists(App.staticFilesStoreDir())) {
|
if (await this.fileSystemRepository.dirIsExists(App.staticFilesStoreDir())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const createFolderUseCase = await new CreateFolderUseCase().call(App.staticFilesStoreDir());
|
await new CreateFolderUseCase().call(App.staticFilesStoreDir());
|
||||||
|
|
||||||
createFolderUseCase.fold(
|
|
||||||
(_s) => {},
|
|
||||||
(e) => {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
14
server/src/core/usecases/delete_file_usecase.ts
Normal file
14
server/src/core/usecases/delete_file_usecase.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { Result } from "../helpers/result";
|
||||||
|
import { FileSystemRepository } from "../repository/file_system_repository";
|
||||||
|
|
||||||
|
export class DeleteFileUseCase {
|
||||||
|
fileSystemRepository = new FileSystemRepository();
|
||||||
|
call = (path: string) => {
|
||||||
|
try {
|
||||||
|
this.fileSystemRepository.delete(path);
|
||||||
|
return Result.ok("file delete");
|
||||||
|
} catch {
|
||||||
|
return Result.error("Unknown error");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ import { FileSystemRepository } from "../repository/file_system_repository";
|
||||||
export class DeleteRecursiveFolderUseCase{
|
export class DeleteRecursiveFolderUseCase{
|
||||||
repository:FileSystemRepository = new FileSystemRepository()
|
repository:FileSystemRepository = new FileSystemRepository()
|
||||||
call = async (path:string):Promise<Result<void,void>> =>{
|
call = async (path:string):Promise<Result<void,void>> =>{
|
||||||
console.log(path)
|
|
||||||
await this.repository.deleteDirRecursive(path)
|
await this.repository.deleteDirRecursive(path)
|
||||||
return Result.ok()
|
return Result.ok()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
|
import * as cp from "child_process";
|
||||||
import { CallbackStrategyWithEmpty } from "../controllers/http_controller";
|
import { CallbackStrategyWithEmpty } from "../controllers/http_controller";
|
||||||
import { Result } from "../helpers/result";
|
import { Result } from "../helpers/result";
|
||||||
import { TypedEvent } from "../helpers/typed_event";
|
import { TypedEvent } from "../helpers/typed_event";
|
||||||
import { EXEC_TYPE, ExecError, SpawnError } from "../models/exec_error_model";
|
import { EXEC_EVENT, EXEC_TYPE, ExecError, SpawnError } from "../models/exec_error_model";
|
||||||
import { ExecutorResult } from "../models/executor_result";
|
import { ExecutorResult } from "../models/executor_result";
|
||||||
import { ExecutorProgramService } from "../services/executor_program_service";
|
import { ExecutorProgramService } from "../services/executor_program_service";
|
||||||
|
|
||||||
export const executorProgramService = new ExecutorProgramService("");
|
export const executorProgramService = new ExecutorProgramService("");
|
||||||
|
|
||||||
export class KillLastProcessUseCase extends CallbackStrategyWithEmpty {
|
export class KillLastProcessUseCase extends CallbackStrategyWithEmpty {
|
||||||
call = async (): Promise<Result<undefined, string>> => {
|
call = async (): Promise<Result<undefined, string>> => {
|
||||||
executorProgramService.deleteWorker();
|
executorProgramService.deleteWorker();
|
||||||
|
@ -26,7 +28,7 @@ export class ExecProcessUseCase {
|
||||||
call = async (
|
call = async (
|
||||||
path: string,
|
path: string,
|
||||||
command: string,
|
command: string,
|
||||||
id:string,
|
id: string,
|
||||||
watcher?: TypedEvent<Result<ExecError | SpawnError, ExecutorResult>>
|
watcher?: TypedEvent<Result<ExecError | SpawnError, ExecutorResult>>
|
||||||
): Promise<Result<Error, string>> => {
|
): Promise<Result<Error, string>> => {
|
||||||
try {
|
try {
|
||||||
|
@ -34,7 +36,7 @@ export class ExecProcessUseCase {
|
||||||
executorProgramService.on((event) => {
|
executorProgramService.on((event) => {
|
||||||
if (watcher) watcher.emit(event);
|
if (watcher) watcher.emit(event);
|
||||||
});
|
});
|
||||||
executorProgramService.call(EXEC_TYPE.EXEC, command, undefined ,id);
|
executorProgramService.call(EXEC_TYPE.EXEC, command, undefined, id);
|
||||||
|
|
||||||
return Result.ok("ok");
|
return Result.ok("ok");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -42,3 +44,39 @@ export class ExecProcessUseCase {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SpawnProcessUseCase {
|
||||||
|
call = async (
|
||||||
|
path: string,
|
||||||
|
command: string,
|
||||||
|
id: string,
|
||||||
|
watcher?: TypedEvent<Result<ExecError | SpawnError, ExecutorResult>>
|
||||||
|
): Promise<Result<Error, string>> => {
|
||||||
|
try {
|
||||||
|
const commands = command.split(" ");
|
||||||
|
|
||||||
|
const subprocess = cp.spawn(commands.at(0), commands.slice(1, commands.length), {
|
||||||
|
cwd: path,
|
||||||
|
});
|
||||||
|
const sendWatcher = (event: Buffer) => {
|
||||||
|
if (watcher) {
|
||||||
|
watcher.emit(Result.ok(new ExecutorResult(EXEC_TYPE.SPAWN, EXEC_EVENT.PROGRESS, event.toString())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
subprocess.stdout.on("data", (data) => sendWatcher(data));
|
||||||
|
|
||||||
|
subprocess.stderr.on("data", (data) => sendWatcher(data));
|
||||||
|
|
||||||
|
subprocess.on("error", (error) => {
|
||||||
|
console.error(`Ошибка: ${error.message}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
subprocess.on("close", (code) => {
|
||||||
|
console.log(`Процесс завершился с кодом: ${code}`);
|
||||||
|
});
|
||||||
|
return Result.ok('ok');
|
||||||
|
} catch (error) {
|
||||||
|
return Result.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
5
server/src/core/usecases/get_root_dir_usecase.ts
Normal file
5
server/src/core/usecases/get_root_dir_usecase.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import * as os from 'os';
|
||||||
|
|
||||||
|
export class GetRootDirUseCase {
|
||||||
|
call = (): string => os.homedir()
|
||||||
|
}
|
|
@ -2,11 +2,9 @@ import { Result } from "../helpers/result";
|
||||||
import { FileSystemRepository } from "../repository/file_system_repository";
|
import { FileSystemRepository } from "../repository/file_system_repository";
|
||||||
|
|
||||||
export class ReadFileAndParseJsonUseCase {
|
export class ReadFileAndParseJsonUseCase {
|
||||||
fileSystemRepository: FileSystemRepository;
|
fileSystemRepository: FileSystemRepository = new FileSystemRepository();
|
||||||
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.fileSystemRepository = new FileSystemRepository();
|
|
||||||
}
|
|
||||||
async call<T>(path: string): Promise<Result<string, T>> {
|
async call<T>(path: string): Promise<Result<string, T>> {
|
||||||
try {
|
try {
|
||||||
if (RegExp(path).test("^(.+)/([^/]+)$")) {
|
if (RegExp(path).test("^(.+)/([^/]+)$")) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Result } from "../helpers/result";
|
import { Result } from "../helpers/result";
|
||||||
|
|
||||||
export class SearchDataBaseModelUseCase<T> {
|
export class SearchOneDataBaseModelUseCase<T> {
|
||||||
model: any;
|
model: any;
|
||||||
|
|
||||||
constructor(model: any) {
|
constructor(model: any) {
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { Result } from "../helpers/result";
|
||||||
|
|
||||||
|
export class SearchManyDataBaseModelUseCase<T> {
|
||||||
|
model: any;
|
||||||
|
|
||||||
|
constructor(model: any) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
call = async (findFilter: Partial<T>, error: string = "not found database"): Promise<Result<string, T>> => {
|
||||||
|
const result = await this.model.find(findFilter);
|
||||||
|
if (result === null) {
|
||||||
|
return Result.error(error);
|
||||||
|
} else {
|
||||||
|
return Result.ok(result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,58 +0,0 @@
|
||||||
import { CallbackStrategyWithEmpty, CoreHttpController } from "../../core/controllers/http_controller";
|
|
||||||
import { Result } from "../../core/helpers/result";
|
|
||||||
import { EXEC_TYPE } from "../../core/models/exec_error_model";
|
|
||||||
import { ExecutorResult } from "../../core/models/executor_result";
|
|
||||||
import { IPipeline, IssueType, StackGenerateType } from "../../core/models/process_model";
|
|
||||||
import { StackService } from "../../core/services/stack_service";
|
|
||||||
import { TriggerType } from "../_triggers/models/trigger_database_model";
|
|
||||||
|
|
||||||
class NixStoreModel {}
|
|
||||||
|
|
||||||
const getNixStoreFolderCommand: IPipeline[] = [
|
|
||||||
{
|
|
||||||
process: {
|
|
||||||
type: EXEC_TYPE.EXEC,
|
|
||||||
command: `ls /nix/store`,
|
|
||||||
isGenerating: true,
|
|
||||||
isLocaleCode: false,
|
|
||||||
issueType: IssueType.WARNING,
|
|
||||||
},
|
|
||||||
trigger: {
|
|
||||||
type: TriggerType.FILE,
|
|
||||||
value: ["context"],
|
|
||||||
},
|
|
||||||
env: null,
|
|
||||||
stackGenerateType: StackGenerateType.SINGLETON,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
class GetNixStorePackagesUseCase extends CallbackStrategyWithEmpty {
|
|
||||||
call = async () => {
|
|
||||||
const stackService = new StackService(
|
|
||||||
getNixStoreFolderCommand,
|
|
||||||
"/Users/idontsudo/Desktop/testdeck-mocha-seed/server/build/test/"
|
|
||||||
);
|
|
||||||
stackService.call();
|
|
||||||
|
|
||||||
const promise = new Promise((resolve, _reject) => {
|
|
||||||
stackService.on((e) => {
|
|
||||||
const iteration = e.firstElement();
|
|
||||||
if (iteration.result instanceof ExecutorResult) {
|
|
||||||
const nixPackage = iteration.result.data;
|
|
||||||
resolve(nixPackage.split("\n").filter((e) => e.hasNoPattern(".drv")));
|
|
||||||
} else {
|
|
||||||
return "GetNixStorePackagesUseCase unknown Error";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return Result.ok(await promise);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export class NixStoreManagerPresentation extends CoreHttpController<NixStoreModel> {
|
|
||||||
constructor() {
|
|
||||||
super({
|
|
||||||
url: "nix_store_api",
|
|
||||||
});
|
|
||||||
super.get(new GetNixStorePackagesUseCase().call);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
import { Schema, model } from "mongoose";
|
|
||||||
import { IPipeline } from "../../../core/models/process_model";
|
|
||||||
import { schemaProcess } from "../../_process/models/process_database_model";
|
|
||||||
import { triggerSchema } from "../../_triggers/models/trigger_database_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,
|
|
||||||
},
|
|
||||||
stackGenerateType: {
|
|
||||||
type: String,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
}).plugin(require("mongoose-autopopulate"));
|
|
||||||
|
|
||||||
export const schemaPipeline = "Pipeline";
|
|
||||||
|
|
||||||
export const PipelineDBModel = model<IPipeline>(schemaPipeline, PipelineSchema);
|
|
|
@ -1,21 +0,0 @@
|
||||||
import { IsOptional, ValidateNested } from "class-validator";
|
|
||||||
import { IPipeline, IProcess, StackGenerateType } from "../../../core/models/process_model";
|
|
||||||
import { Type } from "class-transformer";
|
|
||||||
import { ProcessModel } from "../../_process/models/process_validation_model";
|
|
||||||
import { TriggerModelValidationModel } from "../../_triggers/models/trigger_validation_model";
|
|
||||||
|
|
||||||
export class PipelineModel implements IPipeline {
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => ProcessModel)
|
|
||||||
public process: IProcess;
|
|
||||||
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => TriggerModelValidationModel)
|
|
||||||
public trigger: TriggerModelValidationModel;
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
public env = null;
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
public stackGenerateType: StackGenerateType;
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
import { IsMongoId, IsOptional } from "class-validator";
|
|
||||||
import { IProcess, StackGenerateType } from "../../../core/models/process_model";
|
|
||||||
import { TriggerModelValidationModel } from "../../_triggers/models/trigger_validation_model";
|
|
||||||
|
|
||||||
export class PipelineValidationModel {
|
|
||||||
@IsMongoId()
|
|
||||||
public process: IProcess;
|
|
||||||
|
|
||||||
@IsMongoId()
|
|
||||||
public trigger: TriggerModelValidationModel;
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
public env = null;
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
public stackGenerateType: StackGenerateType;
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { CrudController } from "../../core/controllers/crud_controller";
|
|
||||||
import { PipelineDBModel } from "./models/pipeline_database_model";
|
|
||||||
import { PipelineValidationModel } from "./models/pipeline_validation_model";
|
|
||||||
|
|
||||||
export class PipelinePresentation extends CrudController<PipelineValidationModel, typeof PipelineDBModel> {
|
|
||||||
constructor() {
|
|
||||||
super({
|
|
||||||
url: "pipeline",
|
|
||||||
validationModel: PipelineValidationModel,
|
|
||||||
databaseModel: PipelineDBModel,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
import { Schema, model } from "mongoose";
|
|
||||||
import { IProcess } from "../../../core/models/process_model";
|
|
||||||
|
|
||||||
export const ProcessSchema = new Schema({
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
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);
|
|
|
@ -1,31 +0,0 @@
|
||||||
import { IsBoolean, IsEnum, IsNumber, IsOptional, IsString } from "class-validator";
|
|
||||||
import { EXEC_TYPE } from "../../../core/models/exec_error_model";
|
|
||||||
import { IProcess, IssueType } from "../../../core/models/process_model";
|
|
||||||
|
|
||||||
export class ProcessModel implements IProcess {
|
|
||||||
@IsEnum(EXEC_TYPE)
|
|
||||||
public type: EXEC_TYPE;
|
|
||||||
|
|
||||||
@IsString()
|
|
||||||
public description: string;
|
|
||||||
|
|
||||||
@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;
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { CrudController } from "../../core/controllers/crud_controller";
|
|
||||||
import { ProcessDBModel } from "./models/process_database_model";
|
|
||||||
import { ProcessModel } from "./models/process_validation_model";
|
|
||||||
|
|
||||||
export class ProcessPresentation extends CrudController<ProcessModel, typeof ProcessDBModel> {
|
|
||||||
constructor() {
|
|
||||||
super({
|
|
||||||
url: "process",
|
|
||||||
validationModel: ProcessModel,
|
|
||||||
databaseModel: ProcessDBModel,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
import { IsArray, IsString } from "class-validator";
|
|
||||||
|
|
||||||
export class ProjectValidationModel {
|
|
||||||
@IsArray()
|
|
||||||
public pipelines: [string];
|
|
||||||
|
|
||||||
@IsString()
|
|
||||||
public description: string;
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { CrudController } from "../../core/controllers/crud_controller";
|
|
||||||
import { ProjectDBModel } from "./models/project_database_model";
|
|
||||||
import { ProjectValidationModel } from "./models/project_validation_model";
|
|
||||||
|
|
||||||
export class ProjectsPresentation extends CrudController<ProjectValidationModel, typeof ProjectDBModel> {
|
|
||||||
constructor() {
|
|
||||||
super({
|
|
||||||
url: "project",
|
|
||||||
validationModel: ProjectValidationModel,
|
|
||||||
databaseModel: ProjectDBModel,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
import { App } from "../../../core/controllers/app";
|
|
||||||
import { CallbackStrategyWithEmpty } from "../../../core/controllers/http_controller";
|
|
||||||
import { Result } from "../../../core/helpers/result";
|
|
||||||
import { IPipeline } from "../../../core/models/process_model";
|
|
||||||
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_by_id_database_model_usecase";
|
|
||||||
import { PipelineValidationModel } from "../../_pipelines/models/pipeline_validation_model";
|
|
||||||
import { IProjectInstanceModel, ProjectInstanceDbModel } from "../../projects/models/project_instance_database_model";
|
|
||||||
import { pipelineRealTimeService } from "../realtime_presentation";
|
|
||||||
import { PipelineStatusUseCase } from "./pipeline_status_usecase";
|
|
||||||
|
|
||||||
const mongoPipelineModelMapper = (el: PipelineValidationModel): IPipeline => {
|
|
||||||
const mapObj: IPipeline = {
|
|
||||||
process: {
|
|
||||||
type: el.process.type,
|
|
||||||
command: el.process.command,
|
|
||||||
isGenerating: Boolean(el.process.isGenerating),
|
|
||||||
isLocaleCode: Boolean(el.process.isLocaleCode),
|
|
||||||
issueType: el.process.issueType,
|
|
||||||
},
|
|
||||||
trigger: {
|
|
||||||
type: el.trigger.type,
|
|
||||||
value: el.trigger.value.map((el) => String(el)),
|
|
||||||
},
|
|
||||||
env: null,
|
|
||||||
stackGenerateType: el.stackGenerateType,
|
|
||||||
};
|
|
||||||
return mapObj;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class RunInstancePipelineUseCase extends CallbackStrategyWithEmpty {
|
|
||||||
async call(): Promise<Result<any, string>> {
|
|
||||||
return (await new PipelineStatusUseCase().call()).map(async (activePipelineModel) => {
|
|
||||||
if (activePipelineModel.pipelineIsRunning) {
|
|
||||||
return Result.error("pipeline is running");
|
|
||||||
}
|
|
||||||
const readByIdDataBaseModelUseCase = await new ReadByIdDataBaseModelUseCase<IProjectInstanceModel>(
|
|
||||||
ProjectInstanceDbModel
|
|
||||||
).call(activePipelineModel.projectId);
|
|
||||||
|
|
||||||
if (readByIdDataBaseModelUseCase.isFailure()) {
|
|
||||||
return readByIdDataBaseModelUseCase.forward();
|
|
||||||
}
|
|
||||||
const projectModel = readByIdDataBaseModelUseCase.value;
|
|
||||||
const resultMapper = projectModel.project.pipelines.map((el) => mongoPipelineModelMapper(el));
|
|
||||||
|
|
||||||
pipelineRealTimeService.setPipelineDependency(
|
|
||||||
resultMapper,
|
|
||||||
App.staticFilesStoreDir() + projectModel.rootDir + "/",
|
|
||||||
projectModel._id,
|
|
||||||
projectModel.rootDir
|
|
||||||
);
|
|
||||||
|
|
||||||
pipelineRealTimeService.runPipeline();
|
|
||||||
return Result.ok("ok");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
import { IsString } from "class-validator";
|
|
||||||
import { CoreHttpController } from "../../core/controllers/http_controller";
|
|
||||||
import { PipelineRealTimeService } from "../../core/services/pipeline_real_time_service";
|
|
||||||
import { RunInstancePipelineUseCase } from "./domain/run_instance_pipeline_usecase";
|
|
||||||
import { PipelineStatusUseCase } from "./domain/pipeline_status_usecase";
|
|
||||||
|
|
||||||
export const pipelineRealTimeService = new PipelineRealTimeService();
|
|
||||||
|
|
||||||
export class RealTimeValidationModel {
|
|
||||||
@IsString()
|
|
||||||
public id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RealTimePresentation extends CoreHttpController<RealTimeValidationModel> {
|
|
||||||
constructor() {
|
|
||||||
super({
|
|
||||||
validationModel: RealTimeValidationModel,
|
|
||||||
url: "realtime",
|
|
||||||
databaseModel: null,
|
|
||||||
});
|
|
||||||
super.get(new PipelineStatusUseCase().call);
|
|
||||||
this.subRoutes.push({
|
|
||||||
method: "POST",
|
|
||||||
subUrl: "run",
|
|
||||||
fn: new RunInstancePipelineUseCase(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
import { Schema, model } from "mongoose";
|
|
||||||
|
|
||||||
export interface ITriggerModel {
|
|
||||||
_id?: string;
|
|
||||||
type: string;
|
|
||||||
description: string;
|
|
||||||
value: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TriggerSchema = new Schema({
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
require: true,
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
type: Array,
|
|
||||||
require: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const triggerSchema = "Trigger";
|
|
||||||
|
|
||||||
export const TriggerDBModel = model<ITriggerModel>(triggerSchema, TriggerSchema);
|
|
||||||
|
|
||||||
export enum TriggerType {
|
|
||||||
PROCESS = "PROCESS",
|
|
||||||
FILE = "FILE",
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Trigger {
|
|
||||||
type: TriggerType;
|
|
||||||
value: string[];
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
import { IsArray, IsOptional, IsEnum, IsString } from "class-validator";
|
|
||||||
import { ITriggerModel, TriggerType } from "./trigger_database_model";
|
|
||||||
|
|
||||||
export class TriggerModelValidationModel implements ITriggerModel {
|
|
||||||
@IsOptional()
|
|
||||||
public _id: string;
|
|
||||||
|
|
||||||
@IsString()
|
|
||||||
public description;
|
|
||||||
|
|
||||||
@IsEnum(TriggerType)
|
|
||||||
public type: TriggerType;
|
|
||||||
|
|
||||||
@IsArray()
|
|
||||||
public value: string[];
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { CrudController } from "../../core/controllers/crud_controller";
|
|
||||||
import { TriggerDBModel } from "./models/trigger_database_model";
|
|
||||||
import { TriggerModelValidationModel } from "./models/trigger_validation_model";
|
|
||||||
|
|
||||||
export class TriggerPresentation extends CrudController<TriggerModelValidationModel, typeof TriggerDBModel> {
|
|
||||||
constructor() {
|
|
||||||
super({
|
|
||||||
url: "trigger",
|
|
||||||
validationModel: TriggerModelValidationModel,
|
|
||||||
databaseModel: TriggerDBModel,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { CrudController } from "../../core/controllers/crud_controller";
|
||||||
|
import { GetBehaviorTreeSkillsTemplatesUseCase } from "./domain/get_bt_skills_templates_usecase";
|
||||||
|
import { BehaviorTreeValidationModel } from "./models/behavior_tree_validation_model";
|
||||||
|
import { BehaviorTreeDBModel } from "./models/behavior_tree_database_model";
|
||||||
|
import { ReadByIdDataBaseModelScenario } from "../../core/scenarios/read_by_id_database_model_scenario";
|
||||||
|
import { GetBehaviorTreeActiveProjectScenario } from "./domain/get_behavior_tree_active_project_scenario";
|
||||||
|
import { SaveBtScenario as FillBtScenario } from "./domain/save_bt_scenario";
|
||||||
|
import { GetCameraUseCase } from "./domain/get_cameras_usecase";
|
||||||
|
import { GetRobotsUseCase } from "./domain/get_robots_usecase";
|
||||||
|
import { GetTopicsUseCase } from "./domain/get_topics_usecase";
|
||||||
|
import { DeleteBehaviorTreeScenario } from "./domain/delete_behavior_tree_scenario";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export class BehaviorTreesPresentation extends CrudController<BehaviorTreeValidationModel, typeof BehaviorTreeDBModel> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
url: "behavior/trees",
|
||||||
|
validationModel: BehaviorTreeValidationModel,
|
||||||
|
databaseModel: BehaviorTreeDBModel,
|
||||||
|
});
|
||||||
|
super.get(new GetBehaviorTreeActiveProjectScenario().call);
|
||||||
|
this.subRoutes.push({
|
||||||
|
method: "POST",
|
||||||
|
subUrl: "fill/tree",
|
||||||
|
fn: new FillBtScenario(),
|
||||||
|
});
|
||||||
|
this.subRoutes.push({ method: "GET", subUrl: "templates", fn: new GetBehaviorTreeSkillsTemplatesUseCase() });
|
||||||
|
this.subRoutes.push({
|
||||||
|
method: "GET",
|
||||||
|
subUrl: "by_id",
|
||||||
|
fn: new ReadByIdDataBaseModelScenario<BehaviorTreeValidationModel>(BehaviorTreeDBModel),
|
||||||
|
});
|
||||||
|
this.subRoutes.push({
|
||||||
|
method: "GET",
|
||||||
|
subUrl: "cameras",
|
||||||
|
fn: new GetCameraUseCase()
|
||||||
|
})
|
||||||
|
this.subRoutes.push({
|
||||||
|
method: "GET",
|
||||||
|
subUrl: "robots",
|
||||||
|
fn: new GetRobotsUseCase()
|
||||||
|
})
|
||||||
|
this.subRoutes.push({
|
||||||
|
method: "GET",
|
||||||
|
subUrl: "topics",
|
||||||
|
fn: new GetTopicsUseCase()
|
||||||
|
})
|
||||||
|
this.subRoutes.push({
|
||||||
|
method: "POST",
|
||||||
|
subUrl: "delete/bt",
|
||||||
|
fn: new DeleteBehaviorTreeScenario(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { CallbackStrategyWithIdQuery, ResponseBase } from "../../../core/controllers/http_controller";
|
||||||
|
import { StaticFilesProject } from "../../../core/models/static_files";
|
||||||
|
import { DeleteDataBaseModelUseCase } from "../../../core/usecases/delete_database_model_usecase";
|
||||||
|
import { DeleteRecursiveFolderUseCase } from "../../../core/usecases/delete_recursive_folder_usecase";
|
||||||
|
import { SearchOneDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
|
||||||
|
import { CoreValidation } from "../../../core/validations/core_validation";
|
||||||
|
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
|
||||||
|
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
|
||||||
|
import { BehaviorTreeDBModel } from "../models/behavior_tree_database_model";
|
||||||
|
|
||||||
|
export class DeleteBehaviorTreeScenario extends CallbackStrategyWithIdQuery {
|
||||||
|
idValidationExpression: CoreValidation = new MongoIdValidation();
|
||||||
|
call = async (id: string): ResponseBase => (
|
||||||
|
await new SearchOneDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call({ isActive: true }, "no active projects")
|
||||||
|
).map(async (model) => (await (new DeleteRecursiveFolderUseCase().call(`${model.rootDir}/${StaticFilesProject.behaviorTrees}`))).map(async () => (await new DeleteDataBaseModelUseCase(BehaviorTreeDBModel).call(id))));
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
|
||||||
|
import { Result } from "../../../core/helpers/result";
|
||||||
|
import { SearchOneDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
|
||||||
|
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
|
||||||
|
import { BehaviorTreeDBModel } from "../models/behavior_tree_database_model";
|
||||||
|
|
||||||
|
export class GetBehaviorTreeActiveProjectScenario extends CallbackStrategyWithEmpty {
|
||||||
|
call = async (): ResponseBase =>
|
||||||
|
(
|
||||||
|
await new SearchOneDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call(
|
||||||
|
{ isActive: true },
|
||||||
|
"no active projects"
|
||||||
|
)
|
||||||
|
).map(async (project) => Result.ok(await BehaviorTreeDBModel.find({ project: project._id })));
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
|
||||||
|
import { Result } from "../../../core/helpers/result";
|
||||||
|
|
||||||
|
export class GetBehaviorTreeSkillsTemplatesUseCase extends CallbackStrategyWithEmpty {
|
||||||
|
call = async (): ResponseBase => {
|
||||||
|
return Result.ok({
|
||||||
|
skills: [
|
||||||
|
{
|
||||||
|
SkillPackage: { name: "Robossembler", version: "1.0", format: "1" },
|
||||||
|
Module: { name: "MoveToPose", description: "Move to Pose skill with cartesian controllers" },
|
||||||
|
Launch: { package: "rbss_movetopose", executable: "mtp_cartesian.py", name: "mtp_cartesian" },
|
||||||
|
BTAction: [
|
||||||
|
{
|
||||||
|
name: "move",
|
||||||
|
type: "action",
|
||||||
|
param: [
|
||||||
|
{
|
||||||
|
type: "move_to_pose",
|
||||||
|
dependency: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
Interface: {
|
||||||
|
Input: [
|
||||||
|
{ name: "robotName", type: "ROBOT" },
|
||||||
|
{ name: "pose", type: "POSE" },
|
||||||
|
],
|
||||||
|
Output: [],
|
||||||
|
},
|
||||||
|
Settings: [
|
||||||
|
{ name: "topicServer", value: "cartesian_move_to_pose" },
|
||||||
|
{ name: "end_effector_velocity", value: 1.0 },
|
||||||
|
{ name: "end_effector_acceleration", value: 1.0 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Module: { name: "MMM", description: "Move to Pose skill with cartesian controllers" },
|
||||||
|
topicOut: [
|
||||||
|
{
|
||||||
|
topicName: "",
|
||||||
|
topicType: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
BTAction: [
|
||||||
|
{
|
||||||
|
name: "move",
|
||||||
|
type: "action",
|
||||||
|
param: [
|
||||||
|
{
|
||||||
|
type: "move_to_pose",
|
||||||
|
dependency: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SkillPackage: { name: "Robossembler", version: "1.0", format: "1", type: "Action" },
|
||||||
|
Module: { name: "PoseEstimation", description: "Pose Estimation skill with DOPE" },
|
||||||
|
Launch: { package: "rbs_perception", executable: "pe_dope_lc.py", name: "lc_dope" },
|
||||||
|
BTAction: [
|
||||||
|
{
|
||||||
|
name: "peConfigure",
|
||||||
|
type: "run",
|
||||||
|
param: [
|
||||||
|
{
|
||||||
|
type: "weights",
|
||||||
|
dependency: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "camera",
|
||||||
|
dependency: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "topic",
|
||||||
|
dependency: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
result: ["POSE"],
|
||||||
|
},
|
||||||
|
{ name: "peStop", type: "stop", param: [], result: [] },
|
||||||
|
],
|
||||||
|
Interface: {
|
||||||
|
Input: [
|
||||||
|
{ name: "cameraLink", type: "CAMERA" },
|
||||||
|
{ name: "object_name", type: "MODEL" },
|
||||||
|
],
|
||||||
|
Output: [{ name: "pose_estimation_topic", type: "POSE" }],
|
||||||
|
},
|
||||||
|
Settings: [
|
||||||
|
{ name: "cameraLink", value: "inner_rgbd_camera" },
|
||||||
|
{ name: "pose", value: "" },
|
||||||
|
{ name: "publishDelay", value: 0.5 },
|
||||||
|
{ name: "tf2_send_pose", value: 1 },
|
||||||
|
{ name: "mesh_scale", value: 0.001 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
120
server/src/features/behavior_trees/domain/get_cameras_usecase.ts
Normal file
120
server/src/features/behavior_trees/domain/get_cameras_usecase.ts
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller"
|
||||||
|
import { Result } from "../../../core/helpers/result"
|
||||||
|
|
||||||
|
export class GetCameraUseCase extends CallbackStrategyWithEmpty {
|
||||||
|
call = async (): ResponseBase => {
|
||||||
|
return Result.ok({
|
||||||
|
"camera": [
|
||||||
|
{
|
||||||
|
"sid": "1",
|
||||||
|
"DevicePackage": {
|
||||||
|
"name": "Robossembler",
|
||||||
|
"version": "1.0",
|
||||||
|
"format": "1"
|
||||||
|
},
|
||||||
|
"Module": {
|
||||||
|
"name": "RealSense Dxx",
|
||||||
|
"description": "ROS Wrapper for Intel(R) RealSense(TM) Cameras"
|
||||||
|
},
|
||||||
|
"Launch": {
|
||||||
|
"package": "realsense2_camera",
|
||||||
|
"executable": "rs_launch.py"
|
||||||
|
},
|
||||||
|
"DTwin": [
|
||||||
|
{
|
||||||
|
"interface": {
|
||||||
|
"input": [
|
||||||
|
{
|
||||||
|
"camera_namespace": "robot1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"camera_name": "455_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"serial_port": "USB_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pose": "[0.0,0.0,0.0,0.0,0.0,0.0]"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Interface": {
|
||||||
|
"param": [
|
||||||
|
{
|
||||||
|
"type": "camera",
|
||||||
|
"dependency": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Settings": [
|
||||||
|
{
|
||||||
|
"name": "camera_config",
|
||||||
|
"description": "Camera Config",
|
||||||
|
"type": "file",
|
||||||
|
"defaultValue": "{ rgb_camera.profile: 1280x720x15 }"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sid": "2",
|
||||||
|
"DevicePackage": {
|
||||||
|
"name": "Robossembler",
|
||||||
|
"version": "1.0",
|
||||||
|
"format": "1"
|
||||||
|
},
|
||||||
|
"Module": {
|
||||||
|
"name": "RealSense Dxx",
|
||||||
|
"description": "ROS Wrapper for Intel(R) RealSense(TM) Cameras"
|
||||||
|
},
|
||||||
|
"Launch": {
|
||||||
|
"package": "realsense2_camera",
|
||||||
|
"executable": "rs_launch.py"
|
||||||
|
},
|
||||||
|
|
||||||
|
"DTwin": [
|
||||||
|
{
|
||||||
|
"interface": {
|
||||||
|
"input": [
|
||||||
|
{
|
||||||
|
"camera_namespace": "robot1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"camera_name": "455_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"serial_port": "USB_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pose": "[0.0,0.0,0.0,0.0,0.0,0.0]"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Interface": {
|
||||||
|
"param": [
|
||||||
|
{
|
||||||
|
"type": "camera",
|
||||||
|
"dependency": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Settings": [
|
||||||
|
{
|
||||||
|
"name": "camera_config",
|
||||||
|
"description": "Camera Config",
|
||||||
|
"type": "file",
|
||||||
|
"defaultValue": "{ rgb_camera.profile: 1280x720x15 }"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
|
||||||
|
import { Result } from "../../../core/helpers/result";
|
||||||
|
|
||||||
|
export class GetRobotsUseCase extends CallbackStrategyWithEmpty {
|
||||||
|
call = async (): ResponseBase => {
|
||||||
|
return Result.ok({
|
||||||
|
"robots": [
|
||||||
|
{
|
||||||
|
"sid": "1",
|
||||||
|
"DevicePackage": {
|
||||||
|
"name": "Robossembler",
|
||||||
|
"version": "1.0",
|
||||||
|
"format": "1"
|
||||||
|
},
|
||||||
|
"Module": {
|
||||||
|
"name": "RBS",
|
||||||
|
"description": "Main Robot"
|
||||||
|
},
|
||||||
|
"Launch": {
|
||||||
|
"package": "rbs_bringup",
|
||||||
|
"executable": "single_robot.launch.py"
|
||||||
|
},
|
||||||
|
"DTwin": [
|
||||||
|
{
|
||||||
|
"interface": {
|
||||||
|
"input": [
|
||||||
|
{
|
||||||
|
"robot_namespace": "robot1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dof": 6
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Settings": [
|
||||||
|
{
|
||||||
|
"name": "robot_type",
|
||||||
|
"description": "Type of robot by name",
|
||||||
|
"defaultValue": "rbs_arm"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
|
||||||
|
import { Result } from "../../../core/helpers/result";
|
||||||
|
|
||||||
|
export class GetTopicsUseCase extends CallbackStrategyWithEmpty {
|
||||||
|
call = async (): ResponseBase => {
|
||||||
|
return Result.ok({
|
||||||
|
"topics": [
|
||||||
|
{
|
||||||
|
"sid": "1",
|
||||||
|
"name": "topic camera 1",
|
||||||
|
"type": "sensor_msgs/Image"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sid": "2",
|
||||||
|
"name": "topic camera 2",
|
||||||
|
"type": "sensor_msgs/Image"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { CallbackStrategyWithValidationModel, ResponseBase } from "../../../core/controllers/http_controller";
|
||||||
|
import { CreateFileUseCase } from "../../../core/usecases/create_file_usecase";
|
||||||
|
import { CreateFolderUseCase } from "../../../core/usecases/create_folder_usecase";
|
||||||
|
import { SearchOneDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
|
||||||
|
import { FolderStructure } from "../../projects/domain/upload_file_to_to_project_scenario";
|
||||||
|
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
|
||||||
|
import { BehaviorTreeValidationModel } from "../models/behavior_tree_validation_model";
|
||||||
|
|
||||||
|
export class SaveBtScenario extends CallbackStrategyWithValidationModel<BehaviorTreeValidationModel> {
|
||||||
|
validationModel: BehaviorTreeValidationModel = new BehaviorTreeValidationModel();
|
||||||
|
call = async (model: BehaviorTreeValidationModel): ResponseBase =>
|
||||||
|
(
|
||||||
|
await new SearchOneDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call(
|
||||||
|
{ isActive: true },
|
||||||
|
"no active projects"
|
||||||
|
)
|
||||||
|
).map(async (project) => {
|
||||||
|
const folder = `${project.rootDir}/${FolderStructure.behaviorTrees}/`;
|
||||||
|
|
||||||
|
(await new CreateFolderUseCase().call(folder)).map(async () =>
|
||||||
|
(await new CreateFolderUseCase().call(`${folder}${model.name}/`)).map(async () =>
|
||||||
|
(await new CreateFileUseCase().call(`${folder}${model.name}/bt.xml`, Buffer.from(model.xml))).map(
|
||||||
|
async () =>
|
||||||
|
await new CreateFileUseCase().call(
|
||||||
|
`${folder}${model.name}/skills.json`,
|
||||||
|
Buffer.from(JSON.stringify(model.skills))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { Schema, model } from "mongoose";
|
||||||
|
import { IProjectModel, projectSchema } from "../../projects/models/project_model_database_model";
|
||||||
|
|
||||||
|
export interface IBehaviorTreeModel {
|
||||||
|
name: string;
|
||||||
|
project?: IProjectModel | string;
|
||||||
|
unixTime?: number;
|
||||||
|
local_path?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BehaviorTreeSchema = new Schema({
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
description: { type: String },
|
||||||
|
scene: {
|
||||||
|
type: Schema.Types.Mixed,
|
||||||
|
default: [],
|
||||||
|
},
|
||||||
|
local_path: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
unixTime: {
|
||||||
|
type: Number,
|
||||||
|
},
|
||||||
|
isFinished: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
dependency: {
|
||||||
|
type: Schema.Types.Mixed,
|
||||||
|
},
|
||||||
|
skills: {
|
||||||
|
type: Schema.Types.Mixed,
|
||||||
|
},
|
||||||
|
sceneId: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
project: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: projectSchema,
|
||||||
|
autopopulate: true,
|
||||||
|
require: true,
|
||||||
|
},
|
||||||
|
}).plugin(require("mongoose-autopopulate"));
|
||||||
|
|
||||||
|
export const behaviorTreeSchema = "Behavior";
|
||||||
|
|
||||||
|
export const BehaviorTreeDBModel = model<IBehaviorTreeModel>(behaviorTreeSchema, BehaviorTreeSchema);
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { IsMongoId, IsNumber, IsString } from "class-validator";
|
||||||
|
import { IBehaviorTreeModel } from "./behavior_tree_database_model";
|
||||||
|
|
||||||
|
export class BehaviorTreeValidationModel implements IBehaviorTreeModel {
|
||||||
|
_id: string;
|
||||||
|
@IsString()
|
||||||
|
public name: string;
|
||||||
|
@IsMongoId()
|
||||||
|
public project: string;
|
||||||
|
public skills: any;
|
||||||
|
public xml: string;
|
||||||
|
@IsNumber()
|
||||||
|
public unixTime: number
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { CrudController } from "../../core/controllers/crud_controller";
|
||||||
|
import { ExecCalculationInstanceProcessScenario } from "./domain/exec_calculations_instance_process_scenario";
|
||||||
|
import { CalculationInstanceValidationModel } from "./models/calculations_instance_validation_model";
|
||||||
|
import { CalculationInstanceDBModel } from "./models/calculations_instance_database_model";
|
||||||
|
import { CreateCalculationInstanceScenario } from "./domain/create_calculation_instance_scenario";
|
||||||
|
import { DeleteCalculationsInstanceScenario } from "./domain/delete_calculations_instance_scenario";
|
||||||
|
import { GetAllEndCalculationsInstanceActiveProjectScenarios } from "./domain/get_all_end_calculations_instance_active_project_scenarios";
|
||||||
|
|
||||||
|
|
||||||
|
export class CalculationsInstancesPresentation extends CrudController<
|
||||||
|
CalculationInstanceValidationModel,
|
||||||
|
typeof CalculationInstanceDBModel
|
||||||
|
> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
url: "calculations/instances",
|
||||||
|
validationModel: CalculationInstanceValidationModel,
|
||||||
|
databaseModel: CalculationInstanceDBModel,
|
||||||
|
});
|
||||||
|
|
||||||
|
super.delete(new DeleteCalculationsInstanceScenario().call);
|
||||||
|
super.post(new CreateCalculationInstanceScenario().call);
|
||||||
|
this.subRoutes.push({
|
||||||
|
method: "POST",
|
||||||
|
subUrl: "get/all/end/calculations",
|
||||||
|
//@ts-expect-error
|
||||||
|
fn: new GetAllEndCalculationsInstanceActiveProjectScenarios(),
|
||||||
|
})
|
||||||
|
this.subRoutes.push({
|
||||||
|
method: "GET",
|
||||||
|
subUrl: "exec",
|
||||||
|
fn: new ExecCalculationInstanceProcessScenario(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { CreateInstanceScenario } from "../../../core/scenarios/create_intance_scenario";
|
||||||
|
import { CalculationInstanceDBModel } from "../models/calculations_instance_database_model";
|
||||||
|
import { CalculationInstanceValidationModel } from "../models/calculations_instance_validation_model";
|
||||||
|
|
||||||
|
export class CreateCalculationInstanceScenario extends CreateInstanceScenario<CalculationInstanceValidationModel> {
|
||||||
|
databaseModel = CalculationInstanceDBModel;
|
||||||
|
validationModel: CalculationInstanceValidationModel = new CalculationInstanceValidationModel();
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { DeleteInstanceScenario } from "../../../core/scenarios/delete_instance_scenario";
|
||||||
|
import { CalculationInstanceDBModel } from "../models/calculations_instance_database_model";
|
||||||
|
import { CalculationInstanceValidationModel } from "../models/calculations_instance_validation_model";
|
||||||
|
|
||||||
|
export class DeleteCalculationsInstanceScenario extends DeleteInstanceScenario<CalculationInstanceValidationModel> {
|
||||||
|
databaseModel = CalculationInstanceDBModel;
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
import { ObjectId } from "mongoose";
|
||||||
|
import { CallbackStrategyWithIdQuery, ResponseBase } from "../../../core/controllers/http_controller";
|
||||||
|
import { ExecProcessUseCase, IsHaveActiveProcessUseCase } from "../../../core/usecases/exec_process_usecase";
|
||||||
|
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_by_id_database_model_usecase";
|
||||||
|
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
|
||||||
|
import { ProcessWatcherAndDatabaseUpdateService } from "../../datasets/domain/create_dataset_scenario";
|
||||||
|
import { CalculationInstanceDBModel, ICalculationInstance } from "../models/calculations_instance_database_model";
|
||||||
|
import { Result } from "../../../core/helpers/result";
|
||||||
|
import { CreateFileUseCase } from "../../../core/usecases/create_file_usecase";
|
||||||
|
import { ExecProcessScenarioV2, ExecProcessWatcher } from "../../../core/scenarios/exec_process_scenario_v2";
|
||||||
|
class ExecProcess extends ExecProcessWatcher {
|
||||||
|
id: string;
|
||||||
|
constructor(id: string) {
|
||||||
|
super()
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
result = async (): Promise<any> => (await new ReadByIdDataBaseModelUseCase<ICalculationInstance>(CalculationInstanceDBModel).call(this.id)).map(async (model) => {
|
||||||
|
model.lastProcessLogs = this.logs.join('\n')
|
||||||
|
model.processStatus = this.status;
|
||||||
|
// @ts-ignore
|
||||||
|
await model.save()
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
export class ExecCalculationInstanceProcessScenario extends CallbackStrategyWithIdQuery {
|
||||||
|
idValidationExpression = new MongoIdValidation();
|
||||||
|
call = async (id: string): ResponseBase =>
|
||||||
|
(await new ReadByIdDataBaseModelUseCase<ICalculationInstance>(CalculationInstanceDBModel).call(id)).map(
|
||||||
|
async (model) => {
|
||||||
|
const fileOutPath = model.instancePath.pathNormalize() + "/form.json";
|
||||||
|
return (await new IsHaveActiveProcessUseCase().call()).map(async () => {
|
||||||
|
const execCommand = `${model.script
|
||||||
|
} --path ${model.instancePath.pathNormalize()} --form ${fileOutPath}`.replace("\n", "");
|
||||||
|
|
||||||
|
await new CreateFileUseCase().call(fileOutPath, Buffer.from(JSON.stringify(model.formBuilder)));
|
||||||
|
await CalculationInstanceDBModel.findById(id).updateOne({
|
||||||
|
processStatus: "RUN",
|
||||||
|
lastProcessExecCommand: execCommand,
|
||||||
|
});
|
||||||
|
|
||||||
|
new ExecProcessScenarioV2().call(execCommand, new ExecProcess(model._id))
|
||||||
|
|
||||||
|
return Result.ok("OK");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { ResponseBase } from "../../../core/controllers/http_controller";
|
||||||
|
import { SearchManyDataBaseModelUseCase } from "../../../core/usecases/search_many_database_model_usecase";
|
||||||
|
import { GetActiveProjectIdScenario } from "../../projects/domain/get_active_project_id_scenario";
|
||||||
|
import { ICalculationInstance, CalculationInstanceDBModel } from "../models/calculations_instance_database_model";
|
||||||
|
|
||||||
|
export class GetAllWeightsActiveProjectScenarios {
|
||||||
|
call = async (): ResponseBase =>
|
||||||
|
(await new GetActiveProjectIdScenario().call()).map(
|
||||||
|
async (model) => await new SearchManyDataBaseModelUseCase<ICalculationInstance>(CalculationInstanceDBModel).call({ project: model.id })
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { IsString } from "class-validator";
|
||||||
|
import { CallbackStrategyWithValidationModel, ResponseBase } from "../../../core/controllers/http_controller";
|
||||||
|
import { SearchManyDataBaseModelUseCase } from "../../../core/usecases/search_many_database_model_usecase";
|
||||||
|
import { GetActiveProjectIdScenario } from "../../projects/domain/get_active_project_id_scenario";
|
||||||
|
import { ICalculationInstance, CalculationInstanceDBModel } from "../models/calculations_instance_database_model";
|
||||||
|
|
||||||
|
|
||||||
|
export class CalculationInstanceType {
|
||||||
|
@IsString()
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GetAllEndCalculationsInstanceActiveProjectScenarios extends CallbackStrategyWithValidationModel<CalculationInstanceType> {
|
||||||
|
validationModel: CalculationInstanceType = new CalculationInstanceType();
|
||||||
|
call = async (model: CalculationInstanceType): ResponseBase => (await new GetActiveProjectIdScenario().call()).map(
|
||||||
|
async (activeProjectModel) => await new SearchManyDataBaseModelUseCase<ICalculationInstance>(CalculationInstanceDBModel).call({ project: activeProjectModel.id, isEnd: true, type: model.type }),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { CallbackStrategyWithIdQuery, ResponseBase } from "../../../core/controllers/http_controller";
|
||||||
|
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_database_model_usecase";
|
||||||
|
import { CoreValidation } from "../../../core/validations/core_validation";
|
||||||
|
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
|
||||||
|
import { ICalculationInstance, CalculationInstanceDBModel } from "../models/calculations_instance_database_model";
|
||||||
|
|
||||||
|
// export class LogToProcessUseCase extends CallbackStrategyWithIdQuery {
|
||||||
|
// idValidationExpression: CoreValidation = new MongoIdValidation();
|
||||||
|
// call = async (id: string): ResponseBase => (await new ReadByIdDataBaseModelUseCase<ICalculationInstance>(CalculationInstanceDBModel).call(id)).map((model) => );
|
||||||
|
|
||||||
|
// }
|
|
@ -0,0 +1,79 @@
|
||||||
|
import { Schema, model } from "mongoose";
|
||||||
|
import { FormBuilderValidationModel } from "../../datasets/models/dataset_validation_model";
|
||||||
|
import { IProjectModel, projectSchema } from "../../projects/models/project_model_database_model";
|
||||||
|
|
||||||
|
export interface ICalculationInstance {
|
||||||
|
_id: string;
|
||||||
|
script: string;
|
||||||
|
instancePath: string;
|
||||||
|
formBuilder: FormBuilderValidationModel;
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
isEnd: boolean;
|
||||||
|
createDate: Date;
|
||||||
|
card?: string;
|
||||||
|
lastProcessLogs?: string;
|
||||||
|
lastProcessExecCommand?: string;
|
||||||
|
lastExecDate?: Date;
|
||||||
|
processStatus: string;
|
||||||
|
project?: IProjectModel | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CalculationInstanceSchema = new Schema({
|
||||||
|
script: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
formBuilder: {
|
||||||
|
type: Schema.Types.Mixed,
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
instanceName: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
isEnd: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
createDate: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
card: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
lastProcessLogs: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
lastProcessExecCommand: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
lastExecDate: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
processStatus: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
path: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
instancePath: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
project: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: projectSchema,
|
||||||
|
autopopulate: true,
|
||||||
|
require: true,
|
||||||
|
},
|
||||||
|
}).plugin(require("mongoose-autopopulate"));
|
||||||
|
|
||||||
|
export const calculationInstanceSchema = "calculations_instances";
|
||||||
|
|
||||||
|
export const CalculationInstanceDBModel = model<ICalculationInstance>(
|
||||||
|
calculationInstanceSchema,
|
||||||
|
CalculationInstanceSchema
|
||||||
|
);
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { IsNotEmpty, IsString, IsMongoId } from "class-validator";
|
||||||
|
import { ICalculationInstance } from "./calculations_instance_database_model";
|
||||||
|
import { FormBuilderValidationModel } from "../../datasets/models/dataset_validation_model";
|
||||||
|
import { IProjectModel } from "../../projects/models/project_model_database_model";
|
||||||
|
|
||||||
|
export class CalculationInstanceValidationModel implements ICalculationInstance {
|
||||||
|
_id: string;
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
instanceName: string;
|
||||||
|
instancePath: string;
|
||||||
|
processStatus: string;
|
||||||
|
@IsString()
|
||||||
|
path: string;
|
||||||
|
project?: string | IProjectModel;
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
script: string;
|
||||||
|
formBuilder: FormBuilderValidationModel;
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
type: string;
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
name: string;
|
||||||
|
isEnd: boolean = false;
|
||||||
|
createDate: Date = new Date();
|
||||||
|
card?: string;
|
||||||
|
lastProcessLogs?: string;
|
||||||
|
lastProcessExecCommand?: string;
|
||||||
|
lastExecDate?: Date;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { CrudController } from "../../core/controllers/crud_controller";
|
||||||
|
import { DeleteCalculationsTemplateScenario } from "./domain/delete_calculations_template_scenario";
|
||||||
|
import { CalculationsTemplateValidationModel as CalculationsTemplateValidationModel } from "./models/calculations_template_validation_model";
|
||||||
|
import { CalculationsTemplateDBModel } from "./models/calculations_template_database_model";
|
||||||
|
import { CreateCalculationsTemplateScenario } from "./domain/create_calculations_template_scenario";
|
||||||
|
|
||||||
|
export class CalculationsTemplatePresentation extends CrudController<
|
||||||
|
CalculationsTemplateValidationModel,
|
||||||
|
typeof CalculationsTemplateDBModel
|
||||||
|
> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
url: "calculations/template",
|
||||||
|
validationModel: CalculationsTemplateValidationModel,
|
||||||
|
databaseModel: CalculationsTemplateDBModel,
|
||||||
|
});
|
||||||
|
super.post(new CreateCalculationsTemplateScenario().call);
|
||||||
|
super.delete(new DeleteCalculationsTemplateScenario().call);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { StaticFilesServer } from "../../../core/models/static_files";
|
||||||
|
import { CreateTemplateScenario } from "../../../core/scenarios/create_template_scenario";
|
||||||
|
import { CalculationsTemplateDBModel } from "../models/calculations_template_database_model";
|
||||||
|
import { CalculationsTemplateValidationModel } from "../models/calculations_template_validation_model";
|
||||||
|
|
||||||
|
export class CreateCalculationsTemplateScenario extends CreateTemplateScenario<CalculationsTemplateValidationModel> {
|
||||||
|
validationModel: CalculationsTemplateValidationModel = new CalculationsTemplateValidationModel();
|
||||||
|
databaseModel = CalculationsTemplateDBModel;
|
||||||
|
path: string = StaticFilesServer.process;
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { DeleteTemplateScenario } from "../../../core/scenarios/delete_template_scenario";
|
||||||
|
import { CalculationsTemplateDBModel } from "../models/calculations_template_database_model";
|
||||||
|
|
||||||
|
export class DeleteCalculationsTemplateScenario extends DeleteTemplateScenario {
|
||||||
|
databaseModel = CalculationsTemplateDBModel;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { ResponseBase } from "../../../core/controllers/http_controller";
|
||||||
|
import { SearchManyDataBaseModelUseCase } from "../../../core/usecases/search_many_database_model_usecase";
|
||||||
|
import { GetActiveProjectIdScenario } from "../../projects/domain/get_active_project_id_scenario";
|
||||||
|
import { ICalculationsTemplateModel, CalculationsTemplateDBModel } from "../models/calculations_template_database_model";
|
||||||
|
|
||||||
|
export class GetAllCalculationsTemplateScenarios {
|
||||||
|
call = async (): ResponseBase =>
|
||||||
|
(await new GetActiveProjectIdScenario().call()).map(
|
||||||
|
async (model) => await new SearchManyDataBaseModelUseCase<ICalculationsTemplateModel>(CalculationsTemplateDBModel).call({ project: model.id })
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { Schema, model } from "mongoose";
|
||||||
|
import { FormBuilderValidationModel, IDatasetModel } from "../../datasets/models/dataset_validation_model";
|
||||||
|
import { IProjectModel, projectSchema } from "../../projects/models/project_model_database_model";
|
||||||
|
|
||||||
|
export interface ICalculationsTemplateModel {
|
||||||
|
path?: string;
|
||||||
|
script: string;
|
||||||
|
formBuilder: FormBuilderValidationModel;
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
isEnd: boolean;
|
||||||
|
createDate: Date;
|
||||||
|
card?: string;
|
||||||
|
lastProcessLogs?: string;
|
||||||
|
lastProcessExecCommand?: string;
|
||||||
|
lastExecDate?: Date;
|
||||||
|
processStatus: string;
|
||||||
|
project?: IProjectModel | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CalculationsTemplateSchema = new Schema({
|
||||||
|
script: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
formBuilder: {
|
||||||
|
type: Schema.Types.Mixed,
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
createDate: {
|
||||||
|
type: Number,
|
||||||
|
},
|
||||||
|
card: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
project: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: projectSchema,
|
||||||
|
autopopulate: true,
|
||||||
|
require: true,
|
||||||
|
},
|
||||||
|
path: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
}).plugin(require("mongoose-autopopulate"));
|
||||||
|
|
||||||
|
export const calculationsTemplateSchema = "calculations_templates";
|
||||||
|
|
||||||
|
export const CalculationsTemplateDBModel = model<ICalculationsTemplateModel>(calculationsTemplateSchema, CalculationsTemplateSchema);
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { IsNotEmpty, IsString, IsMongoId } from "class-validator";
|
||||||
|
import { ICalculationsTemplateModel } from "./calculations_template_database_model";
|
||||||
|
import { FormBuilderValidationModel } from "../../datasets/models/dataset_validation_model";
|
||||||
|
import { IProjectModel } from "../../projects/models/project_model_database_model";
|
||||||
|
|
||||||
|
export class CalculationsTemplateValidationModel implements ICalculationsTemplateModel {
|
||||||
|
processStatus: string;
|
||||||
|
@IsMongoId()
|
||||||
|
project?: string | IProjectModel;
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
script: string;
|
||||||
|
formBuilder: FormBuilderValidationModel;
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
type: string;
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
name: string;
|
||||||
|
isEnd: boolean = true;
|
||||||
|
createDate: Date = new Date();
|
||||||
|
card?: string;
|
||||||
|
lastProcessLogs?: string;
|
||||||
|
lastProcessExecCommand?: string;
|
||||||
|
lastExecDate?: Date;
|
||||||
|
path: string;
|
||||||
|
}
|
|
@ -4,16 +4,20 @@ import { Result } from "../../../core/helpers/result";
|
||||||
import { TypedEvent } from "../../../core/helpers/typed_event";
|
import { TypedEvent } from "../../../core/helpers/typed_event";
|
||||||
import { EXEC_EVENT, ExecError, SpawnError } from "../../../core/models/exec_error_model";
|
import { EXEC_EVENT, ExecError, SpawnError } from "../../../core/models/exec_error_model";
|
||||||
import { ExecutorResult } from "../../../core/models/executor_result";
|
import { ExecutorResult } from "../../../core/models/executor_result";
|
||||||
import { SearchDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
|
import { SearchOneDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
|
||||||
import { IProjectModel, ProjectDBModel } from "../../_projects/models/project_database_model";
|
|
||||||
import { DatasetDBModel } from "../models/dataset_database_model";
|
import { DatasetDBModel } from "../models/dataset_database_model";
|
||||||
import { DatasetValidationModel, ProcessStatus } from "../models/dataset_validation_model";
|
import { DatasetValidationModel, ProcessStatus } from "../models/dataset_validation_model";
|
||||||
|
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
|
||||||
|
|
||||||
export class ProcessWatcherAndDatabaseUpdateService extends TypedEvent<Result<ExecError | SpawnError, ExecutorResult>> {
|
export class ProcessWatcherAndDatabaseUpdateService<A> extends TypedEvent<
|
||||||
|
Result<ExecError | SpawnError, ExecutorResult>
|
||||||
|
> {
|
||||||
databaseId: ObjectId;
|
databaseId: ObjectId;
|
||||||
constructor(databaseId: ObjectId) {
|
model: A;
|
||||||
|
constructor(databaseId: ObjectId, model: A) {
|
||||||
super();
|
super();
|
||||||
this.databaseId = databaseId;
|
this.databaseId = databaseId;
|
||||||
|
this.model = model;
|
||||||
this.on((event) => this.lister(event));
|
this.on((event) => this.lister(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,20 +25,22 @@ export class ProcessWatcherAndDatabaseUpdateService extends TypedEvent<Result<Ex
|
||||||
event.fold(
|
event.fold(
|
||||||
async (success) => {
|
async (success) => {
|
||||||
if (success.event == EXEC_EVENT.END) {
|
if (success.event == EXEC_EVENT.END) {
|
||||||
const dbModel = await DatasetDBModel.findById(this.databaseId);
|
// @ts-expect-error
|
||||||
|
const dbModel = await this.model.findById(this.databaseId);
|
||||||
if (dbModel !== null) {
|
if (dbModel !== null) {
|
||||||
dbModel.local_path;
|
dbModel.local_path;
|
||||||
dbModel.processStatus = ProcessStatus.END;
|
dbModel.processStatus = ProcessStatus.END;
|
||||||
dbModel.processLogs = success.data;
|
dbModel.lastProcessLogs = success.data;
|
||||||
await dbModel.save();
|
await dbModel.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async (error) => {
|
async (error) => {
|
||||||
const dbModel = await DatasetDBModel.findById(this.databaseId);
|
// @ts-expect-error
|
||||||
|
const dbModel = await this.model.findById(this.databaseId);
|
||||||
if (dbModel !== null) {
|
if (dbModel !== null) {
|
||||||
dbModel.processStatus = ProcessStatus.ERROR;
|
dbModel.processStatus = ProcessStatus.ERROR;
|
||||||
dbModel.processLogs = error.message;
|
dbModel.lastProcessLogs = error.message;
|
||||||
await dbModel.save();
|
await dbModel.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +51,7 @@ export class CreateDataSetScenario extends CallbackStrategyWithValidationModel<D
|
||||||
validationModel: DatasetValidationModel;
|
validationModel: DatasetValidationModel;
|
||||||
call = async (model: DatasetValidationModel): ResponseBase => {
|
call = async (model: DatasetValidationModel): ResponseBase => {
|
||||||
return (
|
return (
|
||||||
await new SearchDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call({ isActive: true }, "no active projects")
|
await new SearchOneDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call({ isActive: true }, "no active projects")
|
||||||
).map(async (project) => {
|
).map(async (project) => {
|
||||||
model.processStatus = ProcessStatus.NEW;
|
model.processStatus = ProcessStatus.NEW;
|
||||||
model.local_path = project.rootDir;
|
model.local_path = project.rootDir;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { MongoIdValidation } from "../../../core/validations/mongo_id_validation
|
||||||
import { DatasetDBModel } from "../models/dataset_database_model";
|
import { DatasetDBModel } from "../models/dataset_database_model";
|
||||||
import { IDatasetModel } from "../models/dataset_validation_model";
|
import { IDatasetModel } from "../models/dataset_validation_model";
|
||||||
import { ProcessWatcherAndDatabaseUpdateService } from "./create_dataset_scenario";
|
import { ProcessWatcherAndDatabaseUpdateService } from "./create_dataset_scenario";
|
||||||
|
import { FolderStructure } from "../../projects/domain/upload_file_to_to_project_scenario";
|
||||||
|
|
||||||
export class ExecDatasetProcessScenario extends CallbackStrategyWithIdQuery {
|
export class ExecDatasetProcessScenario extends CallbackStrategyWithIdQuery {
|
||||||
idValidationExpression = new MongoIdValidation();
|
idValidationExpression = new MongoIdValidation();
|
||||||
|
@ -14,12 +15,13 @@ export class ExecDatasetProcessScenario extends CallbackStrategyWithIdQuery {
|
||||||
return (await new ReadByIdDataBaseModelUseCase<IDatasetModel>(DatasetDBModel).call(id)).map(async (model) => {
|
return (await new ReadByIdDataBaseModelUseCase<IDatasetModel>(DatasetDBModel).call(id)).map(async (model) => {
|
||||||
return (await new IsHaveActiveProcessUseCase().call()).map(async () => {
|
return (await new IsHaveActiveProcessUseCase().call()).map(async () => {
|
||||||
await DatasetDBModel.findById(id).updateOne({ processStatus: "RUN" });
|
await DatasetDBModel.findById(id).updateOne({ processStatus: "RUN" });
|
||||||
console.log(`blenderproc run $PYTHON_BLENDER_PROC --cfg '${JSON.stringify(model)}'`);
|
model.local_path = `${model.local_path}/${FolderStructure.datasets}/`;
|
||||||
|
|
||||||
return new ExecProcessUseCase().call(
|
return new ExecProcessUseCase().call(
|
||||||
`${model.project.rootDir}/`,
|
`${model.project.rootDir}/`,
|
||||||
`blenderproc run $PYTHON_BLENDER_PROC --cfg '${JSON.stringify(model)}'`,
|
`blenderproc run $PYTHON_BLENDER_PROC --cfg '${JSON.stringify(model)}'`,
|
||||||
id,
|
id,
|
||||||
new ProcessWatcherAndDatabaseUpdateService(id as unknown as ObjectId)
|
new ProcessWatcherAndDatabaseUpdateService(id as unknown as ObjectId, DatasetDBModel)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
|
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
|
||||||
import { Result } from "../../../core/helpers/result";
|
import { Result } from "../../../core/helpers/result";
|
||||||
import { SearchDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
|
import { SearchOneDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
|
||||||
import { IProjectModel, ProjectDBModel } from "../../_projects/models/project_database_model";
|
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
|
||||||
import { DatasetDBModel } from "../models/dataset_database_model";
|
import { DatasetDBModel } from "../models/dataset_database_model";
|
||||||
|
|
||||||
export class GetDatasetActiveProjectScenario extends CallbackStrategyWithEmpty {
|
export class GetDatasetActiveProjectScenario extends CallbackStrategyWithEmpty {
|
||||||
call = async (): ResponseBase => {
|
call = async (): ResponseBase => {
|
||||||
return (
|
return (
|
||||||
await new SearchDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call({ isActive: true }, "no active projects")
|
await new SearchOneDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call({ isActive: true }, "no active projects")
|
||||||
).map(async (project) => {
|
).map(async (project) => {
|
||||||
return Result.ok(await DatasetDBModel.find({ project: project._id }));
|
return Result.ok(await DatasetDBModel.find({ project: project._id }));
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Mongoose, Schema, model } from "mongoose";
|
import { Schema, model } from "mongoose";
|
||||||
import { IDatasetModel } from "./dataset_validation_model";
|
import { IDatasetModel } from "./dataset_validation_model";
|
||||||
import { projectSchema } from "../../_projects/models/project_database_model";
|
import { projectSchema } from "../../projects/models/project_model_database_model";
|
||||||
|
|
||||||
export const DatasetSchema = new Schema({
|
export const DatasetSchema = new Schema({
|
||||||
name: {
|
name: {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Type } from "class-transformer";
|
import { Type } from "class-transformer";
|
||||||
import { IsArray, IsOptional, IsString, ValidateNested } from "class-validator";
|
import { IsArray, IsOptional, IsString, ValidateNested } from "class-validator";
|
||||||
import { IProjectModel } from "../../_projects/models/project_database_model";
|
import { IProjectModel } from "../../projects/models/project_model_database_model";
|
||||||
|
|
||||||
export class FormBuilderValidationModel {
|
export class FormBuilderValidationModel {
|
||||||
@IsString()
|
@IsString()
|
||||||
|
@ -9,14 +9,16 @@ export class FormBuilderValidationModel {
|
||||||
public context: string;
|
public context: string;
|
||||||
@IsArray()
|
@IsArray()
|
||||||
public form: [];
|
public form: [];
|
||||||
|
output: any;
|
||||||
}
|
}
|
||||||
export enum ProcessStatus {
|
export enum ProcessStatus {
|
||||||
END = "END",
|
END = "END",
|
||||||
ERROR = "ERROR",
|
ERROR = "ERROR",
|
||||||
NEW = "NEW",
|
NEW = "NEW",
|
||||||
|
|
||||||
}
|
}
|
||||||
export interface IDatasetModel {
|
export interface IDatasetModel {
|
||||||
_id?:string;
|
_id?: string;
|
||||||
name: string;
|
name: string;
|
||||||
local_path: string;
|
local_path: string;
|
||||||
dataSetObjects: string[];
|
dataSetObjects: string[];
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { CrudController } from "../../core/controllers/crud_controller";
|
||||||
|
import { CreateDigitalTwinsInstanceScenario } from "./domain/create_digital_twins_instance";
|
||||||
|
import { DeleteDigitalTwinsInstanceScenario } from "./domain/delete_digital_twins_instance";
|
||||||
|
import { ExecInstanceScenario } from "./domain/exec_instance_scenario";
|
||||||
|
import { DigitalTwinsInstanceDatabaseModel } from "./model/digital_twins_instance_database_model";
|
||||||
|
import { DigitalTwinsInstanceValidationModel } from "./model/digital_twins_instance_validation_model";
|
||||||
|
|
||||||
|
export class DigitalTwinsInstancePresentation extends CrudController<
|
||||||
|
DigitalTwinsInstanceValidationModel,
|
||||||
|
typeof DigitalTwinsInstanceDatabaseModel
|
||||||
|
> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
url: "digital/twins/instance",
|
||||||
|
validationModel: DigitalTwinsInstanceValidationModel,
|
||||||
|
databaseModel: DigitalTwinsInstanceDatabaseModel,
|
||||||
|
});
|
||||||
|
super.post(new CreateDigitalTwinsInstanceScenario().call);
|
||||||
|
super.delete(new DeleteDigitalTwinsInstanceScenario().call);
|
||||||
|
this.subRoutes.push({
|
||||||
|
method: "POST",
|
||||||
|
fn: new ExecInstanceScenario(),
|
||||||
|
subUrl: "exec/instance",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { CreateInstanceScenario } from "../../../core/scenarios/create_intance_scenario";
|
||||||
|
import { DigitalTwinsInstanceDatabaseModel } from "../model/digital_twins_instance_database_model";
|
||||||
|
import { DigitalTwinsInstanceValidationModel } from "../model/digital_twins_instance_validation_model";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export class CreateDigitalTwinsInstanceScenario extends CreateInstanceScenario<DigitalTwinsInstanceValidationModel> {
|
||||||
|
databaseModel = DigitalTwinsInstanceDatabaseModel;
|
||||||
|
validationModel: DigitalTwinsInstanceValidationModel = new DigitalTwinsInstanceValidationModel();
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { DeleteInstanceScenario } from "../../../core/scenarios/delete_instance_scenario";
|
||||||
|
import { DigitalTwinsInstanceDatabaseModel } from "../model/digital_twins_instance_database_model";
|
||||||
|
import { DigitalTwinsInstanceValidationModel } from "../model/digital_twins_instance_validation_model";
|
||||||
|
|
||||||
|
export class DeleteDigitalTwinsInstanceScenario extends DeleteInstanceScenario<DigitalTwinsInstanceValidationModel> {
|
||||||
|
databaseModel = DigitalTwinsInstanceDatabaseModel;
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { CallbackStrategyWithIdQuery, ResponseBase } from "../../../core/controllers/http_controller";
|
||||||
|
import { ExecProcessUseCase } from "../../../core/usecases/exec_process_usecase";
|
||||||
|
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_by_id_database_model_usecase";
|
||||||
|
import { CoreValidation } from "../../../core/validations/core_validation";
|
||||||
|
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
|
||||||
|
import {
|
||||||
|
DigitalTwinsInstanceDatabaseModel,
|
||||||
|
IDigitalTwinsInstanceModel,
|
||||||
|
} from "../model/digital_twins_instance_database_model";
|
||||||
|
import { ITopicModel } from "../../topics/topic_database_model";
|
||||||
|
import { ExecInstanceTwinsProcessService } from "../services/exec_instance_twins_process_service";
|
||||||
|
|
||||||
|
export interface Topics {
|
||||||
|
topics: ITopicModel[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ExecInstanceScenario extends CallbackStrategyWithIdQuery {
|
||||||
|
idValidationExpression: CoreValidation = new MongoIdValidation();
|
||||||
|
call = async (id: string): ResponseBase =>
|
||||||
|
(
|
||||||
|
await new ReadByIdDataBaseModelUseCase<IDigitalTwinsInstanceModel>(DigitalTwinsInstanceDatabaseModel).call(id)
|
||||||
|
).map(
|
||||||
|
(document) => (
|
||||||
|
|
||||||
|
new ExecProcessUseCase().call(
|
||||||
|
document.instancePath,
|
||||||
|
`python3 $GET_INTERFACES --path ${document.instancePath.pathNormalize()} --package '${JSON.stringify(
|
||||||
|
document
|
||||||
|
)}'`,
|
||||||
|
"",
|
||||||
|
new ExecInstanceTwinsProcessService(document.instancePath, document)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { Schema, model } from "mongoose";
|
||||||
|
|
||||||
|
export interface IDigitalTwinsInstanceModel {
|
||||||
|
instancePath: string;
|
||||||
|
status?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DigitalTwinsInstanceSchema = new Schema({
|
||||||
|
path: String,
|
||||||
|
name: String,
|
||||||
|
entity: String,
|
||||||
|
description: String,
|
||||||
|
command: String,
|
||||||
|
status: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
interfaces: {
|
||||||
|
cmd: String,
|
||||||
|
},
|
||||||
|
instancePath: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
package: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
executable: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
formBuilder: {
|
||||||
|
type: Schema.Types.Mixed,
|
||||||
|
},
|
||||||
|
}).plugin(require("mongoose-autopopulate"));
|
||||||
|
|
||||||
|
export const digitalTwinsInstanceSchema = "digital_twins_instance";
|
||||||
|
|
||||||
|
export const DigitalTwinsInstanceDatabaseModel = model<IDigitalTwinsInstanceModel>(
|
||||||
|
digitalTwinsInstanceSchema,
|
||||||
|
DigitalTwinsInstanceSchema
|
||||||
|
);
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { Type } from "class-transformer";
|
||||||
|
import { IsEnum, IsString } from "class-validator";
|
||||||
|
import { Instance } from "../../../core/models/instance";
|
||||||
|
|
||||||
|
enum DigitalTwinsTypes {
|
||||||
|
CAMERA = "CAMERA",
|
||||||
|
ROBOT = "ROBOT",
|
||||||
|
}
|
||||||
|
export class Interfaces {
|
||||||
|
@IsString()
|
||||||
|
cmd: string;
|
||||||
|
}
|
||||||
|
export class DigitalTwinsInstanceValidationModel implements Instance {
|
||||||
|
instanceName: string;
|
||||||
|
instancePath: string;
|
||||||
|
path: string;
|
||||||
|
name: string;
|
||||||
|
@IsEnum(DigitalTwinsTypes)
|
||||||
|
entity: DigitalTwinsTypes;
|
||||||
|
@IsString()
|
||||||
|
description: string;
|
||||||
|
@IsString()
|
||||||
|
command: string;
|
||||||
|
@Type(() => Interfaces)
|
||||||
|
interfaces: Interfaces;
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { Result } from "../../../core/helpers/result";
|
||||||
|
import { TypedEvent } from "../../../core/helpers/typed_event";
|
||||||
|
import { ExecError, SpawnError, EXEC_EVENT } from "../../../core/models/exec_error_model";
|
||||||
|
import { ExecutorResult } from "../../../core/models/executor_result";
|
||||||
|
import { CreateDataBaseModelUseCase } from "../../../core/usecases/create_database_model_usecase";
|
||||||
|
import { ReadFileAndParseJsonUseCase } from "../../../core/usecases/read_file_and_parse_json";
|
||||||
|
import { ITopicModel, TopicDatabaseModel } from "../../topics/topic_database_model";
|
||||||
|
import { Topics } from "../domain/exec_instance_scenario";
|
||||||
|
|
||||||
|
export class ExecInstanceTwinsProcessService extends TypedEvent<
|
||||||
|
Result<ExecError | SpawnError, ExecutorResult>
|
||||||
|
> {
|
||||||
|
path: string;
|
||||||
|
databaseModel: any;
|
||||||
|
constructor(path: string, databaseModel: any) {
|
||||||
|
super();
|
||||||
|
this.path = path;
|
||||||
|
this.databaseModel = databaseModel;
|
||||||
|
this.on((event) => this.lister(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
lister = (event: Result<ExecError | SpawnError, ExecutorResult>) =>
|
||||||
|
event.fold(
|
||||||
|
async (success) => {
|
||||||
|
if (success.event == EXEC_EVENT.END) {
|
||||||
|
(await new ReadFileAndParseJsonUseCase().call<Topics>(this.path + "/topics.json")).fold(
|
||||||
|
async (model) => {
|
||||||
|
await model.topics.forEach(async (el) => {
|
||||||
|
el.digitalTwinId = this.databaseModel._id;
|
||||||
|
await new CreateDataBaseModelUseCase<ITopicModel>(TopicDatabaseModel).call(el);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.databaseModel.status = "END";
|
||||||
|
await this.databaseModel.save();
|
||||||
|
},
|
||||||
|
|
||||||
|
async (_) => {
|
||||||
|
this.databaseModel.status = "ERROR";
|
||||||
|
await this.databaseModel.save();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async (_) => {
|
||||||
|
this.databaseModel.status = "ERROR";
|
||||||
|
await this.databaseModel.save();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { CrudController } from "../../core/controllers/crud_controller";
|
||||||
|
import { CreateDigitalTwinsTemplateScenario } from "./domain/create_digital_twins_template";
|
||||||
|
import { DeleteDigitalTwinsTemplateScenario } from "./domain/delete_digital_twins_template";
|
||||||
|
import { DigitalTwinsTemplateDBModel } from "./models/digital_twins_template_database_model";
|
||||||
|
import { DigitalTwinsTemplateValidationModel } from "./models/digital_twins_template_validation_model";
|
||||||
|
|
||||||
|
export class DigitalTwinsTemplatePresentation extends CrudController<
|
||||||
|
DigitalTwinsTemplateValidationModel,
|
||||||
|
typeof DigitalTwinsTemplateDBModel
|
||||||
|
> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
url: "digital/twins/template",
|
||||||
|
validationModel: DigitalTwinsTemplateValidationModel,
|
||||||
|
databaseModel: DigitalTwinsTemplateDBModel,
|
||||||
|
});
|
||||||
|
super.post(new CreateDigitalTwinsTemplateScenario().call);
|
||||||
|
super.delete(new DeleteDigitalTwinsTemplateScenario().call);
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue