Map in mongo & map loader & websocket update state & ctx state stablishment
This commit is contained in:
parent
047a3ffd5c
commit
44e28d8e6b
5
.env
5
.env
@ -14,4 +14,7 @@ POSTGRES_DB=moxitech
|
|||||||
POSTGRES_USER=moxitech
|
POSTGRES_USER=moxitech
|
||||||
POSTGRES_PASSWORD=moxitech
|
POSTGRES_PASSWORD=moxitech
|
||||||
POSTGRES_PORT=5432
|
POSTGRES_PORT=5432
|
||||||
POSTGRES_HOST=postgres
|
POSTGRES_HOST=postgres
|
||||||
|
|
||||||
|
SOCKET_BASE_ADDRESS=9091
|
||||||
|
SOCKET_SERVICE_HOST=socket
|
7
DOCS.md
Normal file
7
DOCS.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
SOCKET MESSAGING:
|
||||||
|
// PORT CHANGE IN .env
|
||||||
|
localhost:9091/storeEvent?client_id=1&message={"me": "update"}
|
||||||
|
// CONNECTION:
|
||||||
|
ws://localhost:9091/ws/1
|
@ -64,6 +64,18 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- dns_net
|
- dns_net
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
|
socket:
|
||||||
|
container_name: dns-socket
|
||||||
|
build:
|
||||||
|
context: ./src/socket
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
env_file: ".env"
|
||||||
|
ports:
|
||||||
|
- "${SOCKET_BASE_ADDRESS}:${SOCKET_BASE_ADDRESS}"
|
||||||
|
networks:
|
||||||
|
- dns_net
|
||||||
|
restart: always
|
||||||
|
|
||||||
front:
|
front:
|
||||||
container_name: dns-ui
|
container_name: dns-ui
|
||||||
|
49
src/frontend/src/Services/SocketMessaging/MessageHook.js
Normal file
49
src/frontend/src/Services/SocketMessaging/MessageHook.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { useEffect, useState, useRef } from 'react';
|
||||||
|
|
||||||
|
const useWebSocket = (userToken) => {
|
||||||
|
const [message, setMessage] = useState(null);
|
||||||
|
const [isConnected, setIsConnected] = useState(false);
|
||||||
|
const ws = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!userToken) return;
|
||||||
|
|
||||||
|
const connectWebSocket = () => {
|
||||||
|
const socketUrl = `ws://${process.env.SOCKET_SERVICE_HOST}:${process.env.SOCKET_BASE_ADDRESS}/ws/${userToken}`;
|
||||||
|
ws.current = new WebSocket(socketUrl);
|
||||||
|
|
||||||
|
ws.current.onopen = () => {
|
||||||
|
console.log('WebSocket connected');
|
||||||
|
setIsConnected(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.current.onmessage = (event) => {
|
||||||
|
const data = event.data;
|
||||||
|
console.log('Message received:', data);
|
||||||
|
setMessage(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.current.onclose = () => {
|
||||||
|
console.log('WebSocket disconnected, attempting to reconnect...');
|
||||||
|
setIsConnected(false);
|
||||||
|
setTimeout(connectWebSocket, 3000); // Reconnect after 3 seconds
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.current.onerror = (error) => {
|
||||||
|
console.error('WebSocket error:', error);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
connectWebSocket();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (ws.current) {
|
||||||
|
ws.current.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [userToken]);
|
||||||
|
|
||||||
|
return { message, isConnected };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useWebSocket;
|
@ -100,7 +100,19 @@ const useWebsocketConnection = (userToken, roomHash) => {
|
|||||||
return { websocketStruct, sendMessage };
|
return { websocketStruct, sendMessage };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const spawnJsonSignal = (signal, name, coords) => {
|
export const spawnJsonSignal =
|
||||||
|
( signal,
|
||||||
|
name,
|
||||||
|
coords,
|
||||||
|
antennaRadius,
|
||||||
|
antennaDirections="0,0,0",
|
||||||
|
modulation="",
|
||||||
|
bandwidth=0,
|
||||||
|
dataRate=0,
|
||||||
|
wayPoints=[],
|
||||||
|
speed=0,
|
||||||
|
meshName=null
|
||||||
|
) => {
|
||||||
if (![1, 2].includes(signal)) {
|
if (![1, 2].includes(signal)) {
|
||||||
throw new Error('Invalid signal value. Expected 1 or 2.');
|
throw new Error('Invalid signal value. Expected 1 or 2.');
|
||||||
}
|
}
|
||||||
@ -115,11 +127,20 @@ export const spawnJsonSignal = (signal, name, coords) => {
|
|||||||
name,
|
name,
|
||||||
params: {
|
params: {
|
||||||
coords,
|
coords,
|
||||||
|
antennaRadius,
|
||||||
|
antennaDirections,
|
||||||
|
modulation,
|
||||||
|
bandwidth,
|
||||||
|
dataRate,
|
||||||
|
wayPoints,
|
||||||
|
speed,
|
||||||
|
meshName
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const DeleteSignal = (name) => {
|
export const DeleteSignal = (name) => {
|
||||||
const signal = 3;
|
const signal = 3;
|
||||||
|
|
||||||
|
@ -28,14 +28,23 @@ const Dashboard = () => {
|
|||||||
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: "",
|
||||||
type: 1,
|
type: 0, // 1 = Drone, 2 = Base Station
|
||||||
coordinates_x: 0,
|
coordinates_x: 0, // Координата X на карте
|
||||||
coordinates_y: 0,
|
coordinates_y: 0, // Координата Y на карте
|
||||||
coordinates_z: 0,
|
coordinates_z: 0, // Координата Z на карте
|
||||||
droneField1: "",
|
|
||||||
droneField2: "",
|
antennaRadius: 0, // Радиус антенны
|
||||||
baseStationField1: "",
|
antennaDirection_x: 0,// Направление антенны по X
|
||||||
baseStationField2: ""
|
antennaDirection_y: 0,// Направление антенны по Y
|
||||||
|
antennaDirection_z: 0,// Направление антенны по Z
|
||||||
|
|
||||||
|
modulation: "", // Модуляция
|
||||||
|
bandwidth: 0, // Пропускная способность
|
||||||
|
dataRate: 0, // Скорость передачи данных
|
||||||
|
// DRONE FIELDS
|
||||||
|
wayPoints: 0, // Точки следования
|
||||||
|
speed: 0, // Скорость
|
||||||
|
meshName: "", // Название сети
|
||||||
});
|
});
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
@ -76,18 +85,13 @@ const Dashboard = () => {
|
|||||||
alert("Объект с указанным именем не найден");
|
alert("Объект с указанным именем не найден");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleTypeChange = (type) => {
|
const handleTypeChange = (type) => {
|
||||||
setObjectType(type);
|
setObjectType(type);
|
||||||
setFormData({ ...formData, type });
|
setFormData({ ...formData, type });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteSignal = (name) => {
|
const handleDeleteSignal = (name) => {
|
||||||
sendMessage(DeleteSignal(name));
|
sendMessage(DeleteSignal(name));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Одно состояние для управления всеми модальными окнами
|
// Одно состояние для управления всеми модальными окнами
|
||||||
const [modals, setModals] = useState({
|
const [modals, setModals] = useState({
|
||||||
isModalOpen: false,
|
isModalOpen: false,
|
||||||
@ -96,7 +100,6 @@ const Dashboard = () => {
|
|||||||
isModalSearchOpen: false,
|
isModalSearchOpen: false,
|
||||||
isModalMapOpen: false,
|
isModalMapOpen: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Функция открытия модального окна в зависимости от переданной строки
|
// Функция открытия модального окна в зависимости от переданной строки
|
||||||
const openModal = (modalName) => {
|
const openModal = (modalName) => {
|
||||||
setModals((prevModals) => ({
|
setModals((prevModals) => ({
|
||||||
@ -104,7 +107,6 @@ const Dashboard = () => {
|
|||||||
[modalName]: true,
|
[modalName]: true,
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Функция закрытия всех модальных окон
|
// Функция закрытия всех модальных окон
|
||||||
const closeAllModals = () => {
|
const closeAllModals = () => {
|
||||||
setModals({
|
setModals({
|
||||||
@ -114,7 +116,7 @@ const Dashboard = () => {
|
|||||||
isModalSearchOpen: false,
|
isModalSearchOpen: false,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
// Обработка websocket
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (websocketStruct && websocketStruct.modulation) {
|
if (websocketStruct && websocketStruct.modulation) {
|
||||||
const modulation = websocketStruct.modulation;
|
const modulation = websocketStruct.modulation;
|
||||||
@ -327,9 +329,34 @@ const containsObjectRecursively = (parent, target) => {
|
|||||||
sceneRef.current.add(drone.getObject());
|
sceneRef.current.add(drone.getObject());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Добавление дрона в сцену
|
const modalAddDroneOrBaseStation = () => {
|
||||||
// Добавление базовой станции в сцену
|
//formObjectData
|
||||||
const handleAddBaseStation = () => {
|
alert(`Добавлено: ${JSON.stringify(formObjectData)}`);
|
||||||
|
if (sceneRef.current) {
|
||||||
|
if (objectType === 1) {
|
||||||
|
const drone = new Drone(formObjectData.name);
|
||||||
|
drone.setPosition(formObjectData.coordinates_x, formObjectData.coordinates_y, formObjectData.coordinates_z);
|
||||||
|
setDrones((prevDrones) => [...prevDrones, drone]);
|
||||||
|
let json_signal = spawnJsonSignal(
|
||||||
|
1,
|
||||||
|
formObjectData.name,
|
||||||
|
`${formObjectData.coordinates_x},${formObjectData.coordinates_y},${formObjectData.coordinates_z}`,
|
||||||
|
formObjectData.antennaRadius,
|
||||||
|
`${formObjectData.antennaDirection_x},${formObjectData.antennaDirection_y},${formObjectData.antennaDirection_z}`,
|
||||||
|
formObjectData.modulation,
|
||||||
|
formObjectData.bandwidth,
|
||||||
|
formObjectData.dataRate,
|
||||||
|
formObjectData.wayPoints,
|
||||||
|
formObjectData.speed,
|
||||||
|
formObjectData.meshName
|
||||||
|
);
|
||||||
|
sendMessage(json_signal)
|
||||||
|
sceneRef.current.add(drone.getObject());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Добавление базовой станции в сцену
|
||||||
|
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);
|
||||||
@ -350,7 +377,7 @@ const handleAddBaseStation = () => {
|
|||||||
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());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Обработчик ввода на форму высот
|
// Обработчик ввода на форму высот
|
||||||
const handleInputChange = (event) => {
|
const handleInputChange = (event) => {
|
||||||
@ -497,60 +524,120 @@ const handleAddBaseStation = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label>Параметры антенны:</label>
|
||||||
|
<div className="input-group mb-2">
|
||||||
|
<span className="input-group-text">Радиус антенны</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="form-control"
|
||||||
|
value={formObjectData.antennaRadius}
|
||||||
|
name='antennaRadius'
|
||||||
|
onChange={handleAddInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="input-group mb-2">
|
||||||
|
<span className="input-group-text">Направление X</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="form-control"
|
||||||
|
value={formObjectData.antennaDirection_x}
|
||||||
|
name='antennaDirection_x'
|
||||||
|
onChange={handleAddInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="input-group mb-2">
|
||||||
|
<span className="input-group-text">Направление Y</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="form-control"
|
||||||
|
name='antennaDirection_y'
|
||||||
|
value={formObjectData.antennaDirection_y}
|
||||||
|
onChange={handleAddInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="input-group mb-2">
|
||||||
|
<span className="input-group-text">Направление Z</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="form-control"
|
||||||
|
name='antennaDirection_z'
|
||||||
|
value={formObjectData.antennaDirection_z}
|
||||||
|
onChange={handleAddInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="input-group mb-2">
|
||||||
|
<span className="input-group-text">Модуляция</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="form-control"
|
||||||
|
name='modulation'
|
||||||
|
value={formObjectData.modulation}
|
||||||
|
onChange={handleAddInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="input-group mb-2">
|
||||||
|
<span className="input-group-text">Пропускная способность</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="form-control"
|
||||||
|
name='bandwidth'
|
||||||
|
value={formObjectData.bandwidth}
|
||||||
|
onChange={handleAddInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="input-group mb-2">
|
||||||
|
<span className="input-group-text">Скорость</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="form-control"
|
||||||
|
name='dataRate'
|
||||||
|
value={formObjectData.dataRate}
|
||||||
|
onChange={handleAddInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
{objectType === 1 && (
|
{objectType === 1 && (
|
||||||
<>
|
<>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label>Поле 1 для дрона:</label>
|
<label>Скорость перемещения:</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
name='droneField1'
|
name='speed'
|
||||||
value={formObjectData.droneField1}
|
value={formObjectData.speed}
|
||||||
onChange={handleAddInputChange}
|
onChange={handleAddInputChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label>Поле 2 для дрона:</label>
|
<label>Название Mesh сети:</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
name='droneField2'
|
name='meshName'
|
||||||
value={formObjectData.droneField2}
|
value={formObjectData.meshName}
|
||||||
|
onChange={handleAddInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label>Точки перемещения:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="form-control"
|
||||||
|
name='wayPoints'
|
||||||
|
value={formObjectData.wayPoints}
|
||||||
onChange={handleAddInputChange}
|
onChange={handleAddInputChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{objectType === 2 && (
|
|
||||||
<>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label>Поле 1 для базовой станции:</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="form-control"
|
|
||||||
name='baseStationField1'
|
|
||||||
value={formObjectData.baseStationField1}
|
|
||||||
onChange={handleAddInputChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label>Поле 2 для базовой станции:</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="form-control"
|
|
||||||
name='baseStationField2'
|
|
||||||
value={formObjectData.baseStationField2}
|
|
||||||
onChange={handleAddInputChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="modal-footer">
|
<div className="modal-footer">
|
||||||
<button type="button" className="btn btn-secondary" onClick={closeAllModals}>Закрыть</button>
|
<button type="button" className="btn btn-secondary" onClick={closeAllModals}>Закрыть</button>
|
||||||
<button type="button" className="btn btn-primary" onClick={() => { alert(`Добавлено: ${JSON.stringify(formData)}`); }}>Добавить</button>
|
<button type="button" className="btn btn-primary" onClick={() => { modalAddDroneOrBaseStation(); }}>Добавить</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import '../DeviceGroups.css';
|
import '../css/DeviceGroups.css';
|
||||||
|
|
||||||
const DeviceGroups = () => {
|
const DeviceGroups = () => {
|
||||||
const [groups, setGroups] = useState([]);
|
const [groups, setGroups] = useState([]);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { QRCodeCanvas } from "qrcode.react";
|
import { QRCodeCanvas } from "qrcode.react";
|
||||||
import '../Devices.css';
|
import '../css/Devices.css';
|
||||||
|
|
||||||
const Devices = () => {
|
const Devices = () => {
|
||||||
return (
|
return (
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
|
|
||||||
// Инициализация WebSocket соединения
|
|
||||||
// const socket = io("ws://localhost:8080");
|
|
||||||
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// // Получаем местоположение пользователя
|
|
||||||
// if (navigator.geolocation) {
|
|
||||||
// navigator.geolocation.getCurrentPosition(
|
|
||||||
// (position) => {
|
|
||||||
// const { latitude, longitude } = position.coords;
|
|
||||||
// setUserLocation([latitude, longitude]); // Устанавливаем координаты пользователя
|
|
||||||
// setLocationLoaded(true); // Флаг, что местоположение загружено
|
|
||||||
// },
|
|
||||||
// (error) => {
|
|
||||||
// console.error("Ошибка при получении геолокации:", error);
|
|
||||||
// setLocationLoaded(true); // Продолжаем даже при ошибке
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
// } else {
|
|
||||||
// console.error("Геолокация не поддерживается вашим браузером");
|
|
||||||
// setLocationLoaded(true); // Продолжаем даже если геолокация недоступна
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Получаем данные устройств в реальном времени
|
|
||||||
// socket.on("deviceLocationUpdate", (data) => {
|
|
||||||
// setDevices(data);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// return () => {
|
|
||||||
// socket.off("deviceLocationUpdate");
|
|
||||||
// };
|
|
||||||
// }, []);
|
|
@ -1,9 +1,26 @@
|
|||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||||
class BaseStation {
|
class BaseStation {
|
||||||
constructor(name, scale = 10) {
|
constructor(
|
||||||
|
name,
|
||||||
|
scale = 10,
|
||||||
|
antennaRadius = 1,
|
||||||
|
antennaDirection_x=0,
|
||||||
|
antennaDirection_y=0,
|
||||||
|
antennaDirection_z=0,
|
||||||
|
modulation="QAM-16",
|
||||||
|
bandwidth=0,
|
||||||
|
dataRate=0,
|
||||||
|
) {
|
||||||
this.object = new THREE.Object3D();
|
this.object = new THREE.Object3D();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.antennaRadius = antennaRadius;
|
||||||
|
this.antennaDirection_x = antennaDirection_x;
|
||||||
|
this.antennaDirection_y = antennaDirection_y;
|
||||||
|
this.antennaDirection_z = antennaDirection_z;
|
||||||
|
this.modulation = modulation;
|
||||||
|
this.bandwidth = bandwidth;
|
||||||
|
this.dataRate = dataRate;
|
||||||
|
|
||||||
// Инициализируем GLTFLoader
|
// Инициализируем GLTFLoader
|
||||||
const loader = new GLTFLoader();
|
const loader = new GLTFLoader();
|
||||||
|
@ -1,10 +1,32 @@
|
|||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||||
class Drone {
|
class Drone {
|
||||||
constructor(name, scale = 0.5) {
|
constructor(name,
|
||||||
|
antennaRadius = 1,
|
||||||
|
antennaDirection_x=0,
|
||||||
|
antennaDirection_y=0,
|
||||||
|
antennaDirection_z=0,
|
||||||
|
modulation="QAM-16",
|
||||||
|
bandwidth=0,
|
||||||
|
dataRate=0,
|
||||||
|
wayPoints=[],
|
||||||
|
speed=0,
|
||||||
|
meshName=null,
|
||||||
|
scale = 0.5)
|
||||||
|
{
|
||||||
this.object = new THREE.Object3D();
|
this.object = new THREE.Object3D();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.antennaRadius = antennaRadius;
|
||||||
|
|
||||||
|
this.antennaDirection_x = antennaDirection_x;
|
||||||
|
this.antennaDirection_y = antennaDirection_y;
|
||||||
|
this.antennaDirection_z = antennaDirection_z;
|
||||||
|
this.modulation = modulation;
|
||||||
|
this.bandwidth = bandwidth;
|
||||||
|
this.dataRate = dataRate;
|
||||||
|
this.wayPoints = wayPoints
|
||||||
|
this.speed = speed;
|
||||||
|
this.meshName = meshName;
|
||||||
// Инициализируем GLTFLoader
|
// Инициализируем GLTFLoader
|
||||||
const loader = new GLTFLoader();
|
const loader = new GLTFLoader();
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
"go.mongodb.org/mongo-driver/mongo/options"
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
@ -102,3 +103,65 @@ func (db *MongoDbInstance) InsertIntoSimulationsHistory(data interface{}) (primi
|
|||||||
|
|
||||||
return insertedID, nil
|
return insertedID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MapUpload saves a [][]float64 map into the map_templates collection
|
||||||
|
func (db *MongoDbInstance) MapUpload(mapData [][]float64) (primitive.ObjectID, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
collection := db.Db.Collection("map_templates")
|
||||||
|
|
||||||
|
mapDocument := bson.M{"map_data": mapData, "created_at": time.Now()}
|
||||||
|
|
||||||
|
result, err := collection.InsertOne(ctx, mapDocument)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error inserting map into collection 'map_templates': %v", err)
|
||||||
|
return primitive.NilObjectID, err
|
||||||
|
}
|
||||||
|
|
||||||
|
insertedID := result.InsertedID.(primitive.ObjectID)
|
||||||
|
log.Printf("Map successfully inserted with ID: %v", insertedID)
|
||||||
|
|
||||||
|
return insertedID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapLoader loads a [][]float64 map from the map_templates collection
|
||||||
|
func (db *MongoDbInstance) MapLoader(mapID primitive.ObjectID) ([][]float64, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
collection := db.Db.Collection("map_templates")
|
||||||
|
|
||||||
|
var result bson.M
|
||||||
|
err := collection.FindOne(ctx, bson.M{"_id": mapID}).Decode(&result)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error loading map from collection 'map_templates': %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mapData, ok := result["map_data"].(primitive.A)
|
||||||
|
if !ok {
|
||||||
|
log.Printf("Error asserting map data type")
|
||||||
|
return nil, mongo.ErrNoDocuments
|
||||||
|
}
|
||||||
|
|
||||||
|
heightMap := make([][]float64, len(mapData))
|
||||||
|
for i, row := range mapData {
|
||||||
|
rowArray, ok := row.(primitive.A)
|
||||||
|
if !ok {
|
||||||
|
log.Printf("Error asserting row type")
|
||||||
|
return nil, mongo.ErrNoDocuments
|
||||||
|
}
|
||||||
|
heightMap[i] = make([]float64, len(rowArray))
|
||||||
|
for j, val := range rowArray {
|
||||||
|
floatVal, ok := val.(float64)
|
||||||
|
if !ok {
|
||||||
|
log.Printf("Error asserting value type at row %d, column %d", i, j)
|
||||||
|
return nil, mongo.ErrNoDocuments
|
||||||
|
}
|
||||||
|
heightMap[i][j] = floatVal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return heightMap, nil
|
||||||
|
}
|
||||||
|
@ -57,6 +57,11 @@ func (db *GormDbInstance) AutoMakeSuperUser() error {
|
|||||||
db.DB.Create(&database.User{Username: "admin", Password: "admin", IsAdmin: true})
|
db.DB.Create(&database.User{Username: "admin", Password: "admin", IsAdmin: true})
|
||||||
fmt.Println("Superuser has updated! :: \n Login: admin \n Password: admin")
|
fmt.Println("Superuser has updated! :: \n Login: admin \n Password: admin")
|
||||||
}
|
}
|
||||||
|
db.DB.Where("username = ?", "user").First(&user)
|
||||||
|
if user.ID == 0 {
|
||||||
|
db.DB.Create(&database.User{Username: "user", Password: "user", IsAdmin: false})
|
||||||
|
fmt.Println("User has added! :: \n Login: user \n Password: user")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("DB is nil poiner")
|
return fmt.Errorf("DB is nil poiner")
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
package simulator
|
package simulator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"moxitech/dns/internal/database"
|
||||||
"moxitech/dns/package/math/distance"
|
"moxitech/dns/package/math/distance"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Map struct {
|
type Map struct {
|
||||||
@ -246,11 +250,18 @@ func CalculateDataRate(modulation string, bandwidth float64) float64 {
|
|||||||
|
|
||||||
// MakeExampleMap создает статическую карту
|
// MakeExampleMap создает статическую карту
|
||||||
func MakeExampleMap() Map {
|
func MakeExampleMap() Map {
|
||||||
|
mapID, err := primitive.ObjectIDFromHex("6709c34cdeb5f8e46f450c9f")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Ошибка при преобразовании строки в ObjectID: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
database.Instance.MapLoader(mapID)
|
||||||
heightData := [][]float64{
|
heightData := [][]float64{
|
||||||
{0, 10, 15, 20},
|
{0, 10, 15, 20},
|
||||||
{5, 15, 25, 30},
|
{5, 15, 25, 30},
|
||||||
{10, 20, 35, 40},
|
{10, 20, 35, 40},
|
||||||
{15, 25, 40, 50},
|
{15, 25, 40, 50},
|
||||||
|
{20, 30, 25, 50},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Определяем карту высот
|
// Определяем карту высот
|
||||||
@ -263,7 +274,7 @@ func MakeExampleMap() Map {
|
|||||||
return mapObj
|
return mapObj
|
||||||
}
|
}
|
||||||
|
|
||||||
// Создает полностью случаную карту
|
// Создает полностью случайную карту
|
||||||
func MakeRandomMap() Map {
|
func MakeRandomMap() Map {
|
||||||
// Задаём случайное количество высот
|
// Задаём случайное количество высот
|
||||||
numRows := rand.Intn(50) + 1 // Случайное количество строк (от 1 до 50)
|
numRows := rand.Intn(50) + 1 // Случайное количество строк (от 1 до 50)
|
||||||
|
12
src/socket/Dockerfile
Normal file
12
src/socket/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Build stage
|
||||||
|
FROM golang:1.22.7-alpine3.20 AS builder
|
||||||
|
WORKDIR /var/socket
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
COPY . .
|
||||||
|
RUN go build -o main cmd/main.go
|
||||||
|
|
||||||
|
# Run stage
|
||||||
|
FROM alpine:3.20.3
|
||||||
|
COPY --from=builder /var/socket/main /main
|
||||||
|
CMD ["./main"]
|
97
src/socket/cmd/main.go
Normal file
97
src/socket/cmd/main.go
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
clients = make(map[int]*websocket.Conn) // Список активных клиентов
|
||||||
|
events = make(map[int]string) // Локальная карта для хранения сообщений
|
||||||
|
mutex sync.Mutex // Мьютекс для управления конкурентным доступом к карте
|
||||||
|
upgrader = websocket.Upgrader{
|
||||||
|
CheckOrigin: func(r *http.Request) bool { return true },
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
http.HandleFunc("/storeEvent", handleStoreEvent)
|
||||||
|
http.HandleFunc("/ws/", handleWebSocket)
|
||||||
|
|
||||||
|
// Запуск горутины для обработки сообщений каждую секунду
|
||||||
|
go processEvents()
|
||||||
|
fmt.Printf("Server started on %v \n", os.Getenv("SOCKET_BASE_ADDRESS"))
|
||||||
|
http.ListenAndServe(fmt.Sprintf("0.0.0.0:%v", os.Getenv("SOCKET_BASE_ADDRESS")), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработчик для сохранения событий
|
||||||
|
func handleStoreEvent(w http.ResponseWriter, r *http.Request) {
|
||||||
|
clientID := r.URL.Query().Get("client_id")
|
||||||
|
message := r.URL.Query().Get("message")
|
||||||
|
|
||||||
|
if clientID == "" || message == "" {
|
||||||
|
http.Error(w, "client_id and message are required", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var id int
|
||||||
|
_, err := fmt.Sscanf(clientID, "%d", &id)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Invalid client_id", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex.Lock()
|
||||||
|
events[id] = message
|
||||||
|
mutex.Unlock()
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработчик WebSocket соединений
|
||||||
|
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
|
||||||
|
clientIDStr := r.URL.Path[len("/ws/"):]
|
||||||
|
var clientID int
|
||||||
|
_, err := fmt.Sscanf(clientIDStr, "%d", &clientID)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Invalid client ID", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := upgrader.Upgrade(w, r, nil)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Failed to upgrade to WebSocket", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex.Lock()
|
||||||
|
clients[clientID] = conn
|
||||||
|
mutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Функция для обработки событий и отправки сообщений подключенным клиентам
|
||||||
|
func processEvents() {
|
||||||
|
for {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
mutex.Lock()
|
||||||
|
for id, message := range events {
|
||||||
|
if conn, ok := clients[id]; ok {
|
||||||
|
err := conn.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("Client %d: %s", id, message)))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error sending message to client %d: %v\n", id, err)
|
||||||
|
conn.Close()
|
||||||
|
delete(clients, id)
|
||||||
|
}
|
||||||
|
// Удаляем событие после отправки
|
||||||
|
delete(events, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex.Unlock()
|
||||||
|
}
|
||||||
|
}
|
5
src/socket/go.mod
Normal file
5
src/socket/go.mod
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module moxitech/socket
|
||||||
|
|
||||||
|
go 1.22.7
|
||||||
|
|
||||||
|
require github.com/gorilla/websocket v1.5.3 // indirect
|
2
src/socket/go.sum
Normal file
2
src/socket/go.sum
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
Loading…
Reference in New Issue
Block a user