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.
 
 
 
 

287 satır
7.3 KiB

  1. package main
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "net/http"
  7. "strings"
  8. "time"
  9. "github.com/AFASystems/presence/internal/pkg/kafkaclient"
  10. "github.com/AFASystems/presence/internal/pkg/model"
  11. "github.com/gorilla/handlers"
  12. "github.com/gorilla/mux"
  13. "github.com/gorilla/websocket"
  14. "github.com/redis/go-redis/v9"
  15. "github.com/segmentio/kafka-go"
  16. )
  17. var upgrader = websocket.Upgrader{
  18. CheckOrigin: func(r *http.Request) bool { return true },
  19. }
  20. type Message struct {
  21. Type string `json:"type"`
  22. Data interface{} `json:"data"`
  23. }
  24. func main() {
  25. HttpServer("0.0.0.0:1902")
  26. }
  27. func HttpServer(addr string) {
  28. headersOk := handlers.AllowedHeaders([]string{"X-Requested-With"})
  29. originsOk := handlers.AllowedOrigins([]string{"*"})
  30. methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"})
  31. // Kafka writer that relays messages
  32. writer := kafkaclient.KafkaWriter("kafka:9092", "apibeacons")
  33. defer writer.Close()
  34. settingsWriter := kafkaclient.KafkaWriter("kafka:9092", "settings")
  35. defer settingsWriter.Close()
  36. // Define if maybe ws writer should have more topics
  37. wsWriter := kafkaclient.KafkaWriter("kafka:9092", "wsmessages")
  38. defer wsWriter.Close()
  39. r := mux.NewRouter()
  40. client := redis.NewClient(&redis.Options{
  41. Addr: "valkey:6379",
  42. Password: "",
  43. })
  44. // For now just add beacon DELETE / GET / POST / PUT methods
  45. r.HandleFunc("/api/beacons/{beacon_id}", beaconsDeleteHandler(writer)).Methods("DELETE")
  46. r.HandleFunc("/api/beacons", beaconsListHandler(client)).Methods("GET")
  47. r.HandleFunc("/api/beacons", beaconsAddHandler(writer)).Methods("POST")
  48. r.HandleFunc("/api/beacons", beaconsAddHandler(writer)).Methods("PUT")
  49. r.HandleFunc("/api/settings", settingsListHandler(client)).Methods("GET")
  50. r.HandleFunc("/api/settings", settingsEditHandler(settingsWriter)).Methods("POST")
  51. // Handler for WS messages
  52. // No point in having seperate route for each message type, better to handle different message types in one connection
  53. r.HandleFunc("/ws/api", handleWSApi(wsWriter))
  54. http.ListenAndServe(addr, handlers.CORS(originsOk, headersOk, methodsOk)(r))
  55. }
  56. // Probably define value as interface and then reuse this writer in all of the functions
  57. func sendKafkaMessage(writer *kafka.Writer, value *model.ApiUpdate) bool {
  58. valueStr, err := json.Marshal(&value)
  59. if err != nil {
  60. fmt.Println("error in encoding: ", err)
  61. return false
  62. }
  63. msg := kafka.Message{
  64. Value: valueStr,
  65. }
  66. err = writer.WriteMessages(context.Background(), msg)
  67. if err != nil {
  68. fmt.Println("Error in sending kafka message: ")
  69. return false
  70. }
  71. return true
  72. }
  73. func beaconsDeleteHandler(writer *kafka.Writer) http.HandlerFunc {
  74. return func(w http.ResponseWriter, r *http.Request) {
  75. vars := mux.Vars(r)
  76. beaconId := vars["beacon_id"]
  77. apiUpdate := model.ApiUpdate{
  78. Method: "DELETE",
  79. ID: beaconId,
  80. }
  81. flag := sendKafkaMessage(writer, &apiUpdate)
  82. if !flag {
  83. fmt.Println("error in sending Kafka message")
  84. http.Error(w, "Error in sending kafka message", 500)
  85. return
  86. }
  87. w.Write([]byte("ok"))
  88. }
  89. }
  90. func beaconsAddHandler(writer *kafka.Writer) http.HandlerFunc {
  91. return func(w http.ResponseWriter, r *http.Request) {
  92. decoder := json.NewDecoder(r.Body)
  93. var inBeacon model.Beacon
  94. err := decoder.Decode(&inBeacon)
  95. if err != nil {
  96. http.Error(w, err.Error(), 400)
  97. return
  98. }
  99. if (len(strings.TrimSpace(inBeacon.Name)) == 0) || (len(strings.TrimSpace(inBeacon.Beacon_id)) == 0) {
  100. http.Error(w, "name and beacon_id cannot be blank", 400)
  101. return
  102. }
  103. apiUpdate := model.ApiUpdate{
  104. Method: "POST",
  105. Beacon: inBeacon,
  106. }
  107. flag := sendKafkaMessage(writer, &apiUpdate)
  108. if !flag {
  109. fmt.Println("error in sending Kafka message")
  110. http.Error(w, "Error in sending kafka message", 500)
  111. return
  112. }
  113. w.Write([]byte("ok"))
  114. }
  115. }
  116. func beaconsListHandler(client *redis.Client) http.HandlerFunc {
  117. return func(w http.ResponseWriter, r *http.Request) {
  118. beaconsList, err := client.Get(context.Background(), "beaconsList").Result()
  119. if err == redis.Nil {
  120. fmt.Println("no beacons list, starting empty")
  121. http.Error(w, "list is empty", 500)
  122. } else if err != nil {
  123. http.Error(w, "Internal server error", 500)
  124. panic(err)
  125. } else {
  126. w.Write([]byte(beaconsList))
  127. }
  128. }
  129. }
  130. func settingsListHandler(client *redis.Client) http.HandlerFunc {
  131. return func(w http.ResponseWriter, r *http.Request) {
  132. settings, err := client.Get(context.Background(), "settings").Result()
  133. if err == redis.Nil {
  134. fmt.Println("no settings persisted, starting empty")
  135. http.Error(w, "list is empty", 500)
  136. } else if err != nil {
  137. http.Error(w, "Internal server error", 500)
  138. panic(err)
  139. } else {
  140. w.Write([]byte(settings))
  141. }
  142. }
  143. }
  144. func settingsEditHandler(writer *kafka.Writer) http.HandlerFunc {
  145. return func(w http.ResponseWriter, r *http.Request) {
  146. decoder := json.NewDecoder(r.Body)
  147. var inSettings model.SettingsVal
  148. if err := decoder.Decode(&inSettings); err != nil {
  149. http.Error(w, err.Error(), 400)
  150. fmt.Println("Error in decoding Settings body: ", err)
  151. return
  152. }
  153. if !settingsCheck(inSettings) {
  154. http.Error(w, "values must be greater than 0", 400)
  155. fmt.Println("settings values must be greater than 0")
  156. return
  157. }
  158. valueStr, err := json.Marshal(&inSettings)
  159. if err != nil {
  160. http.Error(w, "Error in encoding settings", 500)
  161. fmt.Println("Error in encoding settings: ", err)
  162. return
  163. }
  164. msg := kafka.Message{
  165. Value: valueStr,
  166. }
  167. if err := writer.WriteMessages(context.Background(), msg); err != nil {
  168. fmt.Println("error in sending Kafka message")
  169. http.Error(w, "Error in sending kafka message", 500)
  170. return
  171. }
  172. w.Write([]byte("ok"))
  173. }
  174. }
  175. func settingsCheck(settings model.SettingsVal) bool {
  176. if settings.Location_confidence <= 0 || settings.Last_seen_threshold <= 0 || settings.HA_send_interval <= 0 {
  177. return false
  178. }
  179. return true
  180. }
  181. func wsWriter(ws *websocket.Conn) {
  182. pingTicker := time.NewTicker(30 * time.Second)
  183. beaconTicker := time.NewTicker(2 * time.Second)
  184. defer func() {
  185. pingTicker.Stop()
  186. beaconTicker.Stop()
  187. ws.Close()
  188. }()
  189. for {
  190. select {
  191. case <-beaconTicker.C:
  192. // What exactly is HTTP ... something to be used in locations
  193. // http_results_lock.RLock()
  194. // js, err := json.Marshal(http_results)
  195. // http_results_lock.RUnlock()
  196. // if err != nil {
  197. // js = []byte("error")
  198. // }
  199. ws.SetWriteDeadline(time.Now().Add(10 * time.Second))
  200. if err := ws.WriteMessage(websocket.TextMessage, []byte{1}); err != nil {
  201. return
  202. }
  203. case <-pingTicker.C:
  204. ws.SetWriteDeadline(time.Now().Add(10 * time.Second))
  205. if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
  206. return
  207. }
  208. }
  209. }
  210. }
  211. func handleWSApi(writer *kafka.Writer) http.HandlerFunc {
  212. return func(w http.ResponseWriter, r *http.Request) {
  213. ws, err := upgrader.Upgrade(w, r, nil)
  214. if err != nil {
  215. if _, ok := err.(websocket.HandshakeError); !ok {
  216. fmt.Println("Error in upgrading connection: ", err)
  217. }
  218. return
  219. }
  220. defer ws.Close()
  221. go wsWriter(ws)
  222. for {
  223. _, msgBytes, err := ws.ReadMessage()
  224. if err != nil {
  225. fmt.Println("Connection closed: ", err)
  226. break
  227. }
  228. // What are the WS messages even?
  229. msg := kafka.Message{
  230. Value: msgBytes,
  231. }
  232. fmt.Println("recieved WS message: ", msgBytes)
  233. if err := writer.WriteMessages(context.Background(), msg); err != nil {
  234. fmt.Println("Error in sending WS Kafka message: ", err)
  235. break
  236. }
  237. }
  238. }
  239. }