Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 

196 рядки
5.7 KiB

  1. package main
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "log"
  7. "net/http"
  8. "os/signal"
  9. "strings"
  10. "sync"
  11. "syscall"
  12. "time"
  13. "github.com/AFASystems/presence/internal/pkg/common/appcontext"
  14. "github.com/AFASystems/presence/internal/pkg/config"
  15. "github.com/AFASystems/presence/internal/pkg/controller"
  16. "github.com/AFASystems/presence/internal/pkg/kafkaclient"
  17. "github.com/AFASystems/presence/internal/pkg/model"
  18. "github.com/AFASystems/presence/internal/pkg/service"
  19. "github.com/gorilla/handlers"
  20. "github.com/gorilla/mux"
  21. "github.com/gorilla/websocket"
  22. )
  23. var upgrader = websocket.Upgrader{
  24. ReadBufferSize: 1024,
  25. WriteBufferSize: 1024,
  26. }
  27. var wg sync.WaitGroup
  28. func main() {
  29. cfg := config.Load()
  30. appState := appcontext.NewAppState()
  31. // define context
  32. ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
  33. defer stop()
  34. headersOk := handlers.AllowedHeaders([]string{"X-Requested-With"})
  35. originsOk := handlers.AllowedOrigins([]string{"*"})
  36. methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"})
  37. writer := appState.AddKafkaWriter(cfg.KafkaURL, "apibeacons")
  38. settingsWriter := appState.AddKafkaWriter(cfg.KafkaURL, "settings")
  39. locationReader := appState.AddKafkaReader(cfg.KafkaURL, "locevents", "gid-loc-server")
  40. alertsReader := appState.AddKafkaReader(cfg.KafkaURL, "alertbeacons", "gid-alert-serv")
  41. client := appState.AddValkeyClient(cfg.ValkeyURL)
  42. fmt.Println("Init of kafka writers and readers done")
  43. chLoc := make(chan model.HTTPLocation, 200)
  44. chEvents := make(chan model.BeaconEvent, 500)
  45. wg.Add(2)
  46. go kafkaclient.Consume(locationReader, chLoc, ctx, &wg)
  47. go kafkaclient.Consume(alertsReader, chEvents, ctx, &wg)
  48. r := mux.NewRouter()
  49. fmt.Println("new print")
  50. fmt.Println("new print")
  51. // For now just add beacon DELETE / GET / POST / PUT methods
  52. r.HandleFunc("/api/beacons/{beacon_id}", controller.BeaconsDeleteController(writer, ctx, appState)).Methods("DELETE")
  53. r.HandleFunc("/api/beacons", controller.BeaconsListController(appState)).Methods("GET")
  54. r.HandleFunc("/api/beacons/{beacon_id}", controller.BeaconsListSingleController(appState)).Methods("GET")
  55. r.HandleFunc("/api/beacons", controller.BeaconsAddController(writer, ctx)).Methods("POST")
  56. r.HandleFunc("/api/beacons", controller.BeaconsAddController(writer, ctx)).Methods("PUT")
  57. r.HandleFunc("/api/settings", controller.SettingsListController(appState, client, ctx)).Methods("GET")
  58. r.HandleFunc("/api/settings", controller.SettingsEditController(settingsWriter, appState, client, ctx)).Methods("POST")
  59. wsHandler := http.HandlerFunc(serveWs(appState, ctx))
  60. restApiHandler := handlers.CORS(originsOk, headersOk, methodsOk)(r)
  61. mainHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  62. if strings.HasPrefix(r.URL.Path, "/api/beacons/ws") {
  63. wsHandler.ServeHTTP(w, r)
  64. return
  65. }
  66. restApiHandler.ServeHTTP(w, r)
  67. })
  68. server := http.Server{
  69. Addr: cfg.HTTPAddr,
  70. Handler: mainHandler,
  71. }
  72. go server.ListenAndServe()
  73. eventLoop:
  74. for {
  75. select {
  76. case <-ctx.Done():
  77. break eventLoop
  78. case msg := <-chLoc:
  79. if err := service.LocationToBeaconService(msg, appState, client, ctx); err != nil {
  80. fmt.Printf("Error in writing location change to beacon: %v\n", err)
  81. }
  82. case msg := <-chEvents:
  83. if err := service.EventToBeaconService(msg, appState, client, ctx); err != nil {
  84. fmt.Printf("Error in writing event change to beacon: %v\n", err)
  85. }
  86. }
  87. }
  88. if err := server.Shutdown(context.Background()); err != nil {
  89. fmt.Printf("could not shutdown: %v\n", err)
  90. }
  91. fmt.Println("broken out of the main event loop and HTTP server shutdown")
  92. wg.Wait()
  93. fmt.Println("All go routines have stopped, Beggining to close Kafka connections")
  94. appState.CleanKafkaReaders()
  95. appState.CleanKafkaWriters()
  96. fmt.Println("All kafka clients shutdown, starting shutdown of valkey client")
  97. appState.CleanValkeyClient()
  98. }
  99. func serveWs(appstate *appcontext.AppState, ctx context.Context) http.HandlerFunc {
  100. return func(w http.ResponseWriter, r *http.Request) {
  101. ws, err := upgrader.Upgrade(w, r, nil)
  102. if err != nil {
  103. if _, ok := err.(websocket.HandshakeError); !ok {
  104. log.Println(err)
  105. }
  106. return
  107. }
  108. wg.Add(2)
  109. go writer(ws, appstate, ctx)
  110. go reader(ws, ctx)
  111. }
  112. }
  113. func writer(ws *websocket.Conn, appstate *appcontext.AppState, ctx context.Context) {
  114. pingTicker := time.NewTicker((60 * 9) / 10 * time.Second)
  115. beaconTicker := time.NewTicker(2 * time.Second)
  116. defer func() {
  117. pingTicker.Stop()
  118. beaconTicker.Stop()
  119. ws.Close()
  120. wg.Done()
  121. }()
  122. for {
  123. select {
  124. case <-ctx.Done():
  125. log.Println("WebSocket writer received shutdown signal.")
  126. ws.SetWriteDeadline(time.Now().Add(10 * time.Second))
  127. ws.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
  128. return
  129. case <-beaconTicker.C:
  130. beacons := appstate.GetAllBeacons()
  131. js, err := json.Marshal(beacons)
  132. if err != nil {
  133. js = []byte("error")
  134. }
  135. ws.SetWriteDeadline(time.Now().Add(10 * time.Second))
  136. if err := ws.WriteMessage(websocket.TextMessage, js); err != nil {
  137. return
  138. }
  139. case <-pingTicker.C:
  140. ws.SetWriteDeadline(time.Now().Add(10 * time.Second))
  141. if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
  142. return
  143. }
  144. }
  145. }
  146. }
  147. func reader(ws *websocket.Conn, ctx context.Context) {
  148. defer func() {
  149. ws.Close()
  150. wg.Done()
  151. }()
  152. ws.SetReadLimit(512)
  153. ws.SetReadDeadline(time.Now().Add((60 * 9) / 10 * time.Second))
  154. ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add((60 * 9) / 10 * time.Second)); return nil })
  155. for {
  156. fmt.Println("this is called")
  157. select {
  158. case <-ctx.Done():
  159. fmt.Println("closing websocket reader")
  160. return
  161. default:
  162. _, _, err := ws.ReadMessage()
  163. if err != nil {
  164. return
  165. }
  166. }
  167. }
  168. }