25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

200 lines
5.2 KiB

  1. package main
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "net/http"
  7. "strings"
  8. "github.com/AFASystems/presence/internal/pkg/kafkaclient"
  9. "github.com/AFASystems/presence/internal/pkg/model"
  10. "github.com/gorilla/handlers"
  11. "github.com/gorilla/mux"
  12. "github.com/redis/go-redis/v9"
  13. "github.com/segmentio/kafka-go"
  14. )
  15. func main() {
  16. HttpServer("0.0.0.0:1902")
  17. }
  18. func HttpServer(addr string) {
  19. headersOk := handlers.AllowedHeaders([]string{"X-Requested-With"})
  20. originsOk := handlers.AllowedOrigins([]string{"*"})
  21. methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"})
  22. // Kafka writer that relays messages
  23. writer := kafkaclient.KafkaWriter("kafka:9092", "apibeacons")
  24. defer writer.Close()
  25. settingsWriter := kafkaclient.KafkaWriter("kafka:9092", "settings")
  26. defer settingsWriter.Close()
  27. r := mux.NewRouter()
  28. client := redis.NewClient(&redis.Options{
  29. Addr: "valkey:6379",
  30. Password: "",
  31. })
  32. // For now just add beacon DELETE / GET / POST / PUT methods
  33. r.HandleFunc("/api/beacons/{beacon_id}", beaconsDeleteHandler(writer)).Methods("DELETE")
  34. r.HandleFunc("/api/beacons", beaconsListHandler(client)).Methods("GET")
  35. r.HandleFunc("/api/beacons", beaconsAddHandler(writer)).Methods("POST")
  36. r.HandleFunc("/api/beacons", beaconsAddHandler(writer)).Methods("PUT")
  37. r.HandleFunc("/api/settings", settingsListHandler(client)).Methods("GET")
  38. r.HandleFunc("/api/settings", settingsEditHandler(settingsWriter)).Methods("POST")
  39. http.ListenAndServe(addr, handlers.CORS(originsOk, headersOk, methodsOk)(r))
  40. }
  41. // This looks wrong, should handle error somehow
  42. func sendKafkaMessage(writer *kafka.Writer, value *model.ApiUpdate) bool {
  43. valueStr, err := json.Marshal(&value)
  44. if err != nil {
  45. fmt.Println("error in encoding: ", err)
  46. return false
  47. }
  48. msg := kafka.Message{
  49. Value: valueStr,
  50. }
  51. err = writer.WriteMessages(context.Background(), msg)
  52. if err != nil {
  53. fmt.Println("Error in sending kafka message: ")
  54. return false
  55. }
  56. return true
  57. }
  58. func beaconsDeleteHandler(writer *kafka.Writer) http.HandlerFunc {
  59. return func(w http.ResponseWriter, r *http.Request) {
  60. vars := mux.Vars(r)
  61. beaconId := vars["beacon_id"]
  62. apiUpdate := model.ApiUpdate{
  63. Method: "DELETE",
  64. ID: beaconId,
  65. }
  66. flag := sendKafkaMessage(writer, &apiUpdate)
  67. if !flag {
  68. fmt.Println("error in sending Kafka message")
  69. http.Error(w, "Error in sending kafka message", 500)
  70. return
  71. }
  72. w.Write([]byte("ok"))
  73. }
  74. }
  75. func beaconsAddHandler(writer *kafka.Writer) http.HandlerFunc {
  76. return func(w http.ResponseWriter, r *http.Request) {
  77. decoder := json.NewDecoder(r.Body)
  78. var inBeacon model.Beacon
  79. err := decoder.Decode(&inBeacon)
  80. if err != nil {
  81. http.Error(w, err.Error(), 400)
  82. return
  83. }
  84. if (len(strings.TrimSpace(inBeacon.Name)) == 0) || (len(strings.TrimSpace(inBeacon.Beacon_id)) == 0) {
  85. http.Error(w, "name and beacon_id cannot be blank", 400)
  86. return
  87. }
  88. apiUpdate := model.ApiUpdate{
  89. Method: "POST",
  90. Beacon: inBeacon,
  91. }
  92. flag := sendKafkaMessage(writer, &apiUpdate)
  93. if !flag {
  94. fmt.Println("error in sending Kafka message")
  95. http.Error(w, "Error in sending kafka message", 500)
  96. return
  97. }
  98. w.Write([]byte("ok"))
  99. }
  100. }
  101. func beaconsListHandler(client *redis.Client) http.HandlerFunc {
  102. return func(w http.ResponseWriter, r *http.Request) {
  103. beaconsList, err := client.Get(context.Background(), "beaconsList").Result()
  104. if err == redis.Nil {
  105. fmt.Println("no beacons list, starting empty")
  106. http.Error(w, "list is empty", 500)
  107. } else if err != nil {
  108. http.Error(w, "Internal server error", 500)
  109. panic(err)
  110. } else {
  111. w.Write([]byte(beaconsList))
  112. }
  113. }
  114. }
  115. func settingsListHandler(client *redis.Client) http.HandlerFunc {
  116. return func(w http.ResponseWriter, r *http.Request) {
  117. settings, err := client.Get(context.Background(), "settings").Result()
  118. if err == redis.Nil {
  119. fmt.Println("no settings persisted, starting empty")
  120. http.Error(w, "list is empty", 500)
  121. } else if err != nil {
  122. http.Error(w, "Internal server error", 500)
  123. panic(err)
  124. } else {
  125. w.Write([]byte(settings))
  126. }
  127. }
  128. }
  129. func settingsEditHandler(writer *kafka.Writer) http.HandlerFunc {
  130. return func(w http.ResponseWriter, r *http.Request) {
  131. decoder := json.NewDecoder(r.Body)
  132. var inSettings model.SettingsVal
  133. if err := decoder.Decode(&inSettings); err != nil {
  134. http.Error(w, err.Error(), 400)
  135. fmt.Println("Error in decoding Settings body: ", err)
  136. return
  137. }
  138. if !settingsCheck(inSettings) {
  139. http.Error(w, "values must be greater than 0", 400)
  140. fmt.Println("settings values must be greater than 0")
  141. return
  142. }
  143. valueStr, err := json.Marshal(&inSettings)
  144. if err != nil {
  145. http.Error(w, "Error in encoding settings", 500)
  146. fmt.Println("Error in encoding settings: ", err)
  147. return
  148. }
  149. msg := kafka.Message{
  150. Value: valueStr,
  151. }
  152. if err := writer.WriteMessages(context.Background(), msg); err != nil {
  153. fmt.Println("error in sending Kafka message")
  154. http.Error(w, "Error in sending kafka message", 500)
  155. return
  156. }
  157. w.Write([]byte("ok"))
  158. }
  159. }
  160. func settingsCheck(settings model.SettingsVal) bool {
  161. if settings.Location_confidence <= 0 || settings.Last_seen_threshold <= 0 || settings.HA_send_interval <= 0 {
  162. return false
  163. }
  164. return true
  165. }