Drones
This commit is contained in:
parent
19096a5d76
commit
6225ef638d
4
.env
4
.env
@ -2,7 +2,9 @@ SERVER_BASE_ADDRESS=0.0.0.0:8080
|
||||
|
||||
MONGO_INITDB_ROOT_USERNAME=moxitech
|
||||
MONGO_INITDB_ROOT_PASSWORD=moxitech
|
||||
MONGO_INITDB_DATABASE=moxitech
|
||||
MONGO_INITDB_DATABASE=drone-network-simulator
|
||||
MONGO_INITDB_SIM_COLLECTION=simulations
|
||||
|
||||
|
||||
POSTGRES_DB=moxitech
|
||||
POSTGRES_USER=moxitech
|
||||
|
@ -6,6 +6,9 @@ import Dashboard from './pages/Dashboard';
|
||||
import UserAccount from './pages/UserAccount'; // Импортируем компонент UserAccount
|
||||
import Login from './pages/Login'; // Импортируем страницу логина
|
||||
import Connections from './pages/Connections'; // Импортируем страницу подключений
|
||||
import PrevCalc from './pages/PrevCalc'; // Импортируем страницу подключений
|
||||
import Docs from './pages/Docs'; // Импортируем страницу подключений
|
||||
import "./css/bulma.min.css"
|
||||
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
|
||||
|
||||
const App = () => {
|
||||
@ -44,6 +47,8 @@ const App = () => {
|
||||
{activeTab === 'account' && <UserAccount />} {/* Подключаем компонент UserAccount */}
|
||||
{activeTab === 'groups' && <DeviceGroups />} {/* Группы устройств */}
|
||||
{activeTab === 'devices' && <Devices />} {/* Устройства */}
|
||||
{activeTab === 'prev_calc' && <PrevCalc />} {/* Устройства */}
|
||||
{activeTab === 'docs' && <Docs />} {/* Устройства */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -22,9 +22,12 @@ const Sidebar = ({ onSelectTab, activeTab, onLogout }) => {
|
||||
<li className={activeTab === 'connection' ? 'active' : ''} onClick={() => onSelectTab('connection')}>
|
||||
Настройки
|
||||
</li>
|
||||
<li className={activeTab === 'connection' ? 'active' : ''} onClick={() => onSelectTab('connection')}>
|
||||
<li className={activeTab === 'prev_calc' ? 'active' : ''} onClick={() => onSelectTab('prev_calc')}>
|
||||
Проведенные вычисления
|
||||
</li>
|
||||
<li className={activeTab === 'docs' ? 'active' : ''} onClick={() => onSelectTab('docs')}>
|
||||
Документация
|
||||
</li>
|
||||
<li className={activeTab === 'account' ? 'active' : ''} onClick={toggleSubMenu}>
|
||||
Аккаунт пользователя
|
||||
</li>
|
||||
|
3
src/frontend/src/css/bulma.min.css
vendored
Normal file
3
src/frontend/src/css/bulma.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
41
src/frontend/src/pages/Components/Drone.js
Normal file
41
src/frontend/src/pages/Components/Drone.js
Normal file
@ -0,0 +1,41 @@
|
||||
// Drone.js
|
||||
import * as THREE from 'three';
|
||||
|
||||
export class Drone {
|
||||
constructor() {
|
||||
this.drone = new THREE.Object3D();
|
||||
|
||||
// Создаем основное тело дрона
|
||||
const bodyGeometry = new THREE.BoxGeometry(1, 0.3, 1);
|
||||
const bodyMaterial = new THREE.MeshBasicMaterial({ color: 0x0077ff });
|
||||
const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
|
||||
this.drone.add(body);
|
||||
|
||||
// Добавляем четыре пропеллера
|
||||
const propellerGeometry = new THREE.CylinderGeometry(0.1, 0.1, 0.02, 32);
|
||||
const propellerMaterial = new THREE.MeshBasicMaterial({ color: 0x333333 });
|
||||
const positions = [
|
||||
[-0.5, 0.2, -0.5],
|
||||
[-0.5, 0.2, 0.5],
|
||||
[0.5, 0.2, -0.5],
|
||||
[0.5, 0.2, 0.5],
|
||||
];
|
||||
|
||||
positions.forEach((position) => {
|
||||
const propeller = new THREE.Mesh(propellerGeometry, propellerMaterial);
|
||||
propeller.rotation.x = Math.PI / 2;
|
||||
propeller.position.set(...position);
|
||||
this.drone.add(propeller);
|
||||
});
|
||||
}
|
||||
|
||||
// Метод для установки позиции дрона
|
||||
setPosition(x, y, z) {
|
||||
this.drone.position.set(x, y, z);
|
||||
}
|
||||
|
||||
// Получаем объект дрона для добавления в сцену
|
||||
getObject() {
|
||||
return this.drone;
|
||||
}
|
||||
}
|
@ -3,56 +3,64 @@ import * as THREE from 'three';
|
||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
|
||||
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader';
|
||||
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry';
|
||||
import { Drone } from './Components/Drone';
|
||||
import HeightPoint from './Model/HeightPoint';
|
||||
|
||||
|
||||
const RandomHeightPoint = () => {
|
||||
let result = [];
|
||||
for (let i = 0; i < 20; i++) {
|
||||
for (let j = 0; j < 20; j++) {
|
||||
result.push(new HeightPoint(i, j, Math.random() * 10 + 1));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const Dashboard = () => {
|
||||
const mountRef = useRef(null);
|
||||
const [heightData, setHeightData] = useState([
|
||||
[1, 2, 3, 4, 5],
|
||||
[2, 3, 4, 5, 6],
|
||||
[3, 4, 5, 6, 7],
|
||||
[4, 5, 6, 7, 8],
|
||||
[5, 6, 7, 8, 9],
|
||||
]);
|
||||
|
||||
const sceneRef = useRef(null);
|
||||
const [heightData, setHeightData] = useState(RandomHeightPoint());
|
||||
const [formData, setFormData] = useState({ x: '', y: '', height: '' });
|
||||
const [drones, setDrones] = useState([])
|
||||
const [mapSettings, setMapSettings] = useState({
|
||||
maxHeight: 10,
|
||||
maxHeight: 20,
|
||||
coordX: 0,
|
||||
coordY: 0,
|
||||
});
|
||||
const [contextMenu, setContextMenu] = useState({ visible: false, x: 0, y: 0 });
|
||||
|
||||
useEffect(() => {
|
||||
let localRef = null;
|
||||
if (!mountRef.current) return;
|
||||
let width = mountRef.current.clientWidth;
|
||||
let height = mountRef.current.clientHeight;
|
||||
|
||||
// Сцена
|
||||
const scene = new THREE.Scene();
|
||||
|
||||
// Камера
|
||||
sceneRef.current = scene; // Сохраняем ссылку на сцену
|
||||
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
|
||||
camera.position.set(0, 20, 30);
|
||||
|
||||
// Рендерер
|
||||
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(20, 20, 4, 4);
|
||||
|
||||
const vertices = geometry.attributes.position.array;
|
||||
const colors = [];
|
||||
const color = new THREE.Color();
|
||||
|
||||
// Находим минимальные и максимальные значения высот
|
||||
const minHeight = Math.min(...heightData.flat());
|
||||
const maxHeight = Math.max(mapSettings.maxHeight, ...heightData.flat());
|
||||
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 heightValue = heightData[y][x];
|
||||
|
||||
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);
|
||||
@ -72,68 +80,12 @@ const Dashboard = () => {
|
||||
mesh.rotation.x = -Math.PI / 2;
|
||||
scene.add(mesh);
|
||||
|
||||
// Оси координат X, Y и высота
|
||||
const axesHelper = new THREE.AxesHelper(10);
|
||||
scene.add(axesHelper);
|
||||
|
||||
// Линейка и числовые обозначения
|
||||
const createRuler = (scene) => {
|
||||
const lineMaterial = new THREE.LineBasicMaterial({ color: 0x000000 });
|
||||
|
||||
// Ось X
|
||||
const xPoints = [];
|
||||
xPoints.push(new THREE.Vector3(0, 0.1, 0)); // Левый нижний угол
|
||||
xPoints.push(new THREE.Vector3(20, 0.1, 0)); // Правая сторона
|
||||
const xGeometry = new THREE.BufferGeometry().setFromPoints(xPoints);
|
||||
const xLine = new THREE.Line(xGeometry, lineMaterial);
|
||||
scene.add(xLine);
|
||||
|
||||
// Ось Y
|
||||
const yPoints = [];
|
||||
yPoints.push(new THREE.Vector3(0, 0.1, 0)); // Левый нижний угол
|
||||
yPoints.push(new THREE.Vector3(0, 0.1, 20)); // Верхняя сторона
|
||||
const yGeometry = new THREE.BufferGeometry().setFromPoints(yPoints);
|
||||
const yLine = new THREE.Line(yGeometry, lineMaterial);
|
||||
scene.add(yLine);
|
||||
|
||||
// Числовые обозначения
|
||||
const fontLoader = new FontLoader();
|
||||
fontLoader.load('https://threejs.org/examples/fonts/helvetiker_regular.typeface.json', (font) => {
|
||||
// Числа на оси X
|
||||
for (let i = 0; i <= 20; i += 5) {
|
||||
const textGeometry = new TextGeometry(i.toString(), {
|
||||
font: font,
|
||||
size: 0.5,
|
||||
height: 0.1,
|
||||
});
|
||||
const textMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });
|
||||
const textMesh = new THREE.Mesh(textGeometry, textMaterial);
|
||||
textMesh.position.set(i, 0.1, -0.5);
|
||||
scene.add(textMesh);
|
||||
}
|
||||
|
||||
// Числа на оси Y
|
||||
for (let i = 0; i <= 20; i += 5) {
|
||||
const textGeometry = new TextGeometry(i.toString(), {
|
||||
font: font,
|
||||
size: 0.5,
|
||||
height: 0.1,
|
||||
});
|
||||
const textMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });
|
||||
const textMesh = new THREE.Mesh(textGeometry, textMaterial);
|
||||
textMesh.position.set(-0.5, 0.1, i);
|
||||
scene.add(textMesh);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
createRuler(scene);
|
||||
|
||||
// Настройка OrbitControls для взаимодействия с картой
|
||||
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);
|
||||
@ -145,12 +97,38 @@ const Dashboard = () => {
|
||||
};
|
||||
|
||||
animate();
|
||||
if (mountRef.current) localRef = mountRef.current;
|
||||
// Добавление сохранённых дронов в сцену при рендере
|
||||
drones.forEach(droneData => {
|
||||
// const drone = new Drone();
|
||||
// drone.setPosition(droneData.x, droneData.y, droneData.z);
|
||||
scene.add(droneData.getObject()); //drone.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 = () => {
|
||||
if (sceneRef.current) {
|
||||
const drone = new Drone();
|
||||
drone.setPosition(Math.random() * 20 - 10, 0.5, Math.random() * 20 - 10);
|
||||
setDrones((prevDrones) => [...prevDrones, drone]);
|
||||
sceneRef.current.add(drone.getObject());
|
||||
}
|
||||
};
|
||||
|
||||
const handleInputChange = (event) => {
|
||||
const { name, value } = event.target;
|
||||
setFormData({
|
||||
@ -164,14 +142,10 @@ const Dashboard = () => {
|
||||
|
||||
const { x, y, height } = formData;
|
||||
|
||||
if (x >= 0 && y >= 0 && x < heightData[0].length && y < heightData.length) {
|
||||
const updatedData = [...heightData];
|
||||
updatedData[y][x] = parseFloat(height);
|
||||
setHeightData(updatedData);
|
||||
const newPoint = new HeightPoint(parseInt(x), parseInt(y), parseFloat(height));
|
||||
|
||||
setHeightData((prevData) => [...prevData, newPoint]);
|
||||
setFormData({ x: '', y: '', height: '' });
|
||||
} else {
|
||||
alert('Координаты вне допустимого диапазона!');
|
||||
}
|
||||
};
|
||||
|
||||
const handleSettingsChange = (event) => {
|
||||
@ -182,18 +156,97 @@ const Dashboard = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const handleContextMenuClick = (action) => {
|
||||
if (action === 'add') {
|
||||
handleAddDrone();
|
||||
console.log('Добавить объект');
|
||||
} else if (action === 'save') {
|
||||
console.log('Сохранить промежуточный результат');
|
||||
}
|
||||
setContextMenu({ ...contextMenu, visible: false });
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ flex: 1 }}>
|
||||
<h1>Drone Network Simulator - окно разработки</h1>
|
||||
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||
<div id="navbarBasicExample" class="navbar-menu">
|
||||
<div class="navbar-start">
|
||||
<a class="navbar-item">
|
||||
Объекты
|
||||
</a>
|
||||
|
||||
{/* 3D Карта высот */}
|
||||
<div ref={mountRef} style={{ width: '100%', height: '500px' }} />
|
||||
<a class="navbar-item">
|
||||
Документация
|
||||
</a>
|
||||
|
||||
<div class="navbar-item has-dropdown is-hoverable">
|
||||
<a class="navbar-link">
|
||||
Файл
|
||||
</a>
|
||||
|
||||
<div class="navbar-dropdown">
|
||||
<a class="navbar-item">
|
||||
Сохранить локально
|
||||
</a>
|
||||
<a class="navbar-item is-selected">
|
||||
Сохранить на сервере
|
||||
</a>
|
||||
<a class="navbar-item">
|
||||
Настройки клиента
|
||||
</a>
|
||||
<hr class="navbar-divider"/>
|
||||
<a class="navbar-item">
|
||||
Debug mode
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="navbar-end">
|
||||
<div class="navbar-item">
|
||||
<div class="tabs">
|
||||
<ul>
|
||||
<li class="is-active"><a>Моделирование</a></li>
|
||||
<li><a>Симуляция</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div ref={mountRef} style={{ width: '100%', height: '500px', position: 'relative' }} />
|
||||
|
||||
{/* Контекстное меню */}
|
||||
{contextMenu.visible && (
|
||||
<ul
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: `${contextMenu.y}px`,
|
||||
left: `${contextMenu.x}px`,
|
||||
backgroundColor: 'white',
|
||||
listStyle: 'none',
|
||||
padding: '10px',
|
||||
boxShadow: '0px 0px 5px rgba(0,0,0,0.3)',
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
<div style={{ flex: 1, flexFlow: "column" }}>
|
||||
<li className={"button"} onClick={() => handleContextMenuClick('add')}>Добавить объект</li>
|
||||
<li className={"button"} onClick={() => handleContextMenuClick('save')}>Сохранить промежуточный результат</li>
|
||||
<li className={"button"} onClick={() => handleContextMenuClick('cancel')}>Отмена</li>
|
||||
</div>
|
||||
</ul>
|
||||
)}
|
||||
<div className="columns">
|
||||
{/* Форма для добавления новых высот */}
|
||||
<div className='column'>
|
||||
<form onSubmit={handleAddHeight} style={{ marginTop: '20px' }}>
|
||||
<div>
|
||||
<label>Координата X:</label>
|
||||
<input
|
||||
className="input is-primary"
|
||||
type="number"
|
||||
name="x"
|
||||
value={formData.x}
|
||||
@ -204,6 +257,7 @@ const Dashboard = () => {
|
||||
<div>
|
||||
<label>Координата Y:</label>
|
||||
<input
|
||||
className="input is-primary"
|
||||
type="number"
|
||||
name="y"
|
||||
value={formData.y}
|
||||
@ -214,6 +268,7 @@ const Dashboard = () => {
|
||||
<div>
|
||||
<label>Высота:</label>
|
||||
<input
|
||||
className="input is-primary"
|
||||
type="number"
|
||||
name="height"
|
||||
value={formData.height}
|
||||
@ -221,42 +276,26 @@ const Dashboard = () => {
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<button type="submit">Добавить высоту</button>
|
||||
<button className='button' type="submit">Добавить точку высоты</button>
|
||||
</form>
|
||||
|
||||
{/* Форма для изменения настроек карты */}
|
||||
<form style={{ marginTop: '20px' }}>
|
||||
</div>
|
||||
{/* Настройки карты */}
|
||||
<div className='column'>
|
||||
<div style={{ marginTop: '20px' }}>
|
||||
<h2>Настройки карты</h2>
|
||||
<div>
|
||||
<label>Максимальная высота:</label>
|
||||
<input
|
||||
className="input"
|
||||
type="number"
|
||||
name="maxHeight"
|
||||
value={mapSettings.maxHeight}
|
||||
onChange={handleSettingsChange}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label>Координата X (камера):</label>
|
||||
<input
|
||||
type="number"
|
||||
name="coordX"
|
||||
value={mapSettings.coordX}
|
||||
onChange={handleSettingsChange}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label>Координата Y (камера):</label>
|
||||
<input
|
||||
type="number"
|
||||
name="coordY"
|
||||
value={mapSettings.coordY}
|
||||
onChange={handleSettingsChange}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
19
src/frontend/src/pages/Docs.js
Normal file
19
src/frontend/src/pages/Docs.js
Normal file
@ -0,0 +1,19 @@
|
||||
import React from 'react';
|
||||
|
||||
const Docs = () => {
|
||||
return (
|
||||
<div className="block">
|
||||
<div class="block">
|
||||
Документация <strong>Drone Network Simulator</strong>.
|
||||
</div>
|
||||
<div class="block">
|
||||
created by <strong>@moxitech</strong>
|
||||
</div>
|
||||
<div class="block">
|
||||
Для начала работы необходимо войти в систему
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Docs;
|
11
src/frontend/src/pages/Model/HeightPoint.js
Normal file
11
src/frontend/src/pages/Model/HeightPoint.js
Normal file
@ -0,0 +1,11 @@
|
||||
// Класс для хранения точки с координатами и высотой
|
||||
class HeightPoint {
|
||||
constructor(x, y, height) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default HeightPoint;
|
84
src/frontend/src/pages/PrevCalc.js
Normal file
84
src/frontend/src/pages/PrevCalc.js
Normal file
@ -0,0 +1,84 @@
|
||||
import React, { useState } from 'react';
|
||||
import '../UserAccount.scss';
|
||||
|
||||
const PrevCalc = () => {
|
||||
const [userData, setUserData] = useState({
|
||||
username: 'Мамут Рахал',
|
||||
email: 'yatupoidayn@mail.ru',
|
||||
phone: '+666',
|
||||
});
|
||||
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [formData, setFormData] = useState(userData);
|
||||
|
||||
const handleChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData((prevData) => ({
|
||||
...prevData,
|
||||
[name]: value,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
setUserData(formData);
|
||||
setIsEditing(false);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setFormData(userData);
|
||||
setIsEditing(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="user-account">
|
||||
<h1>Данные</h1>
|
||||
|
||||
{isEditing ? (
|
||||
<div className="edit-form">
|
||||
<label>
|
||||
Имя пользователя:
|
||||
<input
|
||||
type="text"
|
||||
name="username"
|
||||
value={formData.username}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
Никнейм авторизации:
|
||||
<input
|
||||
type="text"
|
||||
name="email"
|
||||
value={formData.email}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
Пароль:
|
||||
<input
|
||||
type="password"
|
||||
name="phone"
|
||||
value={formData.phone}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</label>
|
||||
<div className="buttons">
|
||||
<button onClick={handleSave}>Сохранить</button>
|
||||
<button onClick={handleCancel}>Отмена</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="user-info">
|
||||
<p><strong>Имя:</strong> {userData.username}</p>
|
||||
<p><strong>Email:</strong> {userData.email}</p>
|
||||
<p><strong>Телефон:</strong> {userData.phone}</p>
|
||||
<button className="edit-button" onClick={() => setIsEditing(true)}>
|
||||
Редактировать
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PrevCalc;
|
@ -1,13 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"moxitech/dns/internal/database"
|
||||
"moxitech/dns/internal/server"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
D_EXPORT_VARS()
|
||||
err := server.SpawnServer()
|
||||
err := database.NewDBConnection()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = server.SpawnServer()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -1,7 +1,18 @@
|
||||
package database
|
||||
|
||||
type SystemUser struct {
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type User struct {
|
||||
gorm.Model
|
||||
Username string `json:"username"`
|
||||
FIO string `json:"fio"`
|
||||
Password string `json:"password"`
|
||||
IsAdmin bool `json:"is_admin"`
|
||||
}
|
||||
|
||||
type Objects struct {
|
||||
gorm.Model
|
||||
ObjectName string `json:"name"`
|
||||
Type int `json:"type"`
|
||||
Params string `json:"params"`
|
||||
}
|
||||
|
@ -2,11 +2,16 @@ module moxitech/dns
|
||||
|
||||
go 1.22.7
|
||||
|
||||
require (
|
||||
github.com/gofiber/fiber/v2 v2.52.5
|
||||
gorm.io/driver/postgres v1.5.9
|
||||
gorm.io/gorm v1.25.12
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/fasthttp/websocket v1.5.10 // indirect
|
||||
github.com/gofiber/contrib/websocket v1.3.2 // indirect
|
||||
github.com/gofiber/fiber/v2 v2.52.5 // indirect
|
||||
github.com/fasthttp/websocket v1.5.3 // indirect
|
||||
github.com/gofiber/websocket/v2 v2.2.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
@ -19,15 +24,13 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect
|
||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
|
||||
github.com/stretchr/testify v1.9.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.56.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
golang.org/x/crypto v0.27.0 // indirect
|
||||
golang.org/x/net v0.29.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
golang.org/x/text v0.18.0 // indirect
|
||||
gorm.io/driver/postgres v1.5.9 // indirect
|
||||
gorm.io/gorm v1.25.12 // indirect
|
||||
)
|
||||
|
@ -1,16 +1,14 @@
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fasthttp/websocket v1.5.10 h1:bc7NIGyrg1L6sd5pRzCIbXpro54SZLEluZCu0rOpcN4=
|
||||
github.com/fasthttp/websocket v1.5.10/go.mod h1:BwHeuXGWzCW1/BIKUKD3+qfCl+cTdsHu/f243NcAI/Q=
|
||||
github.com/gofiber/contrib/websocket v1.3.2 h1:AUq5PYeKwK50s0nQrnluuINYeep1c4nRCJ0NWsV3cvg=
|
||||
github.com/gofiber/contrib/websocket v1.3.2/go.mod h1:07u6QGMsvX+sx7iGNCl5xhzuUVArWwLQ3tBIH24i+S8=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fasthttp/websocket v1.5.3 h1:TPpQuLwJYfd4LJPXvHDYPMFWbLjsT91n3GpWtCQtdek=
|
||||
github.com/fasthttp/websocket v1.5.3/go.mod h1:46gg/UBmTU1kUaTcwQXpUxtRwG2PvIZYeA8oL6vF3Fs=
|
||||
github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo=
|
||||
github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
|
||||
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gofiber/websocket/v2 v2.2.1 h1:C9cjxvloojayOp9AovmpQrk8VqvVnT8Oao3+IUygH7w=
|
||||
github.com/gofiber/websocket/v2 v2.2.1/go.mod h1:Ao/+nyNnX5u/hIFPuHl28a+NIkrqK7PRimyKaj4JxVU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
@ -25,8 +23,6 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0=
|
||||
github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
@ -34,45 +30,40 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc=
|
||||
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg=
|
||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
|
||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
||||
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
||||
github.com/valyala/fasthttp v1.56.0 h1:bEZdJev/6LCBlpdORfrLu/WOZXXxvrUQSiyniuaoW8U=
|
||||
github.com/valyala/fasthttp v1.56.0/go.mod h1:sReBt3XZVnudxuLOx4J/fMrJVorWRiWY2koQKgABiVI=
|
||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8=
|
||||
gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
|
||||
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||
|
@ -2,18 +2,23 @@ package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"moxitech/dns/entity/database"
|
||||
"os"
|
||||
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var (
|
||||
DbDriver *GormDbInstance
|
||||
)
|
||||
|
||||
type GormDbInstance struct {
|
||||
DB *gorm.DB
|
||||
}
|
||||
|
||||
// GiveMeConnectionString создает строку подключения к базе данных
|
||||
func (db *GormDbInstance) GiveMeConnectionString() string {
|
||||
// giveMeConnectionString создает строку подключения к базе данных
|
||||
func giveMeConnectionString() string {
|
||||
str := fmt.Sprintf("postgresql://%s:%s@%s:%s/%s",
|
||||
os.Getenv("POSTGRES_USER"),
|
||||
os.Getenv("POSTGRES_PASSWORD"),
|
||||
@ -25,16 +30,51 @@ func (db *GormDbInstance) GiveMeConnectionString() string {
|
||||
}
|
||||
|
||||
// NewDBConnection создает новое подключение к базе данных
|
||||
func (db *GormDbInstance) NewDBConnection() (*gorm.DB, error) {
|
||||
cs := db.GiveMeConnectionString()
|
||||
func NewDBConnection() error {
|
||||
cs := giveMeConnectionString()
|
||||
dbInstance, err := gorm.Open(postgres.Open(cs), &gorm.Config{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open database connection: %w", err)
|
||||
return fmt.Errorf("failed to open database connection: %w", err)
|
||||
}
|
||||
return dbInstance, nil
|
||||
DbDriver = &GormDbInstance{DB: dbInstance}
|
||||
// AutoMigration Block after restart application
|
||||
DbDriver.AutoMigrate()
|
||||
DbDriver.AutoMakeSuperUser()
|
||||
return nil
|
||||
}
|
||||
|
||||
// AutoMigrate выполняет автоматическую миграцию
|
||||
func (db *GormDbInstance) AutoMigrate(dbInstance *gorm.DB) error {
|
||||
return dbInstance.AutoMigrate()
|
||||
func (db *GormDbInstance) AutoMigrate() error {
|
||||
return DbDriver.DB.AutoMigrate(
|
||||
database.User{},
|
||||
)
|
||||
}
|
||||
func (db *GormDbInstance) AutoMakeSuperUser() error {
|
||||
var user database.User
|
||||
if db.DB != nil {
|
||||
db.DB.Where("username = ?", "admin").First(&user)
|
||||
if user.ID == 0 {
|
||||
db.DB.Create(&database.User{Username: "admin", Password: "admin", IsAdmin: true})
|
||||
fmt.Println("Superuser has updated! :: \n Login: admin \n Password: admin")
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("DB is nil poiner")
|
||||
}
|
||||
}
|
||||
|
||||
func (db *GormDbInstance) GetUserByName(name string) (*database.User, error) {
|
||||
// Find user by name
|
||||
var user database.User
|
||||
if err := db.DB.Where("username = ?", name).First(&user).Error; err != nil {
|
||||
return nil, fmt.Errorf("failed to find user: %v", err)
|
||||
}
|
||||
fmt.Printf("Found user: ID: %d, Name: %s, Email: %s\n", user.ID, user.Username, user.Password)
|
||||
return &user, nil
|
||||
}
|
||||
func CheckIsUserExists() {
|
||||
|
||||
}
|
||||
func (db *GormDbInstance) GetUserSettings() error {
|
||||
return nil
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
package authorization
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"moxitech/dns/internal/database"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// GET localhost:8080/auth/username?/password?
|
||||
func AuthUser(c *fiber.Ctx) error {
|
||||
username := c.Params("username")
|
||||
password := c.Params("password")
|
||||
if username == "" || password == "" {
|
||||
return c.Status(501).SendString("username and password has required!")
|
||||
}
|
||||
user, err := database.DbDriver.GetUserByName(username)
|
||||
if err != nil {
|
||||
return c.Status(501).SendString(err.Error())
|
||||
}
|
||||
if user == nil {
|
||||
return c.Status(403).SendString(fmt.Sprintf("User with username: %v not found", username))
|
||||
}
|
||||
if user.Password != password {
|
||||
return c.Status(403).SendString("Bad password!")
|
||||
}
|
||||
return c.Status(200).SendString(fmt.Sprintf("Welcome to Drone Network Simulator server-side API! \n UserId: %v ", user.ID))
|
||||
}
|
@ -1,9 +1,12 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"moxitech/dns/internal/server/handlers/authorization"
|
||||
"os"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/websocket/v2"
|
||||
)
|
||||
|
||||
func SpawnServer() error {
|
||||
@ -11,5 +14,57 @@ func SpawnServer() error {
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.SendString("Welcome to Drone Network Simulator server-side API")
|
||||
})
|
||||
app.Get("/auth/:username/:password", authorization.AuthUser)
|
||||
// WebSocket маршрут
|
||||
app.Get("/ws/connect/", websocket.New(CreateSocket))
|
||||
|
||||
return app.Listen(os.Getenv("SERVER_BASE_ADDRESS"))
|
||||
}
|
||||
|
||||
// WS :: ws://localhost:8080/ws/connect?userToken=?&groupId=?
|
||||
func CreateSocket(c *websocket.Conn) {
|
||||
// Получаем токен пользователя из query параметров
|
||||
userToken := c.Query("userToken")
|
||||
if userToken == "" {
|
||||
c.WriteMessage(websocket.ClosePolicyViolation, []byte("userToken is required"))
|
||||
return
|
||||
}
|
||||
// Получаем группу к которой коннектиться user из query параметров
|
||||
groupId := c.Query("groupId")
|
||||
if groupId == "" {
|
||||
c.WriteMessage(websocket.ClosePolicyViolation, []byte("groupId is required"))
|
||||
return
|
||||
}
|
||||
|
||||
// Логика обработки подключения
|
||||
fmt.Printf("User connected with token: %s\n", userToken)
|
||||
|
||||
for {
|
||||
// Читаем сообщения от клиента
|
||||
messageType, msg, err := c.ReadMessage()
|
||||
if messageType != websocket.TextMessage {
|
||||
err = c.WriteMessage(websocket.BinaryMessage, []byte("Please use text message instead"))
|
||||
if err != nil {
|
||||
fmt.Printf("Error writing message: %v\n", err)
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Printf("Error reading message: %v\n", err)
|
||||
break
|
||||
}
|
||||
fmt.Printf("Received message from user %s: %s\n", userToken, msg)
|
||||
|
||||
// Отправляем обратно сообщение клиенту
|
||||
err = c.WriteMessage(websocket.BinaryMessage, msg)
|
||||
if err != nil {
|
||||
fmt.Printf("Error writing message: %v\n", err)
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Закрываем соединение при выходе
|
||||
c.Close()
|
||||
}
|
||||
|
@ -1 +1,20 @@
|
||||
package server
|
||||
|
||||
// CreateGroupRequest создает группу пользователей
|
||||
// @UserDTO -> трансфер пользовательских данных {id}
|
||||
func CreateGroupRequest() {
|
||||
|
||||
}
|
||||
|
||||
// FlushGroupRequest сохраняет результат вычислений группы
|
||||
// @GroupEntity : WS entity -> сущность группы с данными и вычислениями
|
||||
// @IsUserRequest : boolean -> если пользовательский запрос - сейвим с именем группы, иначе создаем произвольную запись с Username<UserId:Creator> + timestamp
|
||||
func FlushGroupRequest() {
|
||||
|
||||
}
|
||||
|
||||
// ObserveGroupHandler проверяет массив групп пользователей и если в группе нет активных пользователей - закрываем соединение
|
||||
// Запускать в горутине после старта сервера!
|
||||
func ObserveGroupHandler() {
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user