選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 

123 行
3.6 KiB

  1. package bridge
  2. import (
  3. "context"
  4. "encoding/json"
  5. "log/slog"
  6. "sync"
  7. "github.com/AFASystems/presence/internal/pkg/bridge"
  8. "github.com/AFASystems/presence/internal/pkg/common/appcontext"
  9. "github.com/AFASystems/presence/internal/pkg/config"
  10. "github.com/AFASystems/presence/internal/pkg/kafkaclient"
  11. "github.com/AFASystems/presence/internal/pkg/logger"
  12. "github.com/AFASystems/presence/internal/pkg/model"
  13. mqtt "github.com/eclipse/paho.mqtt.golang"
  14. )
  15. // BridgeApp holds dependencies for the bridge service (MQTT <-> Kafka).
  16. type BridgeApp struct {
  17. Cfg *config.Config
  18. KafkaManager *kafkaclient.KafkaManager
  19. AppState *appcontext.AppState
  20. MQTT *bridge.MQTTClient
  21. ChApi chan model.ApiUpdate
  22. ChAlert chan model.Alert
  23. ChMqtt chan []model.Tracker
  24. Cleanup func()
  25. wg sync.WaitGroup
  26. }
  27. // New creates a BridgeApp with Kafka readers (apibeacons, alert, mqtt), writer (rawbeacons), and MQTT client.
  28. func New(cfg *config.Config) (*BridgeApp, error) {
  29. appState := appcontext.NewAppState()
  30. kafkaManager := kafkaclient.InitKafkaManager()
  31. srvLogger, cleanup := logger.CreateLogger("bridge.log")
  32. slog.SetDefault(srvLogger)
  33. readerTopics := []string{"apibeacons", "alert", "mqtt"}
  34. writerTopics := []string{"rawbeacons"}
  35. kafkaManager.PopulateKafkaManager(cfg.KafkaURL, "bridge", readerTopics)
  36. kafkaManager.PopulateKafkaManager(cfg.KafkaURL, "", writerTopics)
  37. slog.Info("bridge service initialized", "readers", readerTopics, "writers", writerTopics)
  38. writer := kafkaManager.GetWriter("rawbeacons")
  39. mqttClient, err := bridge.NewMQTTClient(cfg, func(m mqtt.Message) {
  40. bridge.HandleMQTTMessage(m.Topic(), m.Payload(), appState, writer)
  41. })
  42. if err != nil {
  43. cleanup()
  44. return nil, err
  45. }
  46. mqttClient.Subscribe()
  47. return &BridgeApp{
  48. Cfg: cfg,
  49. KafkaManager: kafkaManager,
  50. AppState: appState,
  51. MQTT: mqttClient,
  52. ChApi: make(chan model.ApiUpdate, config.SMALL_CHANNEL_SIZE),
  53. ChAlert: make(chan model.Alert, config.SMALL_CHANNEL_SIZE),
  54. ChMqtt: make(chan []model.Tracker, config.SMALL_CHANNEL_SIZE),
  55. Cleanup: cleanup,
  56. }, nil
  57. }
  58. // Run starts Kafka consumers and the event loop until ctx is cancelled.
  59. func (a *BridgeApp) Run(ctx context.Context) {
  60. a.wg.Add(3)
  61. go kafkaclient.Consume(a.KafkaManager.GetReader("apibeacons"), a.ChApi, ctx, &a.wg)
  62. go kafkaclient.Consume(a.KafkaManager.GetReader("alert"), a.ChAlert, ctx, &a.wg)
  63. go kafkaclient.Consume(a.KafkaManager.GetReader("mqtt"), a.ChMqtt, ctx, &a.wg)
  64. for {
  65. select {
  66. case <-ctx.Done():
  67. return
  68. case msg := <-a.ChApi:
  69. switch msg.Method {
  70. case "POST":
  71. a.AppState.AddBeaconToLookup(msg.MAC, msg.ID)
  72. slog.Info("beacon added to lookup", "id", msg.ID)
  73. case "DELETE":
  74. if msg.MAC == "all" {
  75. a.AppState.CleanLookup()
  76. slog.Info("lookup cleared")
  77. continue
  78. }
  79. a.AppState.RemoveBeaconFromLookup(msg.MAC)
  80. slog.Info("beacon removed from lookup", "mac", msg.MAC)
  81. }
  82. case msg := <-a.ChAlert:
  83. p, err := json.Marshal(msg)
  84. if err != nil {
  85. slog.Error("marshaling alert", "err", err)
  86. continue
  87. }
  88. a.MQTT.Client.Publish("/alerts", 0, true, p)
  89. case msg := <-a.ChMqtt:
  90. p, err := json.Marshal(msg)
  91. if err != nil {
  92. slog.Error("marshaling trackers", "err", err)
  93. continue
  94. }
  95. a.MQTT.Client.Publish("/trackers", 0, true, p)
  96. }
  97. }
  98. }
  99. // Shutdown disconnects MQTT, waits for consumers, and cleans up.
  100. func (a *BridgeApp) Shutdown() {
  101. a.wg.Wait()
  102. if a.MQTT != nil {
  103. a.MQTT.Disconnect()
  104. }
  105. a.KafkaManager.CleanKafkaReaders()
  106. a.KafkaManager.CleanKafkaWriters()
  107. if a.Cleanup != nil {
  108. a.Cleanup()
  109. }
  110. slog.Info("bridge service shutdown complete")
  111. }