diff --git a/src/frontend/src/Services/WebsocketHook.js b/src/frontend/src/Services/WebsocketHook.js
index 807cb93..ad2aa59 100644
--- a/src/frontend/src/Services/WebsocketHook.js
+++ b/src/frontend/src/Services/WebsocketHook.js
@@ -156,6 +156,16 @@ export const DeleteSignal = (name) => {
};
};
+export const RunSimulatorSignal = (id) => {
+ const signal = 100;
+
+ return {
+ signal,
+ data: {
+ id,
+ },
+ };
+};
diff --git a/src/frontend/src/pages/Dashboard.js b/src/frontend/src/pages/Dashboard.js
index a5f1cf2..8ba9860 100644
--- a/src/frontend/src/pages/Dashboard.js
+++ b/src/frontend/src/pages/Dashboard.js
@@ -7,7 +7,7 @@ import HeightPoint from './model/HeightPoint';
import { RandomHeightPoint } from './helpers/generateRandomHeightPoints'
import ModalWindow from './components/Modal/Modal';
import { getCustomCookie } from '../Services/Local';
-import useWebsocketConnection, { DeleteSignal, spawnJsonSignal } from '../Services/WebsocketHook';
+import useWebsocketConnection, { DeleteSignal, spawnJsonSignal, RunSimulatorSignal } from '../Services/WebsocketHook';
import './Dashboard.css';
@@ -781,7 +781,10 @@ const containsObjectRecursively = (parent, target) => {
diff --git a/src/server/entity/websocket/models.go b/src/server/entity/websocket/models.go
index ec53d79..efe9405 100644
--- a/src/server/entity/websocket/models.go
+++ b/src/server/entity/websocket/models.go
@@ -3,7 +3,10 @@ package websocket
import (
"fmt"
"moxitech/dns/package/math/simulator"
+ sim_queue "moxitech/dns/package/simulation"
"moxitech/dns/package/utils/randomizer"
+ "strconv"
+ "strings"
"time"
)
@@ -49,75 +52,112 @@ func (o *Modulation) MirrorPayloadToSimulationStruct() Modulation {
return shadow_sim_copy
}
-func (o *Modulation) RunSimulator() {
- // // Пример карты высот, замените на настоящие данные
- // heightData := [][]float64{
- // {0, 10, 15, 20},
- // {5, 15, 25, 30},
- // {10, 20, 35, 40},
- // {15, 25, 40, 50},
- // }
+// StartNewSimulation - инициирует парсинг и добавление в очередь для обработки симуляции
+func (o *Modulation) StartNewSimulation(timestep int, user_id string) {
+ mapObj := o.Map
+ drones := []*simulator.Drone{}
+ stations := []*simulator.BaseStation{}
- // // Определяем карту высот
- //
- // mapObj := &simulator.Map{
- // Name: "Example Map",
- // MinBound: [3]float64{-1000, -1000, 0},
- // MaxBound: [3]float64{1000, 1000, 500},
- // HeightData: heightData,
- // }
- //
- // ? mapObj := o.Map
+ for i, v := range o.Objects {
+ if v.Params == nil {
+ continue
+ }
- // // Определяем дронов
- //
- // 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)
- // }
- // }
+ params := *v.Params
+ if v.Type == 1 {
+ // Парсинг параметров для дронов
+ antennaDirection := [3]float64{1, 0, 0} // значение по умолчанию
+ if dir, ok := params["antennaDirections"]; ok && dir != "" {
+ directionValues := strings.Split(dir, ",")
+ if len(directionValues) == 3 {
+ antennaDirection[0], _ = strconv.ParseFloat(directionValues[0], 64)
+ antennaDirection[1], _ = strconv.ParseFloat(directionValues[1], 64)
+ antennaDirection[2], _ = strconv.ParseFloat(directionValues[2], 64)
+ }
+ }
+
+ antennaRadius := 100.0 // значение по умолчанию
+ if radius, ok := params["antennaRadius"]; ok && radius != "" {
+ antennaRadius, _ = strconv.ParseFloat(radius, 64)
+ }
+
+ waypoints := [][3]float64{}
+ if wp, ok := params["wayPoints"]; ok && wp != "" {
+ // Парсинг waypoints, предполагаем, что это строка вида "x1,y1,z1;x2,y2,z2"
+ waypointStrings := strings.Split(wp, ";")
+ for _, waypointStr := range waypointStrings {
+ coords := strings.Split(waypointStr, ",")
+ if len(coords) == 3 {
+ x, _ := strconv.ParseFloat(coords[0], 64)
+ y, _ := strconv.ParseFloat(coords[1], 64)
+ z, _ := strconv.ParseFloat(coords[2], 64)
+ waypoints = append(waypoints, [3]float64{x, y, z})
+ }
+ }
+ }
+
+ speed := 0.0
+ if spd, ok := params["speed"]; ok && spd != "" {
+ speed, _ = strconv.ParseFloat(spd, 64)
+ }
+
+ meshName := ""
+ if mesh, ok := params["meshName"]; ok {
+ meshName = mesh
+ }
+
+ drone := simulator.Drone{
+ ID: i,
+ Name: v.Name,
+ Coords: [3]float64{float64(v.Coords[0]), float64(v.Coords[1]), float64(v.Coords[2])},
+ Params: simulator.DroneParams{
+ AntennaRadius: antennaRadius,
+ AntennaDirection: antennaDirection,
+ Waypoints: waypoints,
+ Speed: speed,
+ MeshName: meshName,
+ },
+ }
+ drones = append(drones, &drone)
+ }
+
+ if v.Type == 2 {
+ // Парсинг параметров для базовых станций
+ antennaDirection := [3]float64{1, 0, 0} // значение по умолчанию
+ if dir, ok := params["antennaDirections"]; ok && dir != "" {
+ directionValues := strings.Split(dir, ",")
+ if len(directionValues) == 3 {
+ antennaDirection[0], _ = strconv.ParseFloat(directionValues[0], 64)
+ antennaDirection[1], _ = strconv.ParseFloat(directionValues[1], 64)
+ antennaDirection[2], _ = strconv.ParseFloat(directionValues[2], 64)
+ }
+ }
+
+ antennaRadius := 200.0 // значение по умолчанию
+ if radius, ok := params["antennaRadius"]; ok && radius != "" {
+ antennaRadius, _ = strconv.ParseFloat(radius, 64)
+ }
+
+ baseStation := simulator.BaseStation{
+ ID: i,
+ Name: v.Name,
+ Coords: [3]float64{float64(v.Coords[0]), float64(v.Coords[1]), float64(v.Coords[2])},
+ Params: simulator.BaseStationParams{
+ AntennaRadius: antennaRadius,
+ AntennaDirection: antennaDirection,
+ },
+ }
+ stations = append(stations, &baseStation)
+ }
+ }
+
+ sim := &simulator.NetworkSimulation{
+ Map: &mapObj.Map,
+ Drones: drones,
+ BaseStations: stations,
+ TimeStep: timestep,
+ }
+ sim_queue.AddSimulationTask(*sim, user_id)
}
// SpawnExampleData создает случайные данные и перезаписывает карту
diff --git a/src/server/internal/server/server.go b/src/server/internal/server/server.go
index 75c12c6..852851e 100644
--- a/src/server/internal/server/server.go
+++ b/src/server/internal/server/server.go
@@ -5,6 +5,7 @@ import (
"fmt"
"moxitech/dns/entity/dto"
"moxitech/dns/internal/server/handlers/authorization"
+ sim_queue "moxitech/dns/package/simulation"
"os"
"runtime"
"strconv"
@@ -20,6 +21,8 @@ var (
)
func SpawnServer() error {
+ sim_queue.Start()
+ go sim_queue.InvokeComplete()
app := fiber.New()
app.Use(cors.New(cors.Config{
AllowHeaders: "*",
diff --git a/src/server/internal/server/websocket.go b/src/server/internal/server/websocket.go
index fce4708..c2da07f 100644
--- a/src/server/internal/server/websocket.go
+++ b/src/server/internal/server/websocket.go
@@ -230,12 +230,22 @@ func (room *WebsocketRoom) InsertMapFromMongo(name string) {
}
// RunSimulation запускает симуляцию в горутине
-func (room *WebsocketRoom) RunSimulation(name string) (int, error) {
- // TODO +NormalizeDataForSimulation()
+func (room *WebsocketRoom) RunSimulation(message websocket.SignalMessage) (int, error) {
+ var parsedData struct {
+ UserInvoked string `json:"id"`
+ }
+ // Парсим `data` в структуру
+ err := json.Unmarshal(message.Data, &parsedData)
+ if err != nil {
+ return -1, fmt.Errorf("[insert] error parsing data: %v", err)
+ }
+ if parsedData.UserInvoked == "" {
+ return -1, fmt.Errorf("[insert] Error parse userID: %v", err)
+ }
roomsMutex.Lock()
defer roomsMutex.Unlock()
- room.Modulation.MirrorPayloadToSimulationStruct()
- return -1, nil
+ room.Modulation.StartNewSimulation(100, parsedData.UserInvoked)
+ return 0, nil
}
// NormalizeDataForSimulation - Преобразование данных для отправки в симуляцию
@@ -255,6 +265,7 @@ func (room *WebsocketRoom) WebsocketAction(message []byte) (error, bool) {
fmt.Printf("[WebsocketAction] %v", err)
return fmt.Errorf("error parsing occured: %v \n waiting for signal struct", err), false
}
+ fmt.Println("Run collector")
room.UpdateGroupUptime()
switch Signal.Signal {
case 0:
@@ -264,6 +275,7 @@ func (room *WebsocketRoom) WebsocketAction(message []byte) (error, bool) {
room.InsertObject(Signal)
return nil, true
case 2:
+ fmt.Println("Начата вставка объекта")
room.InsertObject(Signal)
return nil, true
case 3:
@@ -287,6 +299,8 @@ func (room *WebsocketRoom) WebsocketAction(message []byte) (error, bool) {
case 33:
// SYNC SIGNAL
case 100:
+ fmt.Println("Запуск симуляции : ", Signal)
+ room.RunSimulation(Signal)
case 101:
// room.StoreMongo(Signal)
diff --git a/src/server/package/simulation/sim_queue.go b/src/server/package/simulation/sim_queue.go
new file mode 100644
index 0000000..b70780d
--- /dev/null
+++ b/src/server/package/simulation/sim_queue.go
@@ -0,0 +1,60 @@
+package sim_queue
+
+import (
+ "encoding/json"
+ "fmt"
+ "moxitech/dns/package/math/simulator"
+ "net/http"
+)
+
+var (
+ AddChannel = make(chan simulator.NetworkSimulation)
+ CompleteChannel = make(chan *simulationResult)
+)
+
+type simulationResult struct {
+ Sim *simulator.NetworkSimulation
+ UserID string
+}
+
+// AddSimulationTask adds a network simulation to the queue and runs it in a goroutine.
+func AddSimulationTask(sim simulator.NetworkSimulation, userID string) {
+ AddChannel <- sim
+ CompleteChannel <- &simulationResult{Sim: &sim, UserID: userID}
+}
+
+// InvokeComplete listens for completed simulations, serializes them to JSON, and sends to a specified endpoint.
+func InvokeComplete() {
+ for result := range CompleteChannel {
+ go func(result *simulationResult) {
+ jsonData, err := json.Marshal(result.Sim)
+ if err != nil {
+ fmt.Println("Error serializing simulation result:", err)
+ return
+ }
+ url := fmt.Sprintf("http://socket:9091/storeEvent?client_id=%s&message=%s", result.UserID, string(jsonData))
+ resp, err := http.Get(url)
+ if err != nil {
+ fmt.Println("Error sending simulation result:", err)
+ return
+ }
+ // database.Instance.InsertIntoSimulations(jsonData)
+ defer resp.Body.Close()
+ }(result)
+ }
+}
+
+// Start starts listening on the channels to manage simulations.
+func Start() {
+ go func() {
+ for sim := range AddChannel {
+ go runSimulation(sim)
+ }
+ }()
+}
+
+// runSimulation runs a simulation and then sends it to the CompleteChannel.
+func runSimulation(sim simulator.NetworkSimulation) {
+ sim.Simulate(sim.TimeStep) // Run the simulation for 300 iterations (as an example)
+ CompleteChannel <- &simulationResult{Sim: &sim}
+}