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

112 рядки
3.4 KiB

  1. package decoder
  2. import (
  3. "context"
  4. "fmt"
  5. "log/slog"
  6. "sync"
  7. "time"
  8. "github.com/AFASystems/presence/internal/pkg/common/appcontext"
  9. "github.com/AFASystems/presence/internal/pkg/config"
  10. "github.com/AFASystems/presence/internal/pkg/decoder"
  11. "github.com/AFASystems/presence/internal/pkg/kafkaclient"
  12. "github.com/AFASystems/presence/internal/pkg/logger"
  13. "github.com/AFASystems/presence/internal/pkg/model"
  14. "github.com/segmentio/kafka-go"
  15. )
  16. // DecoderApp holds dependencies for the decoder service.
  17. type DecoderApp struct {
  18. Cfg *config.Config
  19. KafkaManager *kafkaclient.KafkaManager
  20. AppState *appcontext.AppState
  21. ParserRegistry *model.ParserRegistry
  22. ChRaw chan appcontext.BeaconAdvertisement
  23. ChParser chan model.KafkaParser
  24. Cleanup func()
  25. wg sync.WaitGroup
  26. }
  27. // New creates a DecoderApp with Kafka readers (rawbeacons, parser) and writer (alertbeacons).
  28. func New(cfg *config.Config) (*DecoderApp, error) {
  29. appState := appcontext.NewAppState()
  30. kafkaManager := kafkaclient.InitKafkaManager()
  31. srvLogger, cleanup := logger.CreateLogger("decoder.log")
  32. slog.SetDefault(srvLogger)
  33. readerTopics := []string{"rawbeacons", "parser"}
  34. writerTopics := []string{"alertbeacons", "healthdecoder"}
  35. kafkaManager.PopulateKafkaManager(cfg.KafkaURL, "decoder", readerTopics)
  36. kafkaManager.PopulateKafkaManager(cfg.KafkaURL, "", writerTopics)
  37. slog.Info("decoder service initialized", "readers", readerTopics, "writers", writerTopics)
  38. registry := &model.ParserRegistry{
  39. ParserList: make(map[string]model.BeaconParser),
  40. }
  41. return &DecoderApp{
  42. Cfg: cfg,
  43. KafkaManager: kafkaManager,
  44. AppState: appState,
  45. ParserRegistry: registry,
  46. ChRaw: make(chan appcontext.BeaconAdvertisement, config.LARGE_CHANNEL_SIZE),
  47. ChParser: make(chan model.KafkaParser, config.SMALL_CHANNEL_SIZE),
  48. Cleanup: cleanup,
  49. }, nil
  50. }
  51. // Run starts Kafka consumers and the event loop until ctx is cancelled.
  52. func (a *DecoderApp) Run(ctx context.Context) {
  53. a.wg.Add(2)
  54. go kafkaclient.Consume(a.KafkaManager.GetReader("rawbeacons"), a.ChRaw, ctx, &a.wg)
  55. go kafkaclient.Consume(a.KafkaManager.GetReader("parser"), a.ChParser, ctx, &a.wg)
  56. healthTicker := time.NewTicker(config.LARGE_TICKER_INTERVAL)
  57. defer healthTicker.Stop()
  58. for {
  59. select {
  60. case <-ctx.Done():
  61. return
  62. case <-healthTicker.C:
  63. health, err := a.AppState.GetDecoderHealth(a.KafkaManager)
  64. if err != nil {
  65. slog.Error("getting decoder health", "err", err)
  66. continue
  67. }
  68. m := kafka.Message{
  69. Value: health,
  70. }
  71. if err := kafkaclient.Write(ctx, a.KafkaManager.GetWriter("healthdecoder"), m); err != nil {
  72. slog.Error("writing decoder health", "err", err)
  73. continue
  74. }
  75. case msg := <-a.ChRaw:
  76. fmt.Println("msg: ", msg)
  77. decoder.ProcessIncoming(msg, a.AppState, a.KafkaManager.GetWriter("alertbeacons"), a.ParserRegistry)
  78. case msg := <-a.ChParser:
  79. switch msg.ID {
  80. case "add":
  81. a.ParserRegistry.Register(msg.Config.Name, msg.Config)
  82. case "delete":
  83. a.ParserRegistry.Unregister(msg.Name)
  84. case "update":
  85. a.ParserRegistry.Register(msg.Config.Name, msg.Config)
  86. }
  87. }
  88. }
  89. }
  90. // Shutdown waits for consumers and cleans up.
  91. func (a *DecoderApp) Shutdown() {
  92. a.wg.Wait()
  93. a.KafkaManager.CleanKafkaReaders()
  94. a.KafkaManager.CleanKafkaWriters()
  95. if a.Cleanup != nil {
  96. a.Cleanup()
  97. }
  98. slog.Info("decoder service shutdown complete")
  99. }