Insert, update, exampling, delete over websocket

This commit is contained in:
moxitech 2024-10-05 22:02:41 +07:00
parent fa4be8d5ff
commit f2e9c6f38f
5 changed files with 300 additions and 84 deletions

1
.env
View File

@ -6,6 +6,7 @@ MONGO_INITDB_ROOT_PASSWORD=moxitech
MONGO_INITDB_DATABASE=drone-network-simulator
MONGO_INITDB_SIM_COLLECTION=simulations
MONGO_INITDB_SIM_HIST_COLLECTION=simulations_history
MONGO_INITDB_MAP_COLLECTION=map_templates
POSTGRES_DB=moxitech
POSTGRES_USER=moxitech

View File

@ -1,6 +1,10 @@
package websocket
import "moxitech/dns/package/math/simulator"
import (
"moxitech/dns/package/math/simulator"
"moxitech/dns/package/utils/randomizer"
"time"
)
type Modulation struct {
Map *MapPartial `json:"map"`
@ -21,6 +25,91 @@ type SystemObject struct {
Params *map[string]string `json:"params"`
}
func (o *SystemObject) Delete() {
// DeleteObjectIfExists удаляет объект если он найден
func (o *Modulation) DeleteObjectIfExists(name string) {
if o.Objects == nil {
return
}
for i, obj := range o.Objects {
if obj.Name == name {
o.Objects = append(o.Objects[:i], o.Objects[i+1:]...)
return
}
}
}
// SpawnExampleData создает случайные данные и перезаписывает карту
func (o *Modulation) SpawnExampleData() bool {
o.Map = &MapPartial{
Map: simulator.MakeRandomMap(),
Name: "example starter map",
Changed: false,
}
o.Objects = make([]*SystemObject, 0)
o.Ts_update = time.Now().Unix()
return true
}
// AddObject добавляет объект станции или дрона
func (o *Modulation) AddObject(name string, obj_type int, coords [3]int, params map[string]string) {
if obj_type != 1 && obj_type != 2 {
// Значит объект не станция или не дрон
return
}
if o.Objects == nil {
o.Objects = make([]*SystemObject, 0)
}
if o.ObjectExists(name) {
name = name + " " + randomizer.GenerateRandomString()
}
obj := &SystemObject{
Name: name,
Type: obj_type,
Coords: coords,
Params: &params,
}
o.Objects = append(o.Objects, obj)
}
// UpdateObject обновляет объект станции или дрона по имени
func (o *Modulation) UpdateObject(name string, obj_type int, coords [3]int, params map[string]string) {
if obj_type != 1 && obj_type != 2 {
// Значит объект не станция или не дрон
return
}
if o.Objects == nil {
o.Objects = make([]*SystemObject, 0)
}
ok := o.ObjectExists(name)
if !ok {
o.AddObject(name, obj_type, coords, params)
return
}
obj := &SystemObject{
Name: name,
Type: obj_type,
Coords: coords,
Params: &params,
}
o.DeleteObjectIfExists(name)
o.Objects = append(o.Objects, obj)
}
// GetObjects вернет все объекты карты
func (o *Modulation) GetObjects() []*SystemObject {
return o.Objects
}
// ObjectExists проверит есть ли объект с заданным (именем | id) на карте
func (o *Modulation) ObjectExists(name string) bool {
if o.Objects == nil {
o.Objects = make([]*SystemObject, 0)
return false
}
for _, obj := range o.Objects {
if obj.Name == name {
return true
}
}
return false
}

View File

@ -91,10 +91,16 @@ func CreateOrConnectSocket(c *websocket.Conn) {
}
// LOGGING :
fmt.Printf("Received message from user %s: %s\n", userToken, msg)
room.UpdateGroupUptime()
err, ok = room.WebsocketAction(msg)
if err != nil {
err = c.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("%v", err)))
if err != nil {
fmt.Printf("Error writing message: %v\n", err)
}
}
if ok {
// Обрабатываем сообщение
data, err := json.Marshal(Rooms)
data, err := json.Marshal(Rooms[groupHash])
if err != nil {
fmt.Printf("Error marshal json: %v\n", err)
}
@ -102,7 +108,7 @@ func CreateOrConnectSocket(c *websocket.Conn) {
if err != nil {
fmt.Printf("Error writing message: %v\n", err)
}
}
}
// Закрываем соединение при выходе

View File

@ -5,7 +5,8 @@ import (
"fmt"
"moxitech/dns/entity/websocket"
"moxitech/dns/package/math/simulator"
u_sorting "moxitech/dns/package/utils/sorting"
"strconv"
"strings"
"sync"
"time"
)
@ -79,102 +80,193 @@ func (room *WebsocketRoom) FlushGroupRequest() {
// ... ДОБАВИТЬ ЛОГИКУ ИЗ WEBSOCKET ACTION ...
//
// FlushGroupRequest сохраняет результат вычислений группы
// @GroupEntity : WS entity -> сущность группы с данными и вычислениями
// func (room *WebsocketRoom) DeleteMapObjectRequest(name string) {
// roomsMutex.Lock()
// defer roomsMutex.Unlock()
// room.Modulation.Objects.DeleteObject(name)
// DeleteMapObjectRequest удаляет определенный объект
func (room *WebsocketRoom) DeleteMapObjectRequest(message websocket.SignalMessage) {
var parsedData struct {
Name string `json:"name"`
}
err := json.Unmarshal(message.Data, &parsedData)
if err != nil {
fmt.Printf("[delete] error parsing data: %v", err)
}
// }
roomsMutex.Lock()
defer roomsMutex.Unlock()
room.Modulation.DeleteObjectIfExists(parsedData.Name)
}
// InsertObject вставляет базовые случайные данные в симуляцию
func (room *WebsocketRoom) InsertObject(message websocket.SignalMessage) error {
// Тип объекта (тип сигнала)
type_obj := message.Signal
// Определяем структуру для данных в поле `data`
var parsedData struct {
Name string `json:"name"`
Params map[string]string `json:"params"`
}
// Парсим `data` в структуру
err := json.Unmarshal(message.Data, &parsedData)
if err != nil {
return fmt.Errorf("[insert] error parsing data: %v", err)
}
// Получаем значения name и params
name := parsedData.Name
params := parsedData.Params
// Проверяем наличие координат в параметрах
if params["coords"] == "" {
return fmt.Errorf("[insert] coords is empty")
}
// Разделяем строку координат на отдельные элементы
coordinateStrings := strings.Split(params["coords"], ",")
// Инициализируем массив для хранения координат
coordinates := make([]int, len(coordinateStrings))
// Преобразуем каждую координату в целое число
for i, coord := range coordinateStrings {
parsedCoord, err := strconv.Atoi(strings.TrimSpace(coord))
if err != nil {
return fmt.Errorf("[insert] invalid coordinate: %s", coord)
}
coordinates[i] = parsedCoord
}
params["coords"] = ""
// Добавляем объект в комнату
roomsMutex.Lock()
defer roomsMutex.Unlock()
room.Modulation.AddObject(name, type_obj, [3]int{coordinates[0], coordinates[1], coordinates[2]}, params)
return nil
}
// UpdateObjectRequest вставляет базовые случайные данные в симуляцию
func (room *WebsocketRoom) UpdateObjectRequest(message websocket.SignalMessage) error {
// Тип объекта (тип сигнала)
type_obj := message.Signal - 20
// Определяем структуру для данных в поле `data`
var parsedData struct {
Name string `json:"name"`
Params map[string]string `json:"params"`
}
// Парсим `data` в структуру
err := json.Unmarshal(message.Data, &parsedData)
if err != nil {
return fmt.Errorf("[insert] error parsing data: %v", err)
}
// Получаем значения name и params
name := parsedData.Name
params := parsedData.Params
// Проверяем наличие координат в параметрах
if params["coords"] == "" {
return fmt.Errorf("[insert] coords is empty")
}
// Разделяем строку координат на отдельные элементы
coordinateStrings := strings.Split(params["coords"], ",")
// Инициализируем массив для хранения координат
coordinates := make([]int, len(coordinateStrings))
// Преобразуем каждую координату в целое число
for i, coord := range coordinateStrings {
parsedCoord, err := strconv.Atoi(strings.TrimSpace(coord))
if err != nil {
return fmt.Errorf("[insert] invalid coordinate: %s", coord)
}
coordinates[i] = parsedCoord
}
params["coords"] = ""
// Добавляем объект в комнату
roomsMutex.Lock()
defer roomsMutex.Unlock()
room.Modulation.AddObject(name, type_obj, [3]int{coordinates[0], coordinates[1], coordinates[2]}, params)
return nil
}
// InsertBasicData вставляет базовые случайные данные в симуляцию
func (room *WebsocketRoom) InsertExampleData() {
roomsMutex.Lock()
defer roomsMutex.Unlock()
room.Modulation.SpawnExampleData()
}
// InsertMapFromJson вставляет высоты и прочие данные карты в симуляцию, по шаблону
func (room *WebsocketRoom) InsertMapFromJson(template string) {
// TODO
roomsMutex.Lock()
defer roomsMutex.Unlock()
room.Modulation.DeleteObjectIfExists(template)
}
// InsertMapFromMongo вставляет высоты и прочие данные карты в симуляцию, из mongo по названию
func (room *WebsocketRoom) InsertMapFromMongo(name string) {
// TODO
roomsMutex.Lock()
defer roomsMutex.Unlock()
room.Modulation.DeleteObjectIfExists(name)
}
// RunSimulation запускает симуляцию в горутине
func (room *WebsocketRoom) RunSimulation(name string) {
// TODO +NormalizeDataForSimulation()
roomsMutex.Lock()
defer roomsMutex.Unlock()
room.Modulation.DeleteObjectIfExists(name)
}
// NormalizeDataForSimulation - Преобразование данных для отправки в симуляцию
func (room *WebsocketRoom) NormalizeDataForSimulation() {
// func (room *WebsocketRoom) NormalizeDataForSimulation() {
}
// }
// InitBroadCast - Инициализация раздачи контента участникам комнаты
func (room *WebsocketRoom) InitBroadCast() {
}
func SpawnSimulation(heightData [][]float64) {
// Пример карты высот, замените на настоящие данные
// heightData := [][]float64{
// {0, 10, 15, 20},
// {5, 15, 25, 30},
// {10, 20, 35, 40},
// {15, 25, 40, 50},
// }
// Определяем карту высот
mapObj := &simulator.Map{
Name: "Example Map",
MinBound: [3]float64{-1000, -1000, 0},
MaxBound: [3]float64{1000, 1000, 500},
HeightData: heightData,
}
// Определяем дронов
drones := []*simulator.Drone{
{
ID: 1,
Name: "Drone 1",
Coords: [3]float64{100, 100, 50},
Params: simulator.DroneParams{
AntennaRadius: 500,
AntennaDirection: [3]float64{1, 0, 0},
Waypoints: [][3]float64{{200, 200, 50}},
Speed: 10,
MeshName: "MeshA",
},
},
}
// Определяем базовые станции
baseStations := []*simulator.BaseStation{
{
ID: 1,
Name: "BaseStation1",
Coords: [3]float64{0, 0, 0},
Params: simulator.BaseStationParams{
AntennaRadius: 2000,
AntennaDirection: [3]float64{1, 0, 0},
},
},
}
// Создаем симуляцию
sim := &simulator.NetworkSimulation{
Map: mapObj,
Drones: drones,
BaseStations: baseStations,
TimeStep: 2,
}
// Запуск симуляции на 300 секунд
result_sim := sim.Simulate(300)
result := u_sorting.SortMap(result_sim)
for time, state := range result {
for localstate, f := range state {
fmt.Printf("%v| %v sec :: %v\n", time, localstate, f)
}
}
}
func (room *WebsocketRoom) WebsocketAction(message []byte) {
func (room *WebsocketRoom) WebsocketAction(message []byte) (error, bool) {
var Signal websocket.SignalMessage
err := json.Unmarshal(message, &Signal)
if err != nil {
fmt.Printf("[WebsocketAction] %v", err)
return fmt.Errorf("error parsing occured: %v \n waiting for signal struct", err), false
}
room.UpdateGroupUptime()
switch Signal.Signal {
case 0:
room.UpdateGroupUptime()
return nil, false
case 1:
room.InsertObject(Signal)
return nil, true
case 2:
room.InsertObject(Signal)
return nil, true
case 3:
room.DeleteMapObjectRequest(Signal)
return nil, true
case 21:
// Update Base Station
room.UpdateObjectRequest(Signal)
return nil, true
case 22:
// Update Drone
room.UpdateObjectRequest(Signal)
return nil, true
case 30:
// Init example data
room.InsertExampleData()
case 31:
case 32:
@ -197,4 +289,5 @@ func (room *WebsocketRoom) WebsocketAction(message []byte) {
// Запуск симуляции :: 100
// Пользователь исключен :: 301
return nil, false
}

View File

@ -2,6 +2,7 @@ package simulator
import (
"math"
"math/rand"
"moxitech/dns/package/math/distance"
"sync"
)
@ -259,3 +260,29 @@ func MakeExampleMap() Map {
}
return mapObj
}
// Создает полностью случаную карту
func MakeRandomMap() Map {
// Задаём случайное количество высот
numRows := rand.Intn(50) + 1 // Случайное количество строк (от 1 до 50)
numCols := rand.Intn(50) + 1 // Случайное количество столбцов (от 1 до 50)
// Инициализируем данные высот
heightData := make([][]float64, numRows)
for i := range heightData {
heightData[i] = make([]float64, numCols)
for j := range heightData[i] {
// Случайные значения высот
heightData[i][j] = rand.Float64() * 100 // высоты от 0 до 100
}
}
// Определяем карту высот
mapObj := Map{
Name: "RandomGeneratedMap",
MinBound: [3]float64{-2000, -2000, 0}, // Минимальные координаты
MaxBound: [3]float64{2000, 2000, 500}, // Максимальные координаты
HeightData: heightData, // Случайные высоты
}
return mapObj
}