Insert, update, exampling, delete over websocket
This commit is contained in:
parent
fa4be8d5ff
commit
f2e9c6f38f
1
.env
1
.env
@ -6,6 +6,7 @@ MONGO_INITDB_ROOT_PASSWORD=moxitech
|
|||||||
MONGO_INITDB_DATABASE=drone-network-simulator
|
MONGO_INITDB_DATABASE=drone-network-simulator
|
||||||
MONGO_INITDB_SIM_COLLECTION=simulations
|
MONGO_INITDB_SIM_COLLECTION=simulations
|
||||||
MONGO_INITDB_SIM_HIST_COLLECTION=simulations_history
|
MONGO_INITDB_SIM_HIST_COLLECTION=simulations_history
|
||||||
|
MONGO_INITDB_MAP_COLLECTION=map_templates
|
||||||
|
|
||||||
POSTGRES_DB=moxitech
|
POSTGRES_DB=moxitech
|
||||||
POSTGRES_USER=moxitech
|
POSTGRES_USER=moxitech
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package websocket
|
package websocket
|
||||||
|
|
||||||
import "moxitech/dns/package/math/simulator"
|
import (
|
||||||
|
"moxitech/dns/package/math/simulator"
|
||||||
|
"moxitech/dns/package/utils/randomizer"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type Modulation struct {
|
type Modulation struct {
|
||||||
Map *MapPartial `json:"map"`
|
Map *MapPartial `json:"map"`
|
||||||
@ -21,6 +25,91 @@ type SystemObject struct {
|
|||||||
Params *map[string]string `json:"params"`
|
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: ¶ms,
|
||||||
|
}
|
||||||
|
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: ¶ms,
|
||||||
|
}
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
@ -91,10 +91,16 @@ func CreateOrConnectSocket(c *websocket.Conn) {
|
|||||||
}
|
}
|
||||||
// LOGGING :
|
// LOGGING :
|
||||||
fmt.Printf("Received message from user %s: %s\n", userToken, msg)
|
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[groupHash])
|
||||||
data, err := json.Marshal(Rooms)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error marshal json: %v\n", err)
|
fmt.Printf("Error marshal json: %v\n", err)
|
||||||
}
|
}
|
||||||
@ -102,7 +108,7 @@ func CreateOrConnectSocket(c *websocket.Conn) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error writing message: %v\n", err)
|
fmt.Printf("Error writing message: %v\n", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Закрываем соединение при выходе
|
// Закрываем соединение при выходе
|
||||||
|
@ -5,7 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"moxitech/dns/entity/websocket"
|
"moxitech/dns/entity/websocket"
|
||||||
"moxitech/dns/package/math/simulator"
|
"moxitech/dns/package/math/simulator"
|
||||||
u_sorting "moxitech/dns/package/utils/sorting"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -79,102 +80,193 @@ func (room *WebsocketRoom) FlushGroupRequest() {
|
|||||||
// ... ДОБАВИТЬ ЛОГИКУ ИЗ WEBSOCKET ACTION ...
|
// ... ДОБАВИТЬ ЛОГИКУ ИЗ WEBSOCKET ACTION ...
|
||||||
//
|
//
|
||||||
|
|
||||||
// FlushGroupRequest сохраняет результат вычислений группы
|
// DeleteMapObjectRequest удаляет определенный объект
|
||||||
// @GroupEntity : WS entity -> сущность группы с данными и вычислениями
|
func (room *WebsocketRoom) DeleteMapObjectRequest(message websocket.SignalMessage) {
|
||||||
// func (room *WebsocketRoom) DeleteMapObjectRequest(name string) {
|
var parsedData struct {
|
||||||
// roomsMutex.Lock()
|
Name string `json:"name"`
|
||||||
// defer roomsMutex.Unlock()
|
}
|
||||||
// room.Modulation.Objects.DeleteObject(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 - Преобразование данных для отправки в симуляцию
|
// NormalizeDataForSimulation - Преобразование данных для отправки в симуляцию
|
||||||
func (room *WebsocketRoom) NormalizeDataForSimulation() {
|
// func (room *WebsocketRoom) NormalizeDataForSimulation() {
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
||||||
// InitBroadCast - Инициализация раздачи контента участникам комнаты
|
// InitBroadCast - Инициализация раздачи контента участникам комнаты
|
||||||
func (room *WebsocketRoom) InitBroadCast() {
|
func (room *WebsocketRoom) InitBroadCast() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func SpawnSimulation(heightData [][]float64) {
|
func (room *WebsocketRoom) WebsocketAction(message []byte) (error, bool) {
|
||||||
// Пример карты высот, замените на настоящие данные
|
|
||||||
// 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) {
|
|
||||||
var Signal websocket.SignalMessage
|
var Signal websocket.SignalMessage
|
||||||
err := json.Unmarshal(message, &Signal)
|
err := json.Unmarshal(message, &Signal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("[WebsocketAction] %v", err)
|
fmt.Printf("[WebsocketAction] %v", err)
|
||||||
|
return fmt.Errorf("error parsing occured: %v \n waiting for signal struct", err), false
|
||||||
}
|
}
|
||||||
|
room.UpdateGroupUptime()
|
||||||
switch Signal.Signal {
|
switch Signal.Signal {
|
||||||
case 0:
|
case 0:
|
||||||
room.UpdateGroupUptime()
|
room.UpdateGroupUptime()
|
||||||
|
return nil, false
|
||||||
case 1:
|
case 1:
|
||||||
|
room.InsertObject(Signal)
|
||||||
|
return nil, true
|
||||||
case 2:
|
case 2:
|
||||||
|
room.InsertObject(Signal)
|
||||||
|
return nil, true
|
||||||
case 3:
|
case 3:
|
||||||
|
room.DeleteMapObjectRequest(Signal)
|
||||||
|
return nil, true
|
||||||
case 21:
|
case 21:
|
||||||
|
// Update Base Station
|
||||||
|
room.UpdateObjectRequest(Signal)
|
||||||
|
return nil, true
|
||||||
|
|
||||||
case 22:
|
case 22:
|
||||||
|
// Update Drone
|
||||||
|
room.UpdateObjectRequest(Signal)
|
||||||
|
return nil, true
|
||||||
|
|
||||||
case 30:
|
case 30:
|
||||||
|
// Init example data
|
||||||
|
room.InsertExampleData()
|
||||||
case 31:
|
case 31:
|
||||||
case 32:
|
case 32:
|
||||||
|
|
||||||
@ -197,4 +289,5 @@ func (room *WebsocketRoom) WebsocketAction(message []byte) {
|
|||||||
// Запуск симуляции :: 100
|
// Запуск симуляции :: 100
|
||||||
|
|
||||||
// Пользователь исключен :: 301
|
// Пользователь исключен :: 301
|
||||||
|
return nil, false
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package simulator
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
"math/rand"
|
||||||
"moxitech/dns/package/math/distance"
|
"moxitech/dns/package/math/distance"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
@ -259,3 +260,29 @@ func MakeExampleMap() Map {
|
|||||||
}
|
}
|
||||||
return mapObj
|
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
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user