server & frontend update :: signaling
This commit is contained in:
parent
a3d344ee2f
commit
047a3ffd5c
@ -71,6 +71,10 @@ services:
|
|||||||
context: ./src/frontend
|
context: ./src/frontend
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
env_file: ".env"
|
env_file: ".env"
|
||||||
|
volumes:
|
||||||
|
- ./src/frontend:/app
|
||||||
|
working_dir: /app
|
||||||
|
command: ["npm", "start"]
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
networks:
|
networks:
|
||||||
|
@ -11,7 +11,7 @@ COPY package*.json ./
|
|||||||
RUN npm install
|
RUN npm install
|
||||||
|
|
||||||
# Bundle app source
|
# Bundle app source
|
||||||
COPY . .
|
# COPY . .
|
||||||
|
|
||||||
# Make port 3000 available to the world outside this container
|
# Make port 3000 available to the world outside this container
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
@ -12,6 +12,7 @@ import Docs from './pages/Docs'; // Импортируем страницу п
|
|||||||
import './css/bootstrap-5.3.3-dist/css/bootstrap.min.css';
|
import './css/bootstrap-5.3.3-dist/css/bootstrap.min.css';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import "bootstrap-icons/font/bootstrap-icons.css";
|
import "bootstrap-icons/font/bootstrap-icons.css";
|
||||||
|
import {removeCustomCookie} from './Services/Local'
|
||||||
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
|
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
@ -20,6 +21,7 @@ const App = () => {
|
|||||||
|
|
||||||
// Функция для выхода из системы
|
// Функция для выхода из системы
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
|
removeCustomCookie("userToken")
|
||||||
setIsLoggedIn(false);
|
setIsLoggedIn(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -88,8 +88,9 @@ const useWebsocketConnection = (userToken, roomHash) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Функция для отправки данных в WebSocket
|
// Функция для отправки данных в WebSocket
|
||||||
const sendMessage = (message) => {
|
const sendMessage = async (message) => {
|
||||||
if (socketRef.current && socketRef.current.readyState === WebSocket.OPEN) {
|
if (socketRef.current && socketRef.current.readyState === WebSocket.OPEN) {
|
||||||
|
console.log(JSON.stringify(message))
|
||||||
socketRef.current.send(JSON.stringify(message));
|
socketRef.current.send(JSON.stringify(message));
|
||||||
} else {
|
} else {
|
||||||
console.error('WebSocket is not open. Unable to send message:', message);
|
console.error('WebSocket is not open. Unable to send message:', message);
|
||||||
@ -99,4 +100,42 @@ const useWebsocketConnection = (userToken, roomHash) => {
|
|||||||
return { websocketStruct, sendMessage };
|
return { websocketStruct, sendMessage };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const spawnJsonSignal = (signal, name, coords) => {
|
||||||
|
if (![1, 2].includes(signal)) {
|
||||||
|
throw new Error('Invalid signal value. Expected 1 or 2.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof name !== 'string' || !name.trim()) {
|
||||||
|
throw new Error('Invalid name. Expected a non-empty string.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
signal,
|
||||||
|
data: {
|
||||||
|
name,
|
||||||
|
params: {
|
||||||
|
coords,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DeleteSignal = (name) => {
|
||||||
|
const signal = 3;
|
||||||
|
|
||||||
|
if (typeof name !== 'string' || !name.trim()) {
|
||||||
|
throw new Error('Invalid name. Expected a non-empty string.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
signal,
|
||||||
|
data: {
|
||||||
|
name,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default useWebsocketConnection;
|
export default useWebsocketConnection;
|
@ -1,6 +1,6 @@
|
|||||||
.user-account {
|
.user-account {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background-color: #f4f4f4;
|
background-color: #3cafb7;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
@ -6,16 +6,15 @@ import BaseStation from './model/BaseStation';
|
|||||||
import HeightPoint from './model/HeightPoint';
|
import HeightPoint from './model/HeightPoint';
|
||||||
import { RandomHeightPoint } from './helpers/generateRandomHeightPoints'
|
import { RandomHeightPoint } from './helpers/generateRandomHeightPoints'
|
||||||
import ModalWindow from './components/Modal/Modal';
|
import ModalWindow from './components/Modal/Modal';
|
||||||
import useWebsocketConnection from '../Services/WebsocketHook';
|
import { getCustomCookie } from '../Services/Local';
|
||||||
|
import useWebsocketConnection, { DeleteSignal, spawnJsonSignal } from '../Services/WebsocketHook';
|
||||||
import './Dashboard.css';
|
import './Dashboard.css';
|
||||||
|
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
const mountRef = useRef(null); // Указатель монтирования
|
const mountRef = useRef(null); // Указатель монтирования
|
||||||
const sceneRef = useRef(null); // Указатель на сцену
|
const sceneRef = useRef(null); // Указатель на сцену
|
||||||
const mouse = new THREE.Vector2(); // Мышка
|
const {websocketStruct, sendMessage} = useWebsocketConnection(getCustomCookie("userToken"), 1);
|
||||||
const {websocketStruct, sendMessage} = useWebsocketConnection(1, 1);
|
|
||||||
|
|
||||||
const [heightData, setHeightData] = useState(RandomHeightPoint()); // Высоты
|
const [heightData, setHeightData] = useState(RandomHeightPoint()); // Высоты
|
||||||
const [formData, setFormData] = useState({ x: '', y: '', height: '' }); // Форма для ввода данных карты
|
const [formData, setFormData] = useState({ x: '', y: '', height: '' }); // Форма для ввода данных карты
|
||||||
const [mouseState, setMouseState] = useState({ x: 0, y: 0, z: 0 }); // Форма для ввода данных карты
|
const [mouseState, setMouseState] = useState({ x: 0, y: 0, z: 0 }); // Форма для ввода данных карты
|
||||||
@ -38,6 +37,45 @@ const Dashboard = () => {
|
|||||||
baseStationField1: "",
|
baseStationField1: "",
|
||||||
baseStationField2: ""
|
baseStationField2: ""
|
||||||
});
|
});
|
||||||
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
|
const handleSearch = () => {
|
||||||
|
const foundDrone = drones.find(drone => drone.name.toLowerCase() === searchTerm.toLowerCase());
|
||||||
|
const foundBaseStation = baseStation.find(base => base.name.toLowerCase() === searchTerm.toLowerCase());
|
||||||
|
|
||||||
|
if (foundDrone) {
|
||||||
|
// Выделяем найденный дрон
|
||||||
|
if (selectedDrone) {
|
||||||
|
selectedDrone.getObject().traverse((child) => {
|
||||||
|
if (child.isMesh) {
|
||||||
|
child.material.color.set(0xff0000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
foundDrone.getObject().traverse((child) => {
|
||||||
|
if (child.isMesh) {
|
||||||
|
child.material.color.set(0x00ff00);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setSelectedDrone(foundDrone);
|
||||||
|
} else if (foundBaseStation) {
|
||||||
|
// Выделяем найденную базу
|
||||||
|
if (selectedBaseStation) {
|
||||||
|
selectedBaseStation.getObject().traverse((child) => {
|
||||||
|
if (child.isMesh) {
|
||||||
|
child.material.color.set(0x0000ff);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
foundBaseStation.getObject().traverse((child) => {
|
||||||
|
if (child.isMesh) {
|
||||||
|
child.material.color.set(0x00ff00);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setSelectedBaseStation(foundBaseStation);
|
||||||
|
} else {
|
||||||
|
alert("Объект с указанным именем не найден");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleTypeChange = (type) => {
|
const handleTypeChange = (type) => {
|
||||||
@ -45,14 +83,8 @@ const Dashboard = () => {
|
|||||||
setFormData({ ...formData, type });
|
setFormData({ ...formData, type });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSendMessage = () => {
|
const handleDeleteSignal = (name) => {
|
||||||
const message = {
|
sendMessage(DeleteSignal(name));
|
||||||
signal: 0,
|
|
||||||
data: {
|
|
||||||
key: 'value'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
sendMessage(message);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -82,11 +114,40 @@ const Dashboard = () => {
|
|||||||
isModalSearchOpen: false,
|
isModalSearchOpen: false,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (websocketStruct) {
|
if (websocketStruct && websocketStruct.modulation) {
|
||||||
console.log('Received WebSocket Data:', websocketStruct);
|
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]);
|
}, [websocketStruct]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
if (!mountRef.current) return;
|
if (!mountRef.current) return;
|
||||||
@ -94,7 +155,7 @@ const Dashboard = () => {
|
|||||||
let height = mountRef.current.clientHeight;
|
let height = mountRef.current.clientHeight;
|
||||||
// Создаем объект сцены
|
// Создаем объект сцены
|
||||||
const scene = new THREE.Scene();
|
const scene = new THREE.Scene();
|
||||||
|
scene.background = new THREE.Color(0xffffff);
|
||||||
// Сохраняем ссылку на сцену
|
// Сохраняем ссылку на сцену
|
||||||
sceneRef.current = scene;
|
sceneRef.current = scene;
|
||||||
// Создаем камеру
|
// Создаем камеру
|
||||||
@ -140,7 +201,7 @@ const Dashboard = () => {
|
|||||||
mesh.rotation.x = -Math.PI / 2;
|
mesh.rotation.x = -Math.PI / 2;
|
||||||
scene.add(mesh);
|
scene.add(mesh);
|
||||||
|
|
||||||
const axesHelper = new THREE.AxesHelper(10);
|
const axesHelper = new THREE.AxesHelper(100);
|
||||||
scene.add(axesHelper);
|
scene.add(axesHelper);
|
||||||
|
|
||||||
const controls = new OrbitControls(camera, renderer.domElement);
|
const controls = new OrbitControls(camera, renderer.domElement);
|
||||||
@ -151,34 +212,68 @@ const Dashboard = () => {
|
|||||||
scene.add(light);
|
scene.add(light);
|
||||||
// Обработка кликов на сцене
|
// Обработка кликов на сцене
|
||||||
const handleClick = (event) => {
|
const handleClick = (event) => {
|
||||||
|
// Рассчитываем координаты мыши в нормализованной системе координат и округляем до целого числа
|
||||||
|
const mouse = new THREE.Vector2();
|
||||||
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
|
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
|
||||||
console.log('Mouse coordinates:', mouse);
|
console.log('Mouse coordinates:', mouse);
|
||||||
|
|
||||||
|
// Создаем объект Raycaster для проверки пересечений
|
||||||
const raycaster = new THREE.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);
|
raycaster.setFromCamera(mouse, camera);
|
||||||
|
|
||||||
|
// Проверяем пересечения с объектами дронов
|
||||||
const intersects = raycaster.intersectObjects(drones.map(drone => drone.getObject()), true);
|
const intersects = raycaster.intersectObjects(drones.map(drone => drone.getObject()), true);
|
||||||
console.log('Intersections:', intersects)
|
console.log('Intersections:', intersects);
|
||||||
console.log('Drones:', drones.map(drone => [drone.getObject(), drone.getObject().position, drone.name]))
|
console.log('Drones:', drones.map(drone => [drone.getObject(), drone.getObject().position, drone.name]));
|
||||||
|
|
||||||
if (intersects.length > 0) {
|
if (intersects.length > 0) {
|
||||||
const selected = intersects[0].object;
|
const selected = intersects[0].object;
|
||||||
console.log('Clicked on:', selected); // Лог для проверки объекта
|
console.log('Clicked on:', selected); // Лог для проверки объекта
|
||||||
const drone = drones.find(drone => drone.getObject().children[0] === selected);
|
|
||||||
|
// Поиск дрона рекурсивно
|
||||||
|
const drone = drones.find(drone => containsObjectRecursively(drone.getObject(), selected));
|
||||||
|
|
||||||
if (drone) {
|
if (drone) {
|
||||||
|
// Сбрасываем цвет предыдущего выбранного дрона
|
||||||
if (selectedDrone) {
|
if (selectedDrone) {
|
||||||
selectedDrone.getObject().children[0].material.color.set(0xff0000);
|
drone.getObject().visible = true;
|
||||||
|
// selectedDrone.getObject().material.color.set(0xff0000);
|
||||||
}
|
}
|
||||||
drone.getObject().children[0].material.color.set(0xff1111);
|
// Устанавливаем цвет выбранного дрона
|
||||||
|
// drone.getObject().material.color.set(0xff1111);
|
||||||
|
drone.getObject().visible = false;
|
||||||
|
console.log(drone);
|
||||||
setSelectedDrone(drone);
|
setSelectedDrone(drone);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Сбрасываем выбор, если ни один дрон не был выбран
|
||||||
if (selectedDrone) {
|
if (selectedDrone) {
|
||||||
selectedDrone.getObject().children[0].material.color.set(0xff0000);
|
// selectedDrone.getObject().material.color.set(0xff0000);
|
||||||
|
selectedDrone .getObject().visible = true;
|
||||||
|
|
||||||
setSelectedDrone(null);
|
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) => {
|
const handleMouseMove = (event) => {
|
||||||
let x = event.x;
|
let x = event.x;
|
||||||
let y = event.y;
|
let y = event.y;
|
||||||
@ -226,16 +321,31 @@ const Dashboard = () => {
|
|||||||
// Создаем новый материал для каждого дрона
|
// Создаем новый материал для каждого дрона
|
||||||
drone.setPosition(Math.random() * 20 - 10, 20, Math.random() * 20 - 10);
|
drone.setPosition(Math.random() * 20 - 10, 20, Math.random() * 20 - 10);
|
||||||
setDrones((prevDrones) => [...prevDrones, drone]);
|
setDrones((prevDrones) => [...prevDrones, drone]);
|
||||||
console.log(drones.map(drone => drone.getObject().children[0]));
|
console.log(drones.map(drone => drone.getObject()));
|
||||||
|
let json_signal = spawnJsonSignal(1, current / 1000 + "", "" + Math.round(drone.getObject().position.x) + "," + Math.round(drone.getObject().position.y) + "," + Math.round(drone.getObject().position.z) + "");
|
||||||
|
sendMessage(json_signal)
|
||||||
sceneRef.current.add(drone.getObject());
|
sceneRef.current.add(drone.getObject());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Добавление дрона в сцену
|
// Добавление дрона в сцену
|
||||||
|
// Добавление базовой станции в сцену
|
||||||
const handleAddBaseStation = () => {
|
const handleAddBaseStation = () => {
|
||||||
if (sceneRef.current) {
|
if (sceneRef.current) {
|
||||||
const current = Date.now();
|
const current = Date.now();
|
||||||
const base = new BaseStation(current / 1000);
|
const base = new BaseStation(current / 1000);
|
||||||
base.setPosition(Math.random() * 20 - 10, 20, Math.random() * 20 - 10);
|
|
||||||
|
// Выбираем случайные координаты X и Z
|
||||||
|
const x = Math.random() * 20 - 10;
|
||||||
|
const z = Math.random() * 20 - 10;
|
||||||
|
|
||||||
|
// Находим точку высоты для установки базовой станции на карту
|
||||||
|
const heightPoint = heightData.find(point => point.x === Math.round(x) && point.y === Math.round(z));
|
||||||
|
console.log(heightPoint)
|
||||||
|
const y = heightPoint ? heightPoint.height : 0;
|
||||||
|
|
||||||
|
// Устанавливаем позицию базовой станции на основании высоты карты
|
||||||
|
base.setPosition(x, y, z);
|
||||||
|
|
||||||
setBaseStation((prev) => [...prev, base]);
|
setBaseStation((prev) => [...prev, base]);
|
||||||
console.log(baseStation.map(b => b.getObject().children[0]));
|
console.log(baseStation.map(b => b.getObject().children[0]));
|
||||||
sceneRef.current.add(base.getObject());
|
sceneRef.current.add(base.getObject());
|
||||||
@ -449,15 +559,20 @@ const Dashboard = () => {
|
|||||||
|
|
||||||
<ModalWindow isOpen={modals.isModalSearchOpen} onClose={closeAllModals}>
|
<ModalWindow isOpen={modals.isModalSearchOpen} onClose={closeAllModals}>
|
||||||
<h2>Поиск</h2>
|
<h2>Поиск</h2>
|
||||||
<input type="text" placeholder="Введите имя" />
|
<input
|
||||||
<button onClick={() => alert('Добавлено')}>Выбор</button>
|
type="text"
|
||||||
|
placeholder="Введите имя"
|
||||||
|
value={searchTerm}
|
||||||
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
|
/>
|
||||||
|
<button onClick={handleSearch}>Найти</button>
|
||||||
</ModalWindow>
|
</ModalWindow>
|
||||||
|
|
||||||
<ModalWindow isOpen={modals.isModalDeleteOpen} onClose={closeAllModals}>
|
<ModalWindow isOpen={modals.isModalDeleteOpen} onClose={closeAllModals}>
|
||||||
<h2>Удаление</h2>
|
<h2>Удаление</h2>
|
||||||
<h2>Вы точно хотите удалить объект X?</h2>
|
<h2>Вы точно хотите удалить объект X?</h2>
|
||||||
<button onClick={closeAllModals}>Отмена</button>
|
<button onClick={closeAllModals}>Отмена</button>
|
||||||
<button onClick={() => handleSendMessage() }>Удалить</button>
|
<button onClick={() => handleDeleteSignal(1) }>Удалить</button>
|
||||||
</ModalWindow>
|
</ModalWindow>
|
||||||
|
|
||||||
<ModalWindow isOpen={modals.isModalOpen} onClose={closeAllModals}>
|
<ModalWindow isOpen={modals.isModalOpen} onClose={closeAllModals}>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { setCustomCookie, getCustomCookie } from '../Services/Local'
|
import { setCustomCookie, getCustomCookie } from '../Services/Local'
|
||||||
|
import { giveMeServerAddress } from '../Services/Server'
|
||||||
|
|
||||||
import '../Login.scss';
|
import '../Login.scss';
|
||||||
|
|
||||||
@ -13,16 +14,37 @@ const Login = ({ onLogin }) => {
|
|||||||
onLogin();
|
onLogin();
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
const handleSubmit = (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
// Simple login/password check
|
|
||||||
if (username === 'admin' && password === 'admin') {
|
|
||||||
// TODO :: CHANGE
|
|
||||||
setCustomCookie('userToken', '12345', { expires: 7 }); // Куки с истечением через 7 дней
|
|
||||||
onLogin(); // Call function on successful login
|
|
||||||
|
|
||||||
} else {
|
try {
|
||||||
setError('Неверный логин или пароль');
|
// Отправляем запрос на сервер
|
||||||
|
const response = await fetch(giveMeServerAddress() + "/auth/"+ username +"/" + password, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ username, password })
|
||||||
|
});
|
||||||
|
|
||||||
|
// Проверяем статус ответа
|
||||||
|
if (!response.ok) {
|
||||||
|
// Если статус не 200, ничего не делаем
|
||||||
|
setError('Ошибка авторизации. Пожалуйста, попробуйте снова.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Парсим тело ответа в формате JSON
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
// Устанавливаем userToken из тела ответа
|
||||||
|
setCustomCookie('userToken', data.userid, { expires: 7 });
|
||||||
|
|
||||||
|
// Вызываем функцию после успешного входа в систему
|
||||||
|
onLogin();
|
||||||
|
} catch (error) {
|
||||||
|
// Обработка ошибок сети
|
||||||
|
setError('Произошла ошибка. Пожалуйста, попробуйте снова позже.');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ const Main = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getSimulations();
|
getSimulations();
|
||||||
setCustomCookie('userToken', '12345', { expires: 7 }); // Куки с истечением через 7 дней
|
|
||||||
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import '../UserAccount.scss';
|
import '../UserAccount.scss';
|
||||||
|
import {getCustomCookie} from '../Services/Local';
|
||||||
const UserAccount = () => {
|
const UserAccount = () => {
|
||||||
const [userData, setUserData] = useState({
|
const [userData, setUserData] = useState({
|
||||||
username: 'Никита Николаевич',
|
username: 'Никита Николаевич',
|
||||||
@ -10,6 +10,15 @@ const UserAccount = () => {
|
|||||||
|
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
const [formData, setFormData] = useState(userData);
|
const [formData, setFormData] = useState(userData);
|
||||||
|
const [debug, setDebug] = useState(false)
|
||||||
|
|
||||||
|
const enableDebug = () => {
|
||||||
|
if (debug){
|
||||||
|
setDebug(false)
|
||||||
|
} else {
|
||||||
|
setDebug(true)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleChange = (e) => {
|
const handleChange = (e) => {
|
||||||
const { name, value } = e.target;
|
const { name, value } = e.target;
|
||||||
@ -77,6 +86,18 @@ const UserAccount = () => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<button className="btn btn-info" onClick={() => enableDebug()}>
|
||||||
|
Turn Debug Mode
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{debug ? <p>
|
||||||
|
debug:
|
||||||
|
UserToken: {getCustomCookie("userToken")}
|
||||||
|
</p>
|
||||||
|
:
|
||||||
|
<p></p>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -15,6 +15,12 @@ class Drone {
|
|||||||
}, undefined, (error) => {
|
}, undefined, (error) => {
|
||||||
console.error("Ошибка загрузки GLTF:", error);
|
console.error("Ошибка загрузки GLTF:", error);
|
||||||
});
|
});
|
||||||
|
// Создаем красный куб вместо GLB модели
|
||||||
|
// const geometry = new THREE.BoxGeometry(2, 2, 2);
|
||||||
|
// const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
|
||||||
|
// const cube = new THREE.Mesh(geometry, material);
|
||||||
|
// cube.scale.set(scale, scale, scale);
|
||||||
|
// this.object.add(cube);
|
||||||
}
|
}
|
||||||
|
|
||||||
setPosition(x, y, z) {
|
setPosition(x, y, z) {
|
||||||
|
@ -86,6 +86,7 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
database.Instance = database.NewDbConnection()
|
||||||
err = server.SpawnServer()
|
err = server.SpawnServer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package websocket
|
package websocket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"moxitech/dns/package/math/simulator"
|
"moxitech/dns/package/math/simulator"
|
||||||
"moxitech/dns/package/utils/randomizer"
|
"moxitech/dns/package/utils/randomizer"
|
||||||
"time"
|
"time"
|
||||||
@ -37,8 +38,15 @@ func (o *Modulation) DeleteObjectIfExists(name string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (o *Modulation) MirrorPayloadToSimulationStruct() {
|
|
||||||
|
|
||||||
|
// MirrorPayloadToSimulationStruct - вернет фулл копию симуляции
|
||||||
|
func (o *Modulation) MirrorPayloadToSimulationStruct() Modulation {
|
||||||
|
shadow_sim_copy := Modulation{
|
||||||
|
Map: o.Map,
|
||||||
|
Objects: o.Objects,
|
||||||
|
Ts_update: o.Ts_update,
|
||||||
|
}
|
||||||
|
return shadow_sim_copy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Modulation) RunSimulator() {
|
func (o *Modulation) RunSimulator() {
|
||||||
@ -59,6 +67,8 @@ func (o *Modulation) RunSimulator() {
|
|||||||
// HeightData: heightData,
|
// HeightData: heightData,
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
// ? mapObj := o.Map
|
||||||
|
|
||||||
// // Определяем дронов
|
// // Определяем дронов
|
||||||
//
|
//
|
||||||
// drones := []*simulator.Drone{
|
// drones := []*simulator.Drone{
|
||||||
@ -128,6 +138,7 @@ func (o *Modulation) AddObject(name string, obj_type int, coords [3]int, params
|
|||||||
// Значит объект не станция или не дрон
|
// Значит объект не станция или не дрон
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
fmt.Println(name, obj_type, coords, params)
|
||||||
if o.Objects == nil {
|
if o.Objects == nil {
|
||||||
o.Objects = make([]*SystemObject, 0)
|
o.Objects = make([]*SystemObject, 0)
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,12 @@ type MongoDbInstance struct {
|
|||||||
Db *mongo.Database
|
Db *mongo.Database
|
||||||
}
|
}
|
||||||
|
|
||||||
var instance *MongoDbInstance
|
var Instance *MongoDbInstance
|
||||||
var once sync.Once
|
var once sync.Once
|
||||||
|
|
||||||
// giveMeMongoConnectionString возвращает строку подключения к MongoDB
|
// giveMeMongoConnectionString возвращает строку подключения к MongoDB
|
||||||
func giveMeMongoConnectionString() string {
|
func giveMeMongoConnectionString() string {
|
||||||
return "mongodb://moxitech:moxitech@localhost:27017/" // Замените строку на свою строку подключения
|
return "mongodb://moxitech:moxitech@mongo:27017/" // Замените строку на свою строку подключения
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDbConnection создает подключение к базе данных MongoDB и возвращает единственный экземпляр MongoDbInstance
|
// NewDbConnection создает подключение к базе данных MongoDB и возвращает единственный экземпляр MongoDbInstance
|
||||||
@ -49,13 +49,13 @@ func NewDbConnection() *MongoDbInstance {
|
|||||||
|
|
||||||
log.Println("Успешное подключение к MongoDB")
|
log.Println("Успешное подключение к MongoDB")
|
||||||
|
|
||||||
instance = &MongoDbInstance{
|
Instance = &MongoDbInstance{
|
||||||
Client: client,
|
Client: client,
|
||||||
Db: client.Database(os.Getenv("MONGO_INITDB_DATABASE")),
|
Db: client.Database(os.Getenv("MONGO_INITDB_DATABASE")),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return instance
|
return Instance
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertIntoSimulations вставляет данные в коллекцию "simulations"
|
// InsertIntoSimulations вставляет данные в коллекцию "simulations"
|
||||||
|
@ -5,24 +5,42 @@ import (
|
|||||||
"moxitech/dns/internal/database"
|
"moxitech/dns/internal/database"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GET localhost:8080/auth/username?/password?
|
// POST localhost:8080/auth/username?/password?
|
||||||
func AuthUser(c *fiber.Ctx) error {
|
func AuthUser(c *fiber.Ctx) error {
|
||||||
username := c.Params("username")
|
username := c.Params("username")
|
||||||
password := c.Params("password")
|
password := c.Params("password")
|
||||||
if username == "" || password == "" {
|
if username == "" || password == "" {
|
||||||
return c.Status(501).SendString("username and password has required!")
|
return c.Status(403).JSON(fiber.Map{
|
||||||
|
"error": "username and password are required!",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := database.DbDriver.GetUserByName(username)
|
user, err := database.DbDriver.GetUserByName(username)
|
||||||
|
if err == gorm.ErrRecordNotFound {
|
||||||
|
return c.Status(404).JSON(fiber.Map{
|
||||||
|
"error": "User not found",
|
||||||
|
})
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(501).SendString(err.Error())
|
return c.Status(501).JSON(fiber.Map{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return c.Status(403).SendString(fmt.Sprintf("User with username: %v not found", username))
|
return c.Status(403).JSON(fiber.Map{
|
||||||
|
"error": fmt.Sprintf("User with username: %v not found", username),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if user.Password != password {
|
if user.Password != password {
|
||||||
return c.Status(403).SendString("Bad password!")
|
return c.Status(403).JSON(fiber.Map{
|
||||||
|
"error": "Bad password!",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return c.Status(200).SendString(fmt.Sprintf("Welcome to Drone Network Simulator server-side API! \n UserId: %v ", user.ID))
|
|
||||||
|
return c.Status(200).JSON(fiber.Map{
|
||||||
|
"userid": user.ID,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,7 @@ 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
|
||||||
@ -119,25 +120,31 @@ func (room *WebsocketRoom) InsertObject(message websocket.SignalMessage) error {
|
|||||||
if params["coords"] == "" {
|
if params["coords"] == "" {
|
||||||
return fmt.Errorf("[insert] coords is empty")
|
return fmt.Errorf("[insert] coords is empty")
|
||||||
}
|
}
|
||||||
|
fmt.Println("st 2")
|
||||||
|
|
||||||
// Разделяем строку координат на отдельные элементы
|
// Разделяем строку координат на отдельные элементы
|
||||||
coordinateStrings := strings.Split(params["coords"], ",")
|
coordinateStrings := strings.Split(params["coords"], ",")
|
||||||
|
|
||||||
// Инициализируем массив для хранения координат
|
// Инициализируем массив для хранения координат
|
||||||
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"] = ""
|
params["coords"] = ""
|
||||||
// Добавляем объект в комнату
|
// Добавляем объект в комнату
|
||||||
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)
|
room.Modulation.AddObject(name, type_obj, [3]int{coordinates[0], coordinates[1], coordinates[2]}, params)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -199,6 +206,13 @@ func (room *WebsocketRoom) InsertExampleData() {
|
|||||||
room.Modulation.SpawnExampleData()
|
room.Modulation.SpawnExampleData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InsertBasicData вставляет базовые случайные данные в симуляцию
|
||||||
|
func (room *WebsocketRoom) StoreMongo() {
|
||||||
|
roomsMutex.Lock()
|
||||||
|
defer roomsMutex.Unlock()
|
||||||
|
room.Modulation.MirrorPayloadToSimulationStruct()
|
||||||
|
}
|
||||||
|
|
||||||
// InsertMapFromJson вставляет высоты и прочие данные карты в симуляцию, по шаблону
|
// InsertMapFromJson вставляет высоты и прочие данные карты в симуляцию, по шаблону
|
||||||
func (room *WebsocketRoom) InsertMapFromJson(template string) {
|
func (room *WebsocketRoom) InsertMapFromJson(template string) {
|
||||||
// TODO
|
// TODO
|
||||||
@ -273,6 +287,8 @@ func (room *WebsocketRoom) WebsocketAction(message []byte) (error, bool) {
|
|||||||
case 33:
|
case 33:
|
||||||
// SYNC SIGNAL
|
// SYNC SIGNAL
|
||||||
case 100:
|
case 100:
|
||||||
|
case 101:
|
||||||
|
// room.StoreMongo(Signal)
|
||||||
|
|
||||||
case 301:
|
case 301:
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user