|
- package main
-
- import (
- "bytes"
- "context"
- "encoding/hex"
- "encoding/json"
- "fmt"
- "io"
- "log"
- "log/slog"
- "os"
- "os/signal"
- "strings"
- "sync"
- "syscall"
-
- "github.com/AFASystems/presence/internal/pkg/common/appcontext"
- "github.com/AFASystems/presence/internal/pkg/common/utils"
- "github.com/AFASystems/presence/internal/pkg/config"
- "github.com/AFASystems/presence/internal/pkg/kafkaclient"
- "github.com/AFASystems/presence/internal/pkg/model"
- "github.com/segmentio/kafka-go"
- )
-
- var wg sync.WaitGroup
-
- func main() {
- // Load global context to init beacons and latest list
- appState := appcontext.NewAppState()
- cfg := config.Load()
-
- parserRegistry := model.ParserRegistry{
- ParserList: make([]model.BeaconParser, 0),
- }
-
- configFile, err := os.Open("/app/cmd/decoder/config.json")
- if err != nil {
- panic(err)
- }
-
- b, _ := io.ReadAll(configFile)
-
- var configs []model.Config
- json.Unmarshal(b, &configs)
-
- for _, config := range configs {
- parserRegistry.Register(config.Name, config)
- }
-
- // Create log file
- logFile, err := os.OpenFile("server.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
- if err != nil {
- log.Fatalf("Failed to open log file: %v\n", err)
- }
- // shell and log file multiwriter
- w := io.MultiWriter(os.Stderr, logFile)
- logger := slog.New(slog.NewJSONHandler(w, nil))
- slog.SetDefault(logger)
-
- // define context
- ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
- defer stop()
-
- rawReader := appState.AddKafkaReader(cfg.KafkaURL, "rawbeacons", "gid-raw")
-
- alertWriter := appState.AddKafkaWriter(cfg.KafkaURL, "alertbeacons")
-
- slog.Info("Decoder initialized, subscribed to Kafka topics")
-
- chRaw := make(chan model.BeaconAdvertisement, 2000)
-
- wg.Add(2)
- go kafkaclient.Consume(rawReader, chRaw, ctx, &wg)
-
- eventloop:
- for {
- select {
- case <-ctx.Done():
- break eventloop
- case msg := <-chRaw:
- processIncoming(msg, appState, alertWriter, &parserRegistry)
- }
- }
-
- slog.Info("broken out of the main event loop")
- wg.Wait()
-
- slog.Info("All go routines have stopped, Beggining to close Kafka connections")
- appState.CleanKafkaReaders()
- appState.CleanKafkaWriters()
- }
-
- func processIncoming(adv model.BeaconAdvertisement, appState *appcontext.AppState, writer *kafka.Writer, parserRegistry *model.ParserRegistry) {
- err := decodeBeacon(adv, appState, writer, parserRegistry)
- if err != nil {
- eMsg := fmt.Sprintf("Error in decoding: %v", err)
- fmt.Println(eMsg)
- return
- }
- }
-
- func decodeBeacon(adv model.BeaconAdvertisement, appState *appcontext.AppState, writer *kafka.Writer, parserRegistry *model.ParserRegistry) error {
- beacon := strings.TrimSpace(adv.Data)
- id := adv.ID
- if beacon == "" {
- return nil
- }
-
- b, err := hex.DecodeString(beacon)
- if err != nil {
- return err
- }
-
- b = utils.RemoveFlagBytes(b)
-
- indeces := utils.ParseADFast(b)
- event := utils.LoopADStructures(b, indeces, id, parserRegistry)
-
- if event.ID == "" {
- return nil
- }
-
- prevEvent, ok := appState.GetBeaconEvent(id)
- appState.UpdateBeaconEvent(id, event)
- if ok && bytes.Equal(prevEvent.Hash(), event.Hash()) {
- return nil
- }
-
- eMsg, err := event.ToJSON()
- if err != nil {
- return err
- }
-
- if err := writer.WriteMessages(context.Background(), kafka.Message{Value: eMsg}); err != nil {
- return err
- }
-
- return nil
- }
|