update signal logic :: simulator init & correct parsing
This commit is contained in:
parent
1116ccfb36
commit
d3bcb58a35
12
DOCS.md
12
DOCS.md
@ -4,4 +4,14 @@ SOCKET MESSAGING:
|
|||||||
// PORT CHANGE IN .env
|
// PORT CHANGE IN .env
|
||||||
localhost:9091/storeEvent?client_id=1&message={"me": "update"}
|
localhost:9091/storeEvent?client_id=1&message={"me": "update"}
|
||||||
// CONNECTION:
|
// CONNECTION:
|
||||||
ws://localhost:9091/ws/1
|
ws://localhost:9091/ws/1
|
||||||
|
|
||||||
|
DATABASE LOGS TYPE:
|
||||||
|
1 - INFO
|
||||||
|
2 - WARNING
|
||||||
|
3 - ERROR
|
||||||
|
4 - ADMIN_ACTION
|
||||||
|
5 - USER_ACTION
|
||||||
|
...
|
||||||
|
10 - RESERV
|
||||||
|
|
||||||
|
16
Makefile
16
Makefile
@ -3,29 +3,29 @@
|
|||||||
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
docker compose build
|
docker-compose build
|
||||||
|
|
||||||
dev: build
|
dev: build
|
||||||
docker compose up -d --force-recreate
|
docker-compose up -d --force-recreate
|
||||||
|
|
||||||
devf: dev
|
devf: dev
|
||||||
docker compose logs -f
|
docker-compose logs -f
|
||||||
|
|
||||||
up:
|
up:
|
||||||
docker compose up -d --force-recreate
|
docker-compose up -d --force-recreate
|
||||||
|
|
||||||
upf: up
|
upf: up
|
||||||
docker compose logs -f
|
docker-compose logs -f
|
||||||
|
|
||||||
logs:
|
logs:
|
||||||
docker compose logs -f
|
docker-compose logs -f
|
||||||
|
|
||||||
|
|
||||||
stop:
|
stop:
|
||||||
echo "!!!!!!!!!!!!!!!!!EXTERMINATUS!!!!!!!!!!!!!!!!!"
|
echo "!!!!!!!!!!!!!!!!!EXTERMINATUS!!!!!!!!!!!!!!!!!"
|
||||||
docker compose stop
|
docker-compose stop
|
||||||
start:
|
start:
|
||||||
docker compose start
|
docker-compose start
|
||||||
|
|
||||||
drop:
|
drop:
|
||||||
docker-compose down --volumes
|
docker-compose down --volumes
|
4
ToDO.md.save
Normal file
4
ToDO.md.save
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
|
||||||
|
!1 => Написать хук для воспроизведения симуляции
|
||||||
|
!2 =>
|
316
src/frontend/package-lock.json
generated
316
src/frontend/package-lock.json
generated
@ -8,6 +8,7 @@
|
|||||||
"name": "dsn-application",
|
"name": "dsn-application",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@mui/material": "^6.1.3",
|
||||||
"@testing-library/jest-dom": "^5.17.0",
|
"@testing-library/jest-dom": "^5.17.0",
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
@ -2445,6 +2446,60 @@
|
|||||||
"postcss-selector-parser": "^6.0.10"
|
"postcss-selector-parser": "^6.0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@emotion/cache": {
|
||||||
|
"version": "11.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz",
|
||||||
|
"integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/memoize": "^0.9.0",
|
||||||
|
"@emotion/sheet": "^1.4.0",
|
||||||
|
"@emotion/utils": "^1.4.0",
|
||||||
|
"@emotion/weak-memoize": "^0.4.0",
|
||||||
|
"stylis": "4.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/hash": {
|
||||||
|
"version": "0.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
|
||||||
|
"integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g=="
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/memoize": {
|
||||||
|
"version": "0.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
|
||||||
|
"integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ=="
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/serialize": {
|
||||||
|
"version": "1.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz",
|
||||||
|
"integrity": "sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/hash": "^0.9.2",
|
||||||
|
"@emotion/memoize": "^0.9.0",
|
||||||
|
"@emotion/unitless": "^0.10.0",
|
||||||
|
"@emotion/utils": "^1.4.1",
|
||||||
|
"csstype": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/sheet": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg=="
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/unitless": {
|
||||||
|
"version": "0.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
|
||||||
|
"integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg=="
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/utils": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA=="
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/weak-memoize": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg=="
|
||||||
|
},
|
||||||
"node_modules/@eslint-community/eslint-utils": {
|
"node_modules/@eslint-community/eslint-utils": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
|
||||||
@ -3425,6 +3480,213 @@
|
|||||||
"integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==",
|
"integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@mui/core-downloads-tracker": {
|
||||||
|
"version": "6.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.3.tgz",
|
||||||
|
"integrity": "sha512-ajMUgdfhTb++rwqj134Cq9f4SRN8oXUqMRnY72YBnXiXai3olJLLqETheRlq3MM8wCKrbq7g6j7iWL1VvP44VQ==",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mui-org"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mui/material": {
|
||||||
|
"version": "6.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.3.tgz",
|
||||||
|
"integrity": "sha512-loV5MBoMKLrK80JeWINmQ1A4eWoLv51O2dBPLJ260IAhupkB3Wol8lEQTEvvR2vO3o6xRHuXe1WaQEP6N3riqg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.25.6",
|
||||||
|
"@mui/core-downloads-tracker": "^6.1.3",
|
||||||
|
"@mui/system": "^6.1.3",
|
||||||
|
"@mui/types": "^7.2.18",
|
||||||
|
"@mui/utils": "^6.1.3",
|
||||||
|
"@popperjs/core": "^2.11.8",
|
||||||
|
"@types/react-transition-group": "^4.4.11",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"csstype": "^3.1.3",
|
||||||
|
"prop-types": "^15.8.1",
|
||||||
|
"react-is": "^18.3.1",
|
||||||
|
"react-transition-group": "^4.4.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mui-org"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@emotion/react": "^11.5.0",
|
||||||
|
"@emotion/styled": "^11.3.0",
|
||||||
|
"@mui/material-pigment-css": "^6.1.3",
|
||||||
|
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@emotion/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@emotion/styled": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@mui/material-pigment-css": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mui/material/node_modules/react-is": {
|
||||||
|
"version": "18.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
|
||||||
|
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
|
||||||
|
},
|
||||||
|
"node_modules/@mui/private-theming": {
|
||||||
|
"version": "6.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.3.tgz",
|
||||||
|
"integrity": "sha512-XK5OYCM0x7gxWb/WBEySstBmn+dE3YKX7U7jeBRLm6vHU5fGUd7GiJWRirpivHjOK9mRH6E1MPIVd+ze5vguKQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.25.6",
|
||||||
|
"@mui/utils": "^6.1.3",
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mui-org"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mui/styled-engine": {
|
||||||
|
"version": "6.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.3.tgz",
|
||||||
|
"integrity": "sha512-i4yh9m+eMZE3cNERpDhVr6Wn73Yz6C7MH0eE2zZvw8d7EFkIJlCQNZd1xxGZqarD2DDq2qWHcjIOucWGhxACtA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.25.6",
|
||||||
|
"@emotion/cache": "^11.13.1",
|
||||||
|
"@emotion/serialize": "^1.3.2",
|
||||||
|
"@emotion/sheet": "^1.4.0",
|
||||||
|
"csstype": "^3.1.3",
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mui-org"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@emotion/react": "^11.4.1",
|
||||||
|
"@emotion/styled": "^11.3.0",
|
||||||
|
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@emotion/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@emotion/styled": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mui/system": {
|
||||||
|
"version": "6.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.3.tgz",
|
||||||
|
"integrity": "sha512-ILaD9UsLTBLjMcep3OumJMXh1PYr7aqnkHm/L47bH46+YmSL1zWAX6tWG8swEQROzW2GvYluEMp5FreoxOOC6w==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.25.6",
|
||||||
|
"@mui/private-theming": "^6.1.3",
|
||||||
|
"@mui/styled-engine": "^6.1.3",
|
||||||
|
"@mui/types": "^7.2.18",
|
||||||
|
"@mui/utils": "^6.1.3",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"csstype": "^3.1.3",
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mui-org"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@emotion/react": "^11.5.0",
|
||||||
|
"@emotion/styled": "^11.3.0",
|
||||||
|
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@emotion/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@emotion/styled": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mui/types": {
|
||||||
|
"version": "7.2.18",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.18.tgz",
|
||||||
|
"integrity": "sha512-uvK9dWeyCJl/3ocVnTOS6nlji/Knj8/tVqVX03UVTpdmTJYu/s4jtDd9Kvv0nRGE0CUSNW1UYAci7PYypjealg==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mui/utils": {
|
||||||
|
"version": "6.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.3.tgz",
|
||||||
|
"integrity": "sha512-4JBpLkjprlKjN10DGb1aiy/ii9TKbQ601uSHtAmYFAS879QZgAD7vRnv/YBE4iBbc7NXzFgbQMCOFrupXWekIA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.25.6",
|
||||||
|
"@mui/types": "^7.2.18",
|
||||||
|
"@types/prop-types": "^15.7.13",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"prop-types": "^15.8.1",
|
||||||
|
"react-is": "^18.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mui-org"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mui/utils/node_modules/react-is": {
|
||||||
|
"version": "18.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
|
||||||
|
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
|
||||||
|
},
|
||||||
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
|
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
|
||||||
"version": "5.1.1-v1",
|
"version": "5.1.1-v1",
|
||||||
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
|
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
|
||||||
@ -3549,6 +3811,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@popperjs/core": {
|
||||||
|
"version": "2.11.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||||
|
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/popperjs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@remix-run/router": {
|
"node_modules/@remix-run/router": {
|
||||||
"version": "1.19.2",
|
"version": "1.19.2",
|
||||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.2.tgz",
|
||||||
@ -4769,6 +5040,14 @@
|
|||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/react-transition-group": {
|
||||||
|
"version": "4.4.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz",
|
||||||
|
"integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/resolve": {
|
"node_modules/@types/resolve": {
|
||||||
"version": "1.17.1",
|
"version": "1.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
|
||||||
@ -6611,6 +6890,14 @@
|
|||||||
"wrap-ansi": "^7.0.0"
|
"wrap-ansi": "^7.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/clsx": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/co": {
|
"node_modules/co": {
|
||||||
"version": "4.6.0",
|
"version": "4.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||||
@ -7638,6 +7925,15 @@
|
|||||||
"utila": "~0.4"
|
"utila": "~0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dom-helpers": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.8.7",
|
||||||
|
"csstype": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dom-serializer": {
|
"node_modules/dom-serializer": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
|
||||||
@ -16404,6 +16700,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-transition-group": {
|
||||||
|
"version": "4.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||||
|
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.5.5",
|
||||||
|
"dom-helpers": "^5.0.1",
|
||||||
|
"loose-envify": "^1.4.0",
|
||||||
|
"prop-types": "^15.6.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.6.0",
|
||||||
|
"react-dom": ">=16.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/read-cache": {
|
"node_modules/read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
@ -17951,6 +18262,11 @@
|
|||||||
"postcss": "^8.2.15"
|
"postcss": "^8.2.15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/stylis": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="
|
||||||
|
},
|
||||||
"node_modules/sucrase": {
|
"node_modules/sucrase": {
|
||||||
"version": "3.35.0",
|
"version": "3.35.0",
|
||||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@mui/material": "^6.1.3",
|
||||||
"@testing-library/jest-dom": "^5.17.0",
|
"@testing-library/jest-dom": "^5.17.0",
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
|
@ -27,7 +27,7 @@ const useWebsocketConnection = (userToken, roomHash) => {
|
|||||||
return prevState;
|
return prevState;
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error parsing WebSocket message:', error);
|
console.error('Error parsing WebSocket message:', error, event.data);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,11 +14,12 @@ import { ModalJson } from './Modal/MJson';
|
|||||||
import { ModalMap } from './Modal/MMap';
|
import { ModalMap } from './Modal/MMap';
|
||||||
import { CtxMenu } from './ContextMenu/CtxMenu';
|
import { CtxMenu } from './ContextMenu/CtxMenu';
|
||||||
import { ProgramInterface } from './MainScreen/ProgramInterface';
|
import { ProgramInterface } from './MainScreen/ProgramInterface';
|
||||||
|
import { SimulatorInterface } from './SimScreen/SimScreen';
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
const mountRef = useRef(null); // Указатель монтирования
|
const mountRef = useRef(null); // Указатель монтирования
|
||||||
const sceneRef = useRef(null); // Указатель на сцену
|
const sceneRef = useRef(null); // Указатель на сцену
|
||||||
|
const cameraRef = useRef(null); // Указатель на камеру
|
||||||
const {websocketStruct, sendMessage} = useWebsocketConnection(getCustomCookie("userToken"), 1);
|
const {websocketStruct, sendMessage} = useWebsocketConnection(getCustomCookie("userToken"), 1);
|
||||||
const [heightData, setHeightData] = useState([new HeightPoint()]); // Высоты
|
const [heightData, setHeightData] = useState([new HeightPoint()]); // Высоты
|
||||||
const [formData, setFormData] = useState({ x: '', y: '', height: '' }); // Форма для ввода данных карты
|
const [formData, setFormData] = useState({ x: '', y: '', height: '' }); // Форма для ввода данных карты
|
||||||
@ -29,7 +30,6 @@ const Dashboard = () => {
|
|||||||
const [selectedBaseStation, setSelectedBaseStation] = useState(null); // Состояние для выбранной базовой станции
|
const [selectedBaseStation, setSelectedBaseStation] = useState(null); // Состояние для выбранной базовой станции
|
||||||
const [mapSettings, setMapSettings] = useState({maxHeight: 20, coordX: 0, coordY: 0, }); // Настройки карты
|
const [mapSettings, setMapSettings] = useState({maxHeight: 20, coordX: 0, coordY: 0, }); // Настройки карты
|
||||||
const [contextMenu, setContextMenu] = useState({ visible: false, x: 0, y: 0 }); // контекстное меню сцены
|
const [contextMenu, setContextMenu] = useState({ visible: false, x: 0, y: 0 }); // контекстное меню сцены
|
||||||
|
|
||||||
const [objectType, setObjectType] = useState(1); // 1 = Drone, 2 = Base Station
|
const [objectType, setObjectType] = useState(1); // 1 = Drone, 2 = Base Station
|
||||||
const [formObjectData, setFormObjectData] = useState({
|
const [formObjectData, setFormObjectData] = useState({
|
||||||
name: "",
|
name: "",
|
||||||
@ -52,6 +52,204 @@ const Dashboard = () => {
|
|||||||
meshName: "", // Название сети
|
meshName: "", // Название сети
|
||||||
});
|
});
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
|
const [isSimulationRunning, setIsSimulationRunning] = useState(false);
|
||||||
|
|
||||||
|
// Рекурсивная функция для поиска объекта среди детей
|
||||||
|
const containsObjectRecursively = (parent, target) => {
|
||||||
|
if (parent === target) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (let child of parent.children) {
|
||||||
|
if (containsObjectRecursively(child, target)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Обработка websocket
|
||||||
|
useEffect(() => {
|
||||||
|
if (websocketStruct && websocketStruct.modulation) {
|
||||||
|
const modulation = websocketStruct.modulation;
|
||||||
|
// Парсинг карты
|
||||||
|
const map = modulation.map;
|
||||||
|
setMapSettings({
|
||||||
|
name: map.name,
|
||||||
|
minBound: map.map.MinBound,
|
||||||
|
maxBound: map.map.MaxBound,
|
||||||
|
heightData: map.map.HeightData,
|
||||||
|
maxHeight: 20,
|
||||||
|
});
|
||||||
|
setHeightData(map.map.HeightData.flatMap((row, x) => row.map((height, y) => new HeightPoint(x, y, height))));
|
||||||
|
|
||||||
|
// Парсинг объектов
|
||||||
|
const parsedDrones = [];
|
||||||
|
const parsedBaseStations = [];
|
||||||
|
modulation.objects.forEach((obj) => {
|
||||||
|
if (obj.type === 1) {
|
||||||
|
const drone = new Drone(obj.name);
|
||||||
|
drone.setPosition(...obj.coords);
|
||||||
|
parsedDrones.push(drone);
|
||||||
|
} else if (obj.type === 2) {
|
||||||
|
const base = new BaseStation(obj.name);
|
||||||
|
base.setPosition(...obj.coords);
|
||||||
|
parsedBaseStations.push(base);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setDrones(parsedDrones);
|
||||||
|
setBaseStation(parsedBaseStations);
|
||||||
|
}
|
||||||
|
}, [websocketStruct]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!mountRef.current) return;
|
||||||
|
let width = mountRef.current.clientWidth;
|
||||||
|
let height = mountRef.current.clientHeight;
|
||||||
|
// Создаем объект сцены
|
||||||
|
const scene = new THREE.Scene();
|
||||||
|
scene.background = new THREE.Color(0xffffff);
|
||||||
|
// Сохраняем ссылку на сцену
|
||||||
|
sceneRef.current = scene;
|
||||||
|
// Создаем камеру
|
||||||
|
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 2000);
|
||||||
|
camera.position.set(0, 80, 120);
|
||||||
|
cameraRef.current = camera;
|
||||||
|
|
||||||
|
const renderer = new THREE.WebGLRenderer();
|
||||||
|
renderer.setSize(width, height);
|
||||||
|
mountRef.current.appendChild(renderer.domElement);
|
||||||
|
|
||||||
|
// Плоскость для высотной карты :: TODO :: W/H/Ws/Hs change
|
||||||
|
const geometry = new THREE.PlaneGeometry(200, 200, 20, 20);
|
||||||
|
const vertices = geometry.attributes.position.array;
|
||||||
|
const colors = [];
|
||||||
|
const color = new THREE.Color();
|
||||||
|
|
||||||
|
const minHeight = Math.min(...heightData.map((point) => point.height));
|
||||||
|
const maxHeight = Math.max(mapSettings.maxHeight, ...heightData.map((point) => point.height));
|
||||||
|
|
||||||
|
for (let i = 0; i < vertices.length; i += 3) {
|
||||||
|
const x = Math.floor(i / 3) % 5;
|
||||||
|
const y = Math.floor(i / (3 * 5));
|
||||||
|
|
||||||
|
const heightPoint = heightData.find((point) => point.x === x && point.y === y);
|
||||||
|
const heightValue = heightPoint ? heightPoint.height : 0;
|
||||||
|
|
||||||
|
vertices[i + 2] = heightValue;
|
||||||
|
|
||||||
|
const normalizedHeight = (heightValue - minHeight) / (maxHeight - minHeight);
|
||||||
|
color.setHSL(0.7 * (1 - normalizedHeight), 1, 0.5);
|
||||||
|
colors.push(color.r, color.g, color.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
|
||||||
|
|
||||||
|
const material = new THREE.MeshBasicMaterial({
|
||||||
|
vertexColors: true,
|
||||||
|
side: THREE.DoubleSide,
|
||||||
|
wireframe: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const mesh = new THREE.Mesh(geometry, material);
|
||||||
|
mesh.rotation.x = -Math.PI / 2;
|
||||||
|
scene.add(mesh);
|
||||||
|
|
||||||
|
const axesHelper = new THREE.AxesHelper(100);
|
||||||
|
scene.add(axesHelper);
|
||||||
|
|
||||||
|
const controls = new OrbitControls(camera, renderer.domElement);
|
||||||
|
controls.enableDamping = true;
|
||||||
|
|
||||||
|
const light = new THREE.DirectionalLight(0xffffff, 1);
|
||||||
|
light.position.set(0, 50, 50).normalize();
|
||||||
|
scene.add(light);
|
||||||
|
|
||||||
|
const handleMouseMove = (event) => {
|
||||||
|
let x = event.x;
|
||||||
|
let y = event.y;
|
||||||
|
setMouseState({ x: x, y: y, z: 0 });
|
||||||
|
}
|
||||||
|
const animate = () => {
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
controls.update();
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
};
|
||||||
|
|
||||||
|
renderer.domElement.addEventListener('click', handleClick);
|
||||||
|
renderer.domElement.addEventListener('mousemove', handleMouseMove);
|
||||||
|
|
||||||
|
animate();
|
||||||
|
drones.forEach(droneData => {
|
||||||
|
scene.add(droneData.getObject());
|
||||||
|
});
|
||||||
|
baseStation.forEach(b => {
|
||||||
|
scene.add(b.getObject());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обработка нажатия ПКМ
|
||||||
|
renderer.domElement.addEventListener('contextmenu', (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
setContextMenu({
|
||||||
|
visible: true,
|
||||||
|
x: event.clientX,
|
||||||
|
y: event.clientY,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
if (mountRef.current) {
|
||||||
|
mountRef.current.removeChild(renderer.domElement);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [heightData, mapSettings]);
|
||||||
|
|
||||||
|
// Обработка кликов на сцене
|
||||||
|
const handleClick = (event) => {
|
||||||
|
// Рассчитываем координаты мыши в нормализованной системе координат и округляем до целого числа
|
||||||
|
const mouse = new THREE.Vector2();
|
||||||
|
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
|
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
console.log('Mouse coordinates:', mouse);
|
||||||
|
|
||||||
|
// Создаем объект Raycaster для проверки пересечений
|
||||||
|
const raycaster = new THREE.Raycaster();
|
||||||
|
const rayHelper = new THREE.ArrowHelper(raycaster.ray.direction, raycaster.ray.origin, 100, 0xff4444);
|
||||||
|
sceneRef.current.add(rayHelper);
|
||||||
|
raycaster.setFromCamera(mouse, cameraRef.current);
|
||||||
|
|
||||||
|
// Проверяем пересечения с объектами дронов
|
||||||
|
const intersects = raycaster.intersectObjects(drones.map(drone => drone.getObject()), true);
|
||||||
|
console.log('Intersections:', intersects);
|
||||||
|
console.log('Drones:', drones.map(drone => [drone.getObject(), drone.getObject().position, drone.name]));
|
||||||
|
|
||||||
|
if (intersects.length > 0) {
|
||||||
|
const selected = intersects[0].object;
|
||||||
|
console.log('Clicked on:', selected); // Лог для проверки объекта
|
||||||
|
|
||||||
|
// Поиск дрона рекурсивно
|
||||||
|
const drone = drones.find(drone => containsObjectRecursively(drone.getObject(), selected));
|
||||||
|
|
||||||
|
if (drone) {
|
||||||
|
// Сбрасываем цвет предыдущего выбранного дрона
|
||||||
|
if (selectedDrone) {
|
||||||
|
drone.getObject().visible = true;
|
||||||
|
}
|
||||||
|
// Устанавливаем цвет выбранного дрона
|
||||||
|
drone.getObject().visible = false;
|
||||||
|
console.log(drone);
|
||||||
|
setSelectedDrone(drone);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Сбрасываем выбор, если ни один дрон не был выбран
|
||||||
|
if (selectedDrone) {
|
||||||
|
selectedDrone.getObject().visible = true;
|
||||||
|
setSelectedDrone(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Остальной код компонента остается неизменным
|
||||||
|
|
||||||
|
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
const foundDrone = drones.find(drone => drone.name.toLowerCase() === searchTerm.toLowerCase());
|
const foundDrone = drones.find(drone => drone.name.toLowerCase() === searchTerm.toLowerCase());
|
||||||
const foundBaseStation = baseStation.find(base => base.name.toLowerCase() === searchTerm.toLowerCase());
|
const foundBaseStation = baseStation.find(base => base.name.toLowerCase() === searchTerm.toLowerCase());
|
||||||
@ -122,204 +320,6 @@ const Dashboard = () => {
|
|||||||
isModalSearchOpen: false,
|
isModalSearchOpen: false,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// Обработка websocket
|
|
||||||
useEffect(() => {
|
|
||||||
if (websocketStruct && websocketStruct.modulation) {
|
|
||||||
const modulation = websocketStruct.modulation;
|
|
||||||
// Парсинг карты
|
|
||||||
const map = modulation.map;
|
|
||||||
setMapSettings({
|
|
||||||
name: map.name,
|
|
||||||
minBound: map.map.MinBound,
|
|
||||||
maxBound: map.map.MaxBound,
|
|
||||||
heightData: map.map.HeightData,
|
|
||||||
maxHeight: 20,
|
|
||||||
});
|
|
||||||
setHeightData(map.map.HeightData.flatMap((row, x) => row.map((height, y) => new HeightPoint(x, y, height))));
|
|
||||||
|
|
||||||
// Парсинг объектов
|
|
||||||
const parsedDrones = [];
|
|
||||||
const parsedBaseStations = [];
|
|
||||||
modulation.objects.forEach((obj) => {
|
|
||||||
if (obj.type === 1) {
|
|
||||||
const drone = new Drone(obj.name);
|
|
||||||
drone.setPosition(...obj.coords);
|
|
||||||
parsedDrones.push(drone);
|
|
||||||
} else if (obj.type === 2) {
|
|
||||||
const base = new BaseStation(obj.name);
|
|
||||||
base.setPosition(...obj.coords);
|
|
||||||
parsedBaseStations.push(base);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setDrones(parsedDrones);
|
|
||||||
setBaseStation(parsedBaseStations);
|
|
||||||
}
|
|
||||||
}, [websocketStruct]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
|
|
||||||
if (!mountRef.current) return;
|
|
||||||
let width = mountRef.current.clientWidth;
|
|
||||||
let height = mountRef.current.clientHeight;
|
|
||||||
// Создаем объект сцены
|
|
||||||
const scene = new THREE.Scene();
|
|
||||||
scene.background = new THREE.Color(0xffffff);
|
|
||||||
// Сохраняем ссылку на сцену
|
|
||||||
sceneRef.current = scene;
|
|
||||||
// Создаем камеру
|
|
||||||
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 2000);
|
|
||||||
camera.position.set(0, 80, 120);
|
|
||||||
|
|
||||||
const renderer = new THREE.WebGLRenderer();
|
|
||||||
renderer.setSize(width, height);
|
|
||||||
mountRef.current.appendChild(renderer.domElement);
|
|
||||||
|
|
||||||
// Плоскость для высотной карты :: TODO :: W/H/Ws/Hs change
|
|
||||||
const geometry = new THREE.PlaneGeometry(200, 200, 20, 20);
|
|
||||||
const vertices = geometry.attributes.position.array;
|
|
||||||
const colors = [];
|
|
||||||
const color = new THREE.Color();
|
|
||||||
|
|
||||||
const minHeight = Math.min(...heightData.map((point) => point.height));
|
|
||||||
const maxHeight = Math.max(mapSettings.maxHeight, ...heightData.map((point) => point.height));
|
|
||||||
|
|
||||||
for (let i = 0; i < vertices.length; i += 3) {
|
|
||||||
const x = Math.floor(i / 3) % 5;
|
|
||||||
const y = Math.floor(i / (3 * 5));
|
|
||||||
|
|
||||||
const heightPoint = heightData.find((point) => point.x === x && point.y === y);
|
|
||||||
const heightValue = heightPoint ? heightPoint.height : 0;
|
|
||||||
|
|
||||||
vertices[i + 2] = heightValue;
|
|
||||||
|
|
||||||
const normalizedHeight = (heightValue - minHeight) / (maxHeight - minHeight);
|
|
||||||
color.setHSL(0.7 * (1 - normalizedHeight), 1, 0.5);
|
|
||||||
colors.push(color.r, color.g, color.b);
|
|
||||||
}
|
|
||||||
|
|
||||||
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
|
|
||||||
|
|
||||||
const material = new THREE.MeshBasicMaterial({
|
|
||||||
vertexColors: true,
|
|
||||||
side: THREE.DoubleSide,
|
|
||||||
wireframe: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const mesh = new THREE.Mesh(geometry, material);
|
|
||||||
mesh.rotation.x = -Math.PI / 2;
|
|
||||||
scene.add(mesh);
|
|
||||||
|
|
||||||
const axesHelper = new THREE.AxesHelper(100);
|
|
||||||
scene.add(axesHelper);
|
|
||||||
|
|
||||||
const controls = new OrbitControls(camera, renderer.domElement);
|
|
||||||
controls.enableDamping = true;
|
|
||||||
|
|
||||||
const light = new THREE.DirectionalLight(0xffffff, 1);
|
|
||||||
light.position.set(0, 50, 50).normalize();
|
|
||||||
scene.add(light);
|
|
||||||
// Обработка кликов на сцене
|
|
||||||
const handleClick = (event) => {
|
|
||||||
// Рассчитываем координаты мыши в нормализованной системе координат и округляем до целого числа
|
|
||||||
const mouse = new THREE.Vector2();
|
|
||||||
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
|
||||||
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
|
|
||||||
console.log('Mouse coordinates:', mouse);
|
|
||||||
|
|
||||||
// Создаем объект Raycaster для проверки пересечений
|
|
||||||
const raycaster = new THREE.Raycaster();
|
|
||||||
const rayHelper = new THREE.ArrowHelper(raycaster.ray.direction, raycaster.ray.origin, 100, 0xff4444);
|
|
||||||
scene.add(rayHelper);
|
|
||||||
raycaster.setFromCamera(mouse, camera);
|
|
||||||
|
|
||||||
// Проверяем пересечения с объектами дронов
|
|
||||||
const intersects = raycaster.intersectObjects(drones.map(drone => drone.getObject()), true);
|
|
||||||
console.log('Intersections:', intersects);
|
|
||||||
console.log('Drones:', drones.map(drone => [drone.getObject(), drone.getObject().position, drone.name]));
|
|
||||||
|
|
||||||
if (intersects.length > 0) {
|
|
||||||
const selected = intersects[0].object;
|
|
||||||
console.log('Clicked on:', selected); // Лог для проверки объекта
|
|
||||||
|
|
||||||
// Поиск дрона рекурсивно
|
|
||||||
const drone = drones.find(drone => containsObjectRecursively(drone.getObject(), selected));
|
|
||||||
|
|
||||||
if (drone) {
|
|
||||||
// Сбрасываем цвет предыдущего выбранного дрона
|
|
||||||
if (selectedDrone) {
|
|
||||||
drone.getObject().visible = true;
|
|
||||||
// selectedDrone.getObject().material.color.set(0xff0000);
|
|
||||||
}
|
|
||||||
// Устанавливаем цвет выбранного дрона
|
|
||||||
// drone.getObject().material.color.set(0xff1111);
|
|
||||||
drone.getObject().visible = false;
|
|
||||||
console.log(drone);
|
|
||||||
setSelectedDrone(drone);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Сбрасываем выбор, если ни один дрон не был выбран
|
|
||||||
if (selectedDrone) {
|
|
||||||
// selectedDrone.getObject().material.color.set(0xff0000);
|
|
||||||
selectedDrone .getObject().visible = true;
|
|
||||||
|
|
||||||
setSelectedDrone(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Рекурсивная функция для поиска объекта среди детей
|
|
||||||
const containsObjectRecursively = (parent, target) => {
|
|
||||||
if (parent === target) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for (let child of parent.children) {
|
|
||||||
if (containsObjectRecursively(child, target)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleMouseMove = (event) => {
|
|
||||||
let x = event.x;
|
|
||||||
let y = event.y;
|
|
||||||
setMouseState({ x: x, y: y, z: 0 });
|
|
||||||
}
|
|
||||||
const animate = () => {
|
|
||||||
requestAnimationFrame(animate);
|
|
||||||
controls.update();
|
|
||||||
renderer.render(scene, camera);
|
|
||||||
};
|
|
||||||
|
|
||||||
renderer.domElement.addEventListener('click', handleClick);
|
|
||||||
renderer.domElement.addEventListener('mousemove', handleMouseMove);
|
|
||||||
|
|
||||||
|
|
||||||
animate();
|
|
||||||
drones.forEach(droneData => {
|
|
||||||
scene.add(droneData.getObject());
|
|
||||||
});
|
|
||||||
baseStation.forEach(b => {
|
|
||||||
scene.add(b.getObject());
|
|
||||||
});
|
|
||||||
|
|
||||||
// Обработка нажатия ПКМ
|
|
||||||
renderer.domElement.addEventListener('contextmenu', (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
setContextMenu({
|
|
||||||
visible: true,
|
|
||||||
x: event.clientX,
|
|
||||||
y: event.clientY,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return () => {
|
|
||||||
if (mountRef.current) {
|
|
||||||
mountRef.current.removeChild(renderer.domElement);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [heightData, mapSettings]);
|
|
||||||
|
|
||||||
// Добавление дрона в сцену
|
// Добавление дрона в сцену
|
||||||
const handleAddDrone = () => {
|
const handleAddDrone = () => {
|
||||||
@ -418,12 +418,8 @@ const containsObjectRecursively = (parent, target) => {
|
|||||||
};
|
};
|
||||||
// Открытие контекстного меню
|
// Открытие контекстного меню
|
||||||
const handleContextMenuClick = (action) => {
|
const handleContextMenuClick = (action) => {
|
||||||
if (action === 'add_base'){
|
if (action === 'add_base'){ handleAddBaseStation();}
|
||||||
handleAddBaseStation();
|
else if (action === 'add') { handleAddDrone(); } else if (action === 'save') {
|
||||||
}
|
|
||||||
else if (action === 'add') {
|
|
||||||
handleAddDrone();
|
|
||||||
} else if (action === 'save') {
|
|
||||||
console.log('Сохранить промежуточный результат');
|
console.log('Сохранить промежуточный результат');
|
||||||
}
|
}
|
||||||
setContextMenu({ ...contextMenu, visible: false });
|
setContextMenu({ ...contextMenu, visible: false });
|
||||||
@ -471,16 +467,35 @@ const containsObjectRecursively = (parent, target) => {
|
|||||||
handleInputChange={handleInputChange}
|
handleInputChange={handleInputChange}
|
||||||
mapSettings={mapSettings}
|
mapSettings={mapSettings}
|
||||||
handleSettingsChange={handleSettingsChange}/>
|
handleSettingsChange={handleSettingsChange}/>
|
||||||
|
<ul className="nav">
|
||||||
|
<li className="nav-item">
|
||||||
|
<a className="nav-link active"onClick={() => setIsSimulationRunning(true)} >Активная</a>
|
||||||
|
</li>
|
||||||
|
<li className="nav-item">
|
||||||
|
<a className="nav-link" onClick={() => setIsSimulationRunning(true)}>Симуляция</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
{/* Окно программы */}
|
{/* Окно программы */}
|
||||||
<ProgramInterface
|
{isSimulationRunning ? (
|
||||||
mouseState={mouseState}
|
// isSimulationRunning
|
||||||
mountRef={mountRef}
|
<SimulatorInterface
|
||||||
openModal={openModal}
|
mouseState={mouseState}
|
||||||
sendMessage={sendMessage}
|
mountRef={mountRef}
|
||||||
RunSimulatorSignal={RunSimulatorSignal}
|
openModal={openModal}
|
||||||
getCustomCookie={getCustomCookie}
|
sendMessage={sendMessage}
|
||||||
/>
|
RunSimulatorSignal={RunSimulatorSignal}
|
||||||
|
getCustomCookie={getCustomCookie}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<ProgramInterface
|
||||||
|
mouseState={mouseState}
|
||||||
|
mountRef={mountRef}
|
||||||
|
openModal={openModal}
|
||||||
|
sendMessage={sendMessage}
|
||||||
|
RunSimulatorSignal={RunSimulatorSignal}
|
||||||
|
getCustomCookie={getCustomCookie}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<CtxMenu
|
<CtxMenu
|
||||||
contextMenu={contextMenu}
|
contextMenu={contextMenu}
|
||||||
handleContextMenuClick={handleContextMenuClick}
|
handleContextMenuClick={handleContextMenuClick}
|
||||||
|
@ -1,14 +1,23 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ModalWindow from '../components/Modal/Modal';
|
import ModalWindow from '../components/Modal/Modal';
|
||||||
|
|
||||||
|
export const ModalDelete = ({ isModalDeleteOpen, closeAllModals, handleDeleteSignal }) => {
|
||||||
export const ModalDelete = ({isModalDeleteOpen, closeAllModals, handleDeleteSignal}) => {
|
|
||||||
return (
|
return (
|
||||||
<ModalWindow isOpen={isModalDeleteOpen} onClose={closeAllModals}>
|
<ModalWindow isOpen={isModalDeleteOpen} onClose={closeAllModals}>
|
||||||
<h2>Удаление</h2>
|
<div className="modal-dialog">
|
||||||
<h2>Вы точно хотите удалить объект X?</h2>
|
<div className="modal-content">
|
||||||
<button onClick={closeAllModals}>Отмена</button>
|
<div className="modal-header">
|
||||||
<button onClick={() => handleDeleteSignal(1) }>Удалить</button>
|
<h5 className="modal-title">Удаление</h5>
|
||||||
</ModalWindow>
|
</div>
|
||||||
)
|
<div className="modal-body">
|
||||||
}
|
<p>Вы точно хотите удалить объект X?</p>
|
||||||
|
</div>
|
||||||
|
<div className="modal-footer">
|
||||||
|
<button type="button" className="btn btn-secondary" onClick={closeAllModals}>Отмена</button>
|
||||||
|
<button type="button" className="btn btn-danger" onClick={() => handleDeleteSignal(1)}>Удалить</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ModalWindow>
|
||||||
|
);
|
||||||
|
};
|
@ -2,14 +2,25 @@ import React from 'react';
|
|||||||
import ModalWindow from '../components/Modal/Modal';
|
import ModalWindow from '../components/Modal/Modal';
|
||||||
|
|
||||||
|
|
||||||
export const ModalJson= ({isModalOpen, closeAllModals}) => {
|
export const ModalJson = ({ isModalOpen, closeAllModals }) => {
|
||||||
return (
|
return (
|
||||||
<ModalWindow isOpen={isModalOpen} onClose={closeAllModals}>
|
<ModalWindow isOpen={isModalOpen} onClose={closeAllModals}>
|
||||||
<h2>Загрузка JSON</h2>
|
<div className="modal-dialog">
|
||||||
<p>Выберите или переташите файл для загрузки</p>
|
<div className="modal-content">
|
||||||
<input type='file'/>
|
<div className="modal-header">
|
||||||
<button onClick={closeAllModals}>Отмена</button>
|
<h5 className="modal-title">Загрузка JSON</h5>
|
||||||
<button onClick={() => alert('Загружено')}>Загрузить</button>
|
<button type="button" className="btn-close" aria-label="Close" onClick={closeAllModals}></button>
|
||||||
|
</div>
|
||||||
|
<div className="modal-body">
|
||||||
|
<p>Выберите или переташите файл для загрузки</p>
|
||||||
|
<input type="file" className="form-control" />
|
||||||
|
</div>
|
||||||
|
<div className="modal-footer">
|
||||||
|
<button type="button" className="btn btn-secondary" onClick={closeAllModals}>Отмена</button>
|
||||||
|
<button type="button" className="btn btn-success" onClick={() => alert('Загружено')}>Загрузить</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</ModalWindow>
|
</ModalWindow>
|
||||||
)
|
);
|
||||||
}
|
};
|
@ -1,18 +1,21 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ModalWindow from '../components/Modal/Modal';
|
import ModalWindow from '../components/Modal/Modal';
|
||||||
|
|
||||||
|
export const ModalMap = ({ isModalMapOpen, closeAllModals, handleAddHeight, formData, handleInputChange, mapSettings, handleSettingsChange }) => {
|
||||||
export const ModalMap = ({isModalMapOpen, closeAllModals, handleAddHeight, formData, handleInputChange, mapSettings, handleSettingsChange}) => {
|
return (
|
||||||
return (
|
<ModalWindow isOpen={isModalMapOpen} onClose={closeAllModals}>
|
||||||
<ModalWindow isOpen={isModalMapOpen} onClose={closeAllModals}>
|
<div className="modal-header">
|
||||||
<h2>Настройки карты</h2>
|
<h5 className="modal-title">Настройки карты</h5>
|
||||||
<div className="columns">
|
<button type="button" className="btn-close" aria-label="Close" onClick={closeAllModals}></button>
|
||||||
<div className='column'>
|
</div>
|
||||||
<form onSubmit={handleAddHeight} style={{ marginTop: '20px' }}>
|
<div className="modal-body">
|
||||||
<div>
|
<div className="row">
|
||||||
<label>Координата X:</label>
|
<div className="col-md-6">
|
||||||
|
<form onSubmit={handleAddHeight} className="mt-3">
|
||||||
|
<div className="mb-3">
|
||||||
|
<label className="form-label">Координата X:</label>
|
||||||
<input
|
<input
|
||||||
className="input is-primary"
|
className="form-control"
|
||||||
type="number"
|
type="number"
|
||||||
name="x"
|
name="x"
|
||||||
value={formData.x}
|
value={formData.x}
|
||||||
@ -20,10 +23,10 @@ export const ModalMap = ({isModalMapOpen, closeAllModals, handleAddHeight, formD
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="mb-3">
|
||||||
<label>Координата Y:</label>
|
<label className="form-label">Координата Y:</label>
|
||||||
<input
|
<input
|
||||||
className="input is-primary"
|
className="form-control"
|
||||||
type="number"
|
type="number"
|
||||||
name="y"
|
name="y"
|
||||||
value={formData.y}
|
value={formData.y}
|
||||||
@ -31,10 +34,10 @@ export const ModalMap = ({isModalMapOpen, closeAllModals, handleAddHeight, formD
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="mb-3">
|
||||||
<label>Высота:</label>
|
<label className="form-label">Высота:</label>
|
||||||
<input
|
<input
|
||||||
className="input is-primary"
|
className="form-control"
|
||||||
type="number"
|
type="number"
|
||||||
name="height"
|
name="height"
|
||||||
value={formData.height}
|
value={formData.height}
|
||||||
@ -42,28 +45,31 @@ export const ModalMap = ({isModalMapOpen, closeAllModals, handleAddHeight, formD
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button className='button' type="submit">Добавить точку высоты</button>
|
<button className="btn btn-primary" type="submit">Добавить точку высоты</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{/* Настройки карты */}
|
{/* Настройки карты */}
|
||||||
<div className='column'>
|
<div className="col-md-6">
|
||||||
<div style={{ marginTop: '20px' }}>
|
<div className="mt-3">
|
||||||
<h2>Настройки карты</h2>
|
<h5>Настройки карты</h5>
|
||||||
<div>
|
<div className="mb-3">
|
||||||
<label>Максимальная высота:</label>
|
<label className="form-label">Максимальная высота:</label>
|
||||||
<input
|
<input
|
||||||
className="input"
|
className="form-control"
|
||||||
type="number"
|
type="number"
|
||||||
name="maxHeight"
|
name="maxHeight"
|
||||||
value={mapSettings.maxHeight}
|
value={mapSettings.maxHeight}
|
||||||
onChange={handleSettingsChange}
|
onChange={handleSettingsChange}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button onClick={closeAllModals}>Отмена</button>
|
<div className="modal-footer">
|
||||||
<button onClick={() => alert('Обновлена карта!')}>Готово</button>
|
<button className="btn btn-secondary" onClick={closeAllModals}>Отмена</button>
|
||||||
</ModalWindow>
|
<button className="btn btn-success" onClick={() => alert('Обновлена карта!')}>Готово</button>
|
||||||
)
|
</div>
|
||||||
}
|
</ModalWindow>
|
||||||
|
);
|
||||||
|
};
|
@ -2,17 +2,28 @@ import React from 'react';
|
|||||||
import ModalWindow from '../components/Modal/Modal';
|
import ModalWindow from '../components/Modal/Modal';
|
||||||
|
|
||||||
|
|
||||||
export const ModalSearch = ({isModalSearchOpen, closeAllModals, handleSearch, searchTerm, setSearchTerm}) => {
|
export const ModalSearch = ({ isModalSearchOpen, closeAllModals, handleSearch, searchTerm, setSearchTerm }) => {
|
||||||
return (
|
return (
|
||||||
<ModalWindow isOpen={isModalSearchOpen} onClose={closeAllModals}>
|
<ModalWindow isOpen={isModalSearchOpen} onClose={closeAllModals}>
|
||||||
<h2>Поиск</h2>
|
<div className="modal-dialog">
|
||||||
<input
|
<div className="modal-content">
|
||||||
type="text"
|
<div className="modal-header">
|
||||||
placeholder="Введите имя"
|
<h5 className="modal-title">Поиск</h5>
|
||||||
value={searchTerm}
|
</div>
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
<div className="modal-body">
|
||||||
/>
|
<input
|
||||||
<button onClick={handleSearch}>Найти</button>
|
type="text"
|
||||||
|
className="form-control"
|
||||||
|
placeholder="Введите имя"
|
||||||
|
value={searchTerm}
|
||||||
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="modal-footer">
|
||||||
|
<button type="button" className="btn btn-primary" onClick={handleSearch}>Найти</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</ModalWindow>
|
</ModalWindow>
|
||||||
)
|
);
|
||||||
}
|
};
|
@ -2,35 +2,42 @@ import React from 'react';
|
|||||||
import '../UserAccount.scss';
|
import '../UserAccount.scss';
|
||||||
|
|
||||||
const PrevCalc = () => {
|
const PrevCalc = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table className="table">
|
<div className="container mt-4">
|
||||||
<thead>
|
<h2 className="mb-4 text-center">История Калькуляций</h2>
|
||||||
<tr>
|
<table className="table table-hover table-striped table-bordered">
|
||||||
<th scope='col'><abbr title="Уникальный идентификатор в базе данных">UID</abbr></th>
|
<thead className="thead-dark">
|
||||||
<th scope='col'><abbr title="Название">Имя</abbr></th>
|
<tr>
|
||||||
<th scope='col'>Пользователь</th>
|
<th scope='col'><abbr title="Уникальный идентификатор в базе данных">UID</abbr></th>
|
||||||
<th scope='col'>Время начала</th>
|
<th scope='col'><abbr title="Название">Имя</abbr></th>
|
||||||
<th scope='col'>Время конца</th>
|
<th scope='col'>Пользователь</th>
|
||||||
<th scope='col'>Действия</th>
|
<th scope='col'>Время начала</th>
|
||||||
</tr>
|
<th scope='col'>Время конца</th>
|
||||||
</thead>
|
<th scope='col'>Действия</th>
|
||||||
<tbody>
|
</tr>
|
||||||
<tr>
|
</thead>
|
||||||
<th scope="row">1</th>
|
<tbody>
|
||||||
<td>Калькуляция полета до варшавы</td>
|
<tr>
|
||||||
<td>Гитлер</td>
|
<th scope="row">1</th>
|
||||||
<td>1:00</td>
|
<td>Калькуляция полета до Варшавы</td>
|
||||||
<td>4:04</td>
|
<td>Гитлер</td>
|
||||||
<td>
|
<td>1:00</td>
|
||||||
<button className='btn btn-primary'>
|
<td>4:04</td>
|
||||||
Загрузить
|
<td>
|
||||||
</button>
|
<div className="btn-group" role="group">
|
||||||
</td>
|
<button className='btn btn-primary'>
|
||||||
</tr>
|
Загрузить
|
||||||
</tbody>
|
</button>
|
||||||
</table>
|
<button className='btn btn-danger ml-2'>
|
||||||
)
|
Удалить
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PrevCalc;
|
export default PrevCalc;
|
78
src/frontend/src/pages/SimScreen/SimScreen.js
Normal file
78
src/frontend/src/pages/SimScreen/SimScreen.js
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
export const SimulatorInterface = ({ mouseState, sendMessage, RunSimulatorSignal, getCustomCookie }) => {
|
||||||
|
const [time, setTime] = useState(0);
|
||||||
|
const [simulationState, setSimulationState] = useState({});
|
||||||
|
const [isPlaying, setIsPlaying] = useState(false);
|
||||||
|
const mountRef = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (mountRef.current) {
|
||||||
|
// Инициализация сцены происходит при монтировании компонента
|
||||||
|
initializeScene(mountRef.current);
|
||||||
|
}
|
||||||
|
}, [mountRef.current]);
|
||||||
|
|
||||||
|
const initializeScene = (container) => {
|
||||||
|
// Здесь должна быть логика создания и инициализации сцены внутри контейнера
|
||||||
|
// Например, Three.js сцена
|
||||||
|
console.log('Scene initialized inside container:', container);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSliderChange = (event) => {
|
||||||
|
const newValue = event.target.value;
|
||||||
|
setTime(newValue);
|
||||||
|
// Обновляем состояние симуляции на основе времени
|
||||||
|
const newSimulationState = getSimulationState(newValue);
|
||||||
|
setSimulationState(newSimulationState);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePlayPause = () => {
|
||||||
|
if (isPlaying) {
|
||||||
|
setIsPlaying(false);
|
||||||
|
} else {
|
||||||
|
setIsPlaying(true);
|
||||||
|
sendMessage(RunSimulatorSignal(getCustomCookie("userToken")));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSimulationState = (timeValue) => {
|
||||||
|
// Здесь должна быть логика получения состояния симуляции на основе времени
|
||||||
|
// Например, используйте временную шкалу и объекты, чтобы получить правильное состояние
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='coler-border'>
|
||||||
|
<div>
|
||||||
|
<p> X: {mouseState.x} Y: {mouseState.y} Z: {mouseState.z}</p>
|
||||||
|
</div>
|
||||||
|
<div ref={mountRef} style={{
|
||||||
|
minWidth: '100%',
|
||||||
|
minHeight: '60vh',
|
||||||
|
position: 'relative'
|
||||||
|
}} />
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', margin: '20px 0' }}>
|
||||||
|
<button onClick={handlePlayPause} style={{
|
||||||
|
backgroundColor: '#007bff',
|
||||||
|
color: 'white',
|
||||||
|
border: 'none',
|
||||||
|
padding: '10px 20px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
borderRadius: '4px'
|
||||||
|
}}>
|
||||||
|
{isPlaying ? 'Pause' : 'Play'}
|
||||||
|
</button>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
value={time}
|
||||||
|
onChange={handleSliderChange}
|
||||||
|
min={0}
|
||||||
|
max={100}
|
||||||
|
step={1}
|
||||||
|
style={{ flexGrow: 1, marginLeft: '20px', marginRight: '20px' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
10
src/server/entity/database/logs.go
Normal file
10
src/server/entity/database/logs.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import "gorm.io/gorm"
|
||||||
|
|
||||||
|
// Struct has represent a system log
|
||||||
|
type Logs struct {
|
||||||
|
gorm.Model
|
||||||
|
Log string `json:"log"`
|
||||||
|
LogType int `json:"type"`
|
||||||
|
}
|
@ -23,10 +23,10 @@ type MapPartial struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SystemObject struct {
|
type SystemObject struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Type int `json:"type"` // 0: drone, 1: base_station
|
Type int `json:"type"` // 0: drone, 1: base_station
|
||||||
Coords [3]int `json:"coords"`
|
Coords [3]int `json:"coords"`
|
||||||
Params *map[string]string `json:"params"`
|
Params *map[string]interface{} `json:"params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteObjectIfExists удаляет объект если он найден
|
// DeleteObjectIfExists удаляет объект если он найден
|
||||||
@ -63,11 +63,11 @@ func (o *Modulation) StartNewSimulation(timestep int, user_id string) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
params := *v.Params
|
params := v.Params
|
||||||
if v.Type == 1 {
|
if v.Type == 1 {
|
||||||
// Парсинг параметров для дронов
|
// Парсинг параметров для дронов
|
||||||
antennaDirection := [3]float64{1, 0, 0} // значение по умолчанию
|
antennaDirection := [3]float64{1, 0, 0} // значение по умолчанию
|
||||||
if dir, ok := params["antennaDirections"]; ok && dir != "" {
|
if dir, ok := (*params)["$1"].(string); ok && dir != "" {
|
||||||
directionValues := strings.Split(dir, ",")
|
directionValues := strings.Split(dir, ",")
|
||||||
if len(directionValues) == 3 {
|
if len(directionValues) == 3 {
|
||||||
antennaDirection[0], _ = strconv.ParseFloat(directionValues[0], 64)
|
antennaDirection[0], _ = strconv.ParseFloat(directionValues[0], 64)
|
||||||
@ -77,12 +77,12 @@ func (o *Modulation) StartNewSimulation(timestep int, user_id string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
antennaRadius := 100.0 // значение по умолчанию
|
antennaRadius := 100.0 // значение по умолчанию
|
||||||
if radius, ok := params["antennaRadius"]; ok && radius != "" {
|
if radius, ok := (*params)["$1"].(string); ok && radius != "" {
|
||||||
antennaRadius, _ = strconv.ParseFloat(radius, 64)
|
antennaRadius, _ = strconv.ParseFloat(radius, 64)
|
||||||
}
|
}
|
||||||
|
|
||||||
waypoints := [][3]float64{}
|
waypoints := [][3]float64{}
|
||||||
if wp, ok := params["wayPoints"]; ok && wp != "" {
|
if wp, ok := (*params)["$1"].(string); ok && wp != "" {
|
||||||
// Парсинг waypoints, предполагаем, что это строка вида "x1,y1,z1;x2,y2,z2"
|
// Парсинг waypoints, предполагаем, что это строка вида "x1,y1,z1;x2,y2,z2"
|
||||||
waypointStrings := strings.Split(wp, ";")
|
waypointStrings := strings.Split(wp, ";")
|
||||||
for _, waypointStr := range waypointStrings {
|
for _, waypointStr := range waypointStrings {
|
||||||
@ -97,12 +97,12 @@ func (o *Modulation) StartNewSimulation(timestep int, user_id string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
speed := 0.0
|
speed := 0.0
|
||||||
if spd, ok := params["speed"]; ok && spd != "" {
|
if spd, ok := (*params)["$1"].(string); ok && spd != "" {
|
||||||
speed, _ = strconv.ParseFloat(spd, 64)
|
speed, _ = strconv.ParseFloat(spd, 64)
|
||||||
}
|
}
|
||||||
|
|
||||||
meshName := ""
|
meshName := ""
|
||||||
if mesh, ok := params["meshName"]; ok {
|
if mesh, ok := (*params)["$1"].(string); ok {
|
||||||
meshName = mesh
|
meshName = mesh
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ func (o *Modulation) StartNewSimulation(timestep int, user_id string) {
|
|||||||
if v.Type == 2 {
|
if v.Type == 2 {
|
||||||
// Парсинг параметров для базовых станций
|
// Парсинг параметров для базовых станций
|
||||||
antennaDirection := [3]float64{1, 0, 0} // значение по умолчанию
|
antennaDirection := [3]float64{1, 0, 0} // значение по умолчанию
|
||||||
if dir, ok := params["antennaDirections"]; ok && dir != "" {
|
if dir, ok := (*params)["$1"].(string); ok && dir != "" {
|
||||||
directionValues := strings.Split(dir, ",")
|
directionValues := strings.Split(dir, ",")
|
||||||
if len(directionValues) == 3 {
|
if len(directionValues) == 3 {
|
||||||
antennaDirection[0], _ = strconv.ParseFloat(directionValues[0], 64)
|
antennaDirection[0], _ = strconv.ParseFloat(directionValues[0], 64)
|
||||||
@ -134,7 +134,7 @@ func (o *Modulation) StartNewSimulation(timestep int, user_id string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
antennaRadius := 200.0 // значение по умолчанию
|
antennaRadius := 200.0 // значение по умолчанию
|
||||||
if radius, ok := params["antennaRadius"]; ok && radius != "" {
|
if radius, ok := (*params)["$1"].(string); ok && radius != "" {
|
||||||
antennaRadius, _ = strconv.ParseFloat(radius, 64)
|
antennaRadius, _ = strconv.ParseFloat(radius, 64)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,10 +173,10 @@ func (o *Modulation) SpawnExampleData() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddObject добавляет объект станции или дрона
|
// AddObject добавляет объект станции или дрона
|
||||||
func (o *Modulation) AddObject(name string, obj_type int, coords [3]int, params map[string]string) {
|
func (o *Modulation) AddObject(name string, obj_type int, coords [3]int, params map[string]interface{}) error {
|
||||||
if obj_type != 1 && obj_type != 2 {
|
if obj_type != 1 && obj_type != 2 {
|
||||||
// Значит объект не станция или не дрон
|
// Значит объект не станция или не дрон
|
||||||
return
|
return fmt.Errorf("ошибка добавления объекта: \n object type: %v", obj_type)
|
||||||
}
|
}
|
||||||
fmt.Println(name, obj_type, coords, params)
|
fmt.Println(name, obj_type, coords, params)
|
||||||
if o.Objects == nil {
|
if o.Objects == nil {
|
||||||
@ -192,10 +192,10 @@ func (o *Modulation) AddObject(name string, obj_type int, coords [3]int, params
|
|||||||
Params: ¶ms,
|
Params: ¶ms,
|
||||||
}
|
}
|
||||||
o.Objects = append(o.Objects, obj)
|
o.Objects = append(o.Objects, obj)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateObject обновляет объект станции или дрона по имени
|
func (o *Modulation) UpdateObject(name string, obj_type int, coords [3]int, params map[string]interface{}) {
|
||||||
func (o *Modulation) UpdateObject(name string, obj_type int, coords [3]int, params map[string]string) {
|
|
||||||
if obj_type != 1 && obj_type != 2 {
|
if obj_type != 1 && obj_type != 2 {
|
||||||
// Значит объект не станция или не дрон
|
// Значит объект не станция или не дрон
|
||||||
return
|
return
|
||||||
|
@ -47,6 +47,7 @@ func NewDBConnection() error {
|
|||||||
func (db *GormDbInstance) AutoMigrate() error {
|
func (db *GormDbInstance) AutoMigrate() error {
|
||||||
return DbDriver.DB.AutoMigrate(
|
return DbDriver.DB.AutoMigrate(
|
||||||
database.User{},
|
database.User{},
|
||||||
|
database.Logs{},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
func (db *GormDbInstance) AutoMakeSuperUser() error {
|
func (db *GormDbInstance) AutoMakeSuperUser() error {
|
||||||
@ -68,6 +69,13 @@ func (db *GormDbInstance) AutoMakeSuperUser() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *GormDbInstance) RegisterLog(type_log int, text_log string) error {
|
||||||
|
if type_log > 0 && type_log < 10 {
|
||||||
|
db.DB.Create(&database.Logs{LogType: type_log, Log: text_log})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (db *GormDbInstance) GetUserByName(name string) (*database.User, error) {
|
func (db *GormDbInstance) GetUserByName(name string) (*database.User, error) {
|
||||||
// Find user by name
|
// Find user by name
|
||||||
var user database.User
|
var user database.User
|
||||||
|
69
src/server/internal/server/handlers/logs/logs_handler.go
Normal file
69
src/server/internal/server/handlers/logs/logs_handler.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package logs_handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
database_entity "moxitech/dns/entity/database"
|
||||||
|
"moxitech/dns/internal/database"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetLogs(c *fiber.Ctx) error {
|
||||||
|
var logs []database_entity.Logs
|
||||||
|
|
||||||
|
typeLogs := c.Query("type")
|
||||||
|
if typeLogs == "" {
|
||||||
|
typeLogs = "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
countLogs := c.Query("count")
|
||||||
|
var logsCountParsed int
|
||||||
|
var err error
|
||||||
|
if countLogs != "" {
|
||||||
|
logsCountParsed, err = strconv.Atoi(countLogs)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
|
"error": "Invalid count parameter",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
db := database.DbDriver.DB // GORM DB instance
|
||||||
|
query := db.Model(&database_entity.Logs{})
|
||||||
|
|
||||||
|
if typeLogs != "*" {
|
||||||
|
query = query.Where("type = ?", typeLogs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if logsCountParsed > 0 {
|
||||||
|
query = query.Limit(logsCountParsed)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := query.Find(&logs).Error; err != nil {
|
||||||
|
if err == gorm.ErrRecordNotFound {
|
||||||
|
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
|
||||||
|
"error": "No logs found",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": "Failed to retrieve logs",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(logs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteAllLogs(c *fiber.Ctx) error {
|
||||||
|
db := database.DbDriver.DB // GORM DB instance
|
||||||
|
|
||||||
|
if err := db.Exec("DELETE FROM logs").Error; err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": "Failed to delete logs",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(fiber.Map{
|
||||||
|
"message": "All logs have been deleted successfully",
|
||||||
|
})
|
||||||
|
}
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"moxitech/dns/entity/dto"
|
"moxitech/dns/entity/dto"
|
||||||
"moxitech/dns/internal/server/handlers/authorization"
|
"moxitech/dns/internal/server/handlers/authorization"
|
||||||
|
logs_handler "moxitech/dns/internal/server/handlers/logs"
|
||||||
sim_queue "moxitech/dns/package/simulation"
|
sim_queue "moxitech/dns/package/simulation"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -47,6 +48,9 @@ func SpawnServer() error {
|
|||||||
// GET http://localhost:8080/simulations/from/history
|
// GET http://localhost:8080/simulations/from/history
|
||||||
// app.Get("/simulations/from/history", authorization.AuthUser)
|
// app.Get("/simulations/from/history", authorization.AuthUser)
|
||||||
|
|
||||||
|
// GET http://localhost:8080/system/logs
|
||||||
|
app.Get("/system/logs", logs_handler.GetLogs)
|
||||||
|
|
||||||
// GET http://localhost:8080/get/server/state
|
// GET http://localhost:8080/get/server/state
|
||||||
app.Get("/get/server/state", GetServerState)
|
app.Get("/get/server/state", GetServerState)
|
||||||
// WebSocket маршрут
|
// WebSocket маршрут
|
||||||
@ -102,7 +106,7 @@ func CreateOrConnectSocket(c *websocket.Conn) {
|
|||||||
// Читаем сообщения от клиента
|
// Читаем сообщения от клиента
|
||||||
messageType, msg, err := c.ReadMessage()
|
messageType, msg, err := c.ReadMessage()
|
||||||
if messageType != websocket.TextMessage {
|
if messageType != websocket.TextMessage {
|
||||||
err = c.WriteMessage(websocket.BinaryMessage, []byte("PLS USE JSON TEXT STRUCTURE!"))
|
err = c.WriteMessage(websocket.BinaryMessage, []byte("{\"error\":\"Use text instead\" }"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error writing message: %v\n", err)
|
fmt.Printf("Error writing message: %v\n", err)
|
||||||
break
|
break
|
||||||
@ -116,7 +120,7 @@ func CreateOrConnectSocket(c *websocket.Conn) {
|
|||||||
fmt.Printf("Received message from user %s: %s\n", userToken, msg)
|
fmt.Printf("Received message from user %s: %s\n", userToken, msg)
|
||||||
err, ok = room.WebsocketAction(msg)
|
err, ok = room.WebsocketAction(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = c.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("%v", err)))
|
err = c.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("{\"error\": \"%v\"}", err)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error writing message: %v\n", err)
|
fmt.Printf("Error writing message: %v\n", err)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"moxitech/dns/entity/websocket"
|
"moxitech/dns/entity/websocket"
|
||||||
|
"moxitech/dns/internal/database"
|
||||||
"moxitech/dns/package/math/simulator"
|
"moxitech/dns/package/math/simulator"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -98,11 +99,12 @@ func (room *WebsocketRoom) DeleteMapObjectRequest(message websocket.SignalMessag
|
|||||||
// InsertObject вставляет базовые случайные данные в симуляцию
|
// InsertObject вставляет базовые случайные данные в симуляцию
|
||||||
func (room *WebsocketRoom) InsertObject(message websocket.SignalMessage) error {
|
func (room *WebsocketRoom) InsertObject(message websocket.SignalMessage) error {
|
||||||
// Тип объекта (тип сигнала)
|
// Тип объекта (тип сигнала)
|
||||||
type_obj := message.Signal
|
typeObj := message.Signal
|
||||||
|
|
||||||
// Определяем структуру для данных в поле `data`
|
// Определяем структуру для данных в поле `data`
|
||||||
var parsedData struct {
|
var parsedData struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Params map[string]string `json:"params"`
|
Params map[string]interface{} `json:"params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Парсим `data` в структуру
|
// Парсим `data` в структуру
|
||||||
@ -111,43 +113,44 @@ func (room *WebsocketRoom) InsertObject(message websocket.SignalMessage) error {
|
|||||||
return fmt.Errorf("[insert] error parsing data: %v", err)
|
return fmt.Errorf("[insert] error parsing data: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("st 1")
|
|
||||||
// Получаем значения name и params
|
// Получаем значения name и params
|
||||||
name := parsedData.Name
|
name := parsedData.Name
|
||||||
params := parsedData.Params
|
params := parsedData.Params
|
||||||
|
|
||||||
// Проверяем наличие координат в параметрах
|
// Проверяем наличие координат в параметрах
|
||||||
if params["coords"] == "" {
|
coordsValue, ok := params["coords"].(string)
|
||||||
return fmt.Errorf("[insert] coords is empty")
|
if !ok || coordsValue == "" {
|
||||||
|
return fmt.Errorf("[insert] coords is missing or empty")
|
||||||
}
|
}
|
||||||
fmt.Println("st 2")
|
|
||||||
|
|
||||||
// Разделяем строку координат на отдельные элементы
|
// Разделяем строку координат на отдельные элементы
|
||||||
coordinateStrings := strings.Split(params["coords"], ",")
|
coordinateStrings := strings.Split(coordsValue, ",")
|
||||||
|
|
||||||
// Инициализируем массив для хранения координат
|
// Инициализируем массив для хранения координат
|
||||||
coordinates := make([]int, len(coordinateStrings))
|
coordinates := make([]int, len(coordinateStrings))
|
||||||
fmt.Println("st 3")
|
|
||||||
|
|
||||||
// Преобразуем каждую координату в целое число
|
// Преобразуем каждую координату в целое число
|
||||||
for i, coord := range coordinateStrings {
|
for i, coord := range coordinateStrings {
|
||||||
parsedCoord, err := strconv.Atoi(strings.TrimSpace(coord))
|
parsedCoord, err := strconv.Atoi(strings.TrimSpace(coord))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(fmt.Errorf("[insert] invalid coordinate: %s", coord))
|
|
||||||
return fmt.Errorf("[insert] invalid coordinate: %s", coord)
|
return fmt.Errorf("[insert] invalid coordinate: %s", coord)
|
||||||
}
|
}
|
||||||
coordinates[i] = parsedCoord
|
coordinates[i] = parsedCoord
|
||||||
}
|
}
|
||||||
fmt.Println("st 4")
|
|
||||||
|
|
||||||
params["coords"] = ""
|
// Проверяем, что количество координат соответствует ожидаемому (например, 3 координаты)
|
||||||
|
if len(coordinates) != 3 {
|
||||||
|
return fmt.Errorf("[insert] invalid number of coordinates: expected 3, got %d", len(coordinates))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обновляем значение координат в параметрах
|
||||||
|
params["coords"] = [3]int{coordinates[0], coordinates[1], coordinates[2]}
|
||||||
|
|
||||||
// Добавляем объект в комнату
|
// Добавляем объект в комнату
|
||||||
roomsMutex.Lock()
|
roomsMutex.Lock()
|
||||||
defer roomsMutex.Unlock()
|
defer roomsMutex.Unlock()
|
||||||
fmt.Println("st 5")
|
|
||||||
room.Modulation.AddObject(name, type_obj, [3]int{coordinates[0], coordinates[1], coordinates[2]}, params)
|
|
||||||
|
|
||||||
return nil
|
return room.Modulation.AddObject(name, typeObj, [3]int{coordinates[0], coordinates[1], coordinates[2]}, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateObjectRequest вставляет базовые случайные данные в симуляцию
|
// UpdateObjectRequest вставляет базовые случайные данные в симуляцию
|
||||||
@ -156,8 +159,8 @@ func (room *WebsocketRoom) UpdateObjectRequest(message websocket.SignalMessage)
|
|||||||
type_obj := message.Signal - 20
|
type_obj := message.Signal - 20
|
||||||
// Определяем структуру для данных в поле `data`
|
// Определяем структуру для данных в поле `data`
|
||||||
var parsedData struct {
|
var parsedData struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Params map[string]string `json:"params"`
|
Params map[string]interface{} `json:"params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Парсим `data` в структуру
|
// Парсим `data` в структуру
|
||||||
@ -169,14 +172,14 @@ func (room *WebsocketRoom) UpdateObjectRequest(message websocket.SignalMessage)
|
|||||||
// Получаем значения name и params
|
// Получаем значения name и params
|
||||||
name := parsedData.Name
|
name := parsedData.Name
|
||||||
params := parsedData.Params
|
params := parsedData.Params
|
||||||
|
|
||||||
// Проверяем наличие координат в параметрах
|
// Проверяем наличие координат в параметрах
|
||||||
if params["coords"] == "" {
|
coordsValue, ok := params["coords"].(string)
|
||||||
return fmt.Errorf("[insert] coords is empty")
|
if !ok || coordsValue == "" {
|
||||||
|
return fmt.Errorf("[insert] coords is missing or empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Разделяем строку координат на отдельные элементы
|
// Разделяем строку координат на отдельные элементы
|
||||||
coordinateStrings := strings.Split(params["coords"], ",")
|
coordinateStrings := strings.Split(coordsValue, ",")
|
||||||
|
|
||||||
// Инициализируем массив для хранения координат
|
// Инициализируем массив для хранения координат
|
||||||
coordinates := make([]int, len(coordinateStrings))
|
coordinates := make([]int, len(coordinateStrings))
|
||||||
@ -189,7 +192,15 @@ func (room *WebsocketRoom) UpdateObjectRequest(message websocket.SignalMessage)
|
|||||||
}
|
}
|
||||||
coordinates[i] = parsedCoord
|
coordinates[i] = parsedCoord
|
||||||
}
|
}
|
||||||
params["coords"] = ""
|
|
||||||
|
// Проверяем, что количество координат соответствует ожидаемому (например, 3 координаты)
|
||||||
|
if len(coordinates) != 3 {
|
||||||
|
return fmt.Errorf("[insert] invalid number of coordinates: expected 3, got %d", len(coordinates))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обновляем значение координат в параметрах
|
||||||
|
params["coords"] = [3]int{coordinates[0], coordinates[1], coordinates[2]}
|
||||||
|
|
||||||
// Добавляем объект в комнату
|
// Добавляем объект в комнату
|
||||||
roomsMutex.Lock()
|
roomsMutex.Lock()
|
||||||
defer roomsMutex.Unlock()
|
defer roomsMutex.Unlock()
|
||||||
@ -265,15 +276,15 @@ func (room *WebsocketRoom) WebsocketAction(message []byte) (error, bool) {
|
|||||||
fmt.Printf("[WebsocketAction] %v", err)
|
fmt.Printf("[WebsocketAction] %v", err)
|
||||||
return fmt.Errorf("error parsing occured: %v \n waiting for signal struct", err), false
|
return fmt.Errorf("error parsing occured: %v \n waiting for signal struct", err), false
|
||||||
}
|
}
|
||||||
fmt.Println("Run collector")
|
|
||||||
room.UpdateGroupUptime()
|
room.UpdateGroupUptime()
|
||||||
switch Signal.Signal {
|
switch Signal.Signal {
|
||||||
case 0:
|
case 0:
|
||||||
|
fmt.Println("Uptime updated")
|
||||||
room.UpdateGroupUptime()
|
room.UpdateGroupUptime()
|
||||||
return nil, false
|
return nil, false
|
||||||
case 1:
|
case 1:
|
||||||
room.InsertObject(Signal)
|
fmt.Println("Начата вставка объекта")
|
||||||
return nil, true
|
return room.InsertObject(Signal), true
|
||||||
case 2:
|
case 2:
|
||||||
fmt.Println("Начата вставка объекта")
|
fmt.Println("Начата вставка объекта")
|
||||||
room.InsertObject(Signal)
|
room.InsertObject(Signal)
|
||||||
@ -300,7 +311,9 @@ func (room *WebsocketRoom) WebsocketAction(message []byte) (error, bool) {
|
|||||||
// SYNC SIGNAL
|
// SYNC SIGNAL
|
||||||
case 100:
|
case 100:
|
||||||
fmt.Println("Запуск симуляции : ", Signal)
|
fmt.Println("Запуск симуляции : ", Signal)
|
||||||
|
database.DbDriver.RegisterLog(1, "Симуляция инициирована пользователем")
|
||||||
room.RunSimulation(Signal)
|
room.RunSimulation(Signal)
|
||||||
|
|
||||||
case 101:
|
case 101:
|
||||||
// room.StoreMongo(Signal)
|
// room.StoreMongo(Signal)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user