25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 

205 satır
6.8 KiB

  1. package main
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "log"
  8. "log/slog"
  9. "net/http"
  10. "os"
  11. "os/signal"
  12. "sync"
  13. "syscall"
  14. "time"
  15. "github.com/AFASystems/presence/internal/pkg/apiclient"
  16. "github.com/AFASystems/presence/internal/pkg/common/appcontext"
  17. "github.com/AFASystems/presence/internal/pkg/config"
  18. "github.com/AFASystems/presence/internal/pkg/controller"
  19. "github.com/AFASystems/presence/internal/pkg/database"
  20. "github.com/AFASystems/presence/internal/pkg/kafkaclient"
  21. "github.com/AFASystems/presence/internal/pkg/logger"
  22. "github.com/AFASystems/presence/internal/pkg/model"
  23. "github.com/AFASystems/presence/internal/pkg/service"
  24. "github.com/gorilla/handlers"
  25. "github.com/gorilla/mux"
  26. "github.com/gorilla/websocket"
  27. "github.com/segmentio/kafka-go"
  28. )
  29. var upgrader = websocket.Upgrader{
  30. ReadBufferSize: 1024,
  31. WriteBufferSize: 1024,
  32. }
  33. var _ io.Writer = (*os.File)(nil)
  34. var wg sync.WaitGroup
  35. func main() {
  36. cfg := config.Load()
  37. appState := appcontext.NewAppState()
  38. // Set logger -> terminal and log file
  39. slog.SetDefault(logger.CreateLogger("server.log"))
  40. // define context
  41. ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
  42. defer stop()
  43. db, err := database.Connect(cfg)
  44. if err != nil {
  45. log.Fatalf("Failed to open database connection: %v\n", err)
  46. }
  47. headersOk := handlers.AllowedHeaders([]string{"X-Requested-With"})
  48. originsOk := handlers.AllowedOrigins([]string{"*"})
  49. methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"})
  50. writer := appState.AddKafkaWriter(cfg.KafkaURL, "apibeacons")
  51. settingsWriter := appState.AddKafkaWriter(cfg.KafkaURL, "settings")
  52. alertWriter := appState.AddKafkaWriter(cfg.KafkaURL, "alert")
  53. parserWriter := appState.AddKafkaWriter(cfg.KafkaURL, "parser")
  54. mqttWriter := appState.AddKafkaWriter(cfg.KafkaURL, "mqtt")
  55. slog.Info("Kafka writers topics: apibeacons, settings initialized")
  56. configFile, err := os.Open("/app/cmd/server/config.json")
  57. if err != nil {
  58. panic(err)
  59. }
  60. b, _ := io.ReadAll(configFile)
  61. var configs []model.Config
  62. json.Unmarshal(b, &configs)
  63. for _, config := range configs {
  64. // persist read configs in database
  65. db.Create(&config)
  66. }
  67. db.Find(&configs)
  68. for _, config := range configs {
  69. kp := model.KafkaParser{
  70. ID: "add",
  71. Config: config,
  72. }
  73. if err := service.SendParserConfig(kp, parserWriter, ctx); err != nil {
  74. fmt.Printf("Unable to send parser config to kafka broker %v\n", err)
  75. }
  76. }
  77. if err := apiclient.UpdateDB(db, ctx, cfg, writer, appState); err != nil {
  78. fmt.Printf("Error in getting token: %v\n", err)
  79. }
  80. locationReader := appState.AddKafkaReader(cfg.KafkaURL, "locevents", "gid-loc-server")
  81. alertsReader := appState.AddKafkaReader(cfg.KafkaURL, "alertbeacons", "gid-alert-serv")
  82. slog.Info("Kafka readers topics: locevents, alertbeacons initialized")
  83. chLoc := make(chan model.HTTPLocation, 200)
  84. chEvents := make(chan model.BeaconEvent, 500)
  85. wg.Add(2)
  86. go kafkaclient.Consume(locationReader, chLoc, ctx, &wg)
  87. go kafkaclient.Consume(alertsReader, chEvents, ctx, &wg)
  88. r := mux.NewRouter()
  89. r.HandleFunc("/reslevis/getGateways", controller.GatewayListController(db)).Methods("GET")
  90. r.HandleFunc("/reslevis/postGateway", controller.GatewayAddController(db)).Methods("POST")
  91. r.HandleFunc("/reslevis/removeGateway/{id}", controller.GatewayDeleteController(db)).Methods("DELETE")
  92. r.HandleFunc("/reslevis/updateGateway/{id}", controller.GatewayUpdateController(db)).Methods("PUT")
  93. r.HandleFunc("/reslevis/getZones", controller.ZoneListController(db)).Methods("GET")
  94. r.HandleFunc("/reslevis/postZone", controller.ZoneAddController(db)).Methods("POST")
  95. r.HandleFunc("/reslevis/removeZone/{id}", controller.ZoneDeleteController(db)).Methods("DELETE")
  96. r.HandleFunc("/reslevis/updateZone", controller.ZoneUpdateController(db)).Methods("PUT")
  97. r.HandleFunc("/reslevis/getTrackerZones", controller.TrackerZoneListController(db)).Methods("GET")
  98. r.HandleFunc("/reslevis/postTrackerZone", controller.TrackerZoneAddController(db)).Methods("POST")
  99. r.HandleFunc("/reslevis/removeTrackerZone/{id}", controller.TrackerZoneDeleteController(db)).Methods("DELETE")
  100. r.HandleFunc("/reslevis/updateTrackerZone", controller.TrackerZoneUpdateController(db)).Methods("PUT")
  101. r.HandleFunc("/reslevis/getTrackers", controller.TrackerList(db)).Methods("GET")
  102. r.HandleFunc("/reslevis/postTracker", controller.TrackerAdd(db, writer, ctx)).Methods("POST")
  103. r.HandleFunc("/reslevis/removeTracker/{id}", controller.TrackerDelete(db, writer, ctx)).Methods("DELETE")
  104. r.HandleFunc("/reslevis/updateTracker", controller.TrackerUpdate(db)).Methods("PUT")
  105. r.HandleFunc("/configs/beacons", controller.ParserListController(db)).Methods("GET")
  106. r.HandleFunc("/configs/beacons", controller.ParserAddController(db, parserWriter, ctx)).Methods("POST")
  107. r.HandleFunc("/configs/beacons/{id}", controller.ParserUpdateController(db, parserWriter, ctx)).Methods("PUT")
  108. r.HandleFunc("/configs/beacons/{id}", controller.ParserDeleteController(db, parserWriter, ctx)).Methods("DELETE")
  109. r.HandleFunc("/reslevis/settings", controller.SettingsUpdateController(db, settingsWriter, ctx)).Methods("PATCH")
  110. r.HandleFunc("/reslevis/settings", controller.SettingsListController(db)).Methods("GET")
  111. beaconTicker := time.NewTicker(2 * time.Second)
  112. restApiHandler := handlers.CORS(originsOk, headersOk, methodsOk)(r)
  113. mainHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  114. restApiHandler.ServeHTTP(w, r)
  115. })
  116. server := http.Server{
  117. Addr: cfg.HTTPAddr,
  118. Handler: mainHandler,
  119. }
  120. go server.ListenAndServe()
  121. eventLoop:
  122. for {
  123. select {
  124. case <-ctx.Done():
  125. break eventLoop
  126. case msg := <-chLoc:
  127. service.LocationToBeaconService(msg, db, alertWriter, ctx)
  128. case msg := <-chEvents:
  129. fmt.Printf("event: %+v\n", msg)
  130. id := msg.ID
  131. if err := db.First(&model.Tracker{}, "id = ?", id).Error; err != nil {
  132. fmt.Printf("Decoder event for untracked beacon: %s\n", id)
  133. continue
  134. }
  135. if err := db.Updates(&model.Tracker{ID: id, Battery: msg.Battery}).Error; err != nil {
  136. fmt.Printf("Error in saving decoder event for beacon: %s\n", id)
  137. continue
  138. }
  139. case <-beaconTicker.C:
  140. var list []model.Tracker
  141. db.Find(&list)
  142. eMsg, err := json.Marshal(list)
  143. if err != nil {
  144. fmt.Printf("Error in marshaling trackers list: %v\n", err)
  145. continue
  146. }
  147. msg := kafka.Message{
  148. Value: eMsg,
  149. }
  150. mqttWriter.WriteMessages(ctx, msg)
  151. }
  152. }
  153. if err := server.Shutdown(context.Background()); err != nil {
  154. eMsg := fmt.Sprintf("could not shutdown: %v\n", err)
  155. slog.Error(eMsg)
  156. }
  157. slog.Info("API SERVER: \n")
  158. slog.Warn("broken out of the main event loop and HTTP server shutdown\n")
  159. wg.Wait()
  160. slog.Info("All go routines have stopped, Beggining to close Kafka connections\n")
  161. appState.CleanKafkaReaders()
  162. appState.CleanKafkaWriters()
  163. slog.Info("All kafka clients shutdown, starting shutdown of valkey client")
  164. slog.Info("API server shutting down")
  165. }