package main import ( "context" "encoding/json" "fmt" "strings" "time" "github.com/AFASystems/presence/internal/pkg/model" "github.com/AFASystems/presence/internal/pkg/mqttclient" "github.com/redis/go-redis/v9" "github.com/segmentio/kafka-go" ) func main() { // Load global context to init beacons and latest list appCtx := model.AppContext{ Beacons: model.BeaconsList{ Beacons: make(map[string]model.Beacon), }, LatestList: model.LatestBeaconsList{ LatestList: make(map[string]model.Beacon), }, } // Kafka writer idk why yet writer := kafkaWriter("127.0.0.1:9092", "beacons") // Kafka reader for Raw MQTT beacons rawReader := kafkaReader("127.0.0.1:9092", "rawbeacons", "someID") defer rawReader.Close() // Kafka reader for API server updates apiReader := kafkaReader("127.0.0.1:9092", "apibeacons", "someID") defer apiReader.Close() // Kafka reader for latest list updates latestReader := kafkaReader("127.0.0.1:9092", "latestbeacons", "someID") defer latestReader.Close() defer writer.Close() ctx := context.Background() // Init Redis Client client := redis.NewClient(&redis.Options{ Addr: "127.0.0.1:6379", Password: "", }) // Initialize list values from Redis beaconsList, err := client.Get(ctx, "beaconsList").Result() if err == redis.Nil { fmt.Println("no beacons list, starting empty") } else if err != nil { panic(err) } else { json.Unmarshal([]byte(beaconsList), &appCtx.Beacons.Beacons) } // Initialize list values from Redis latestList, err := client.Get(ctx, "latestList").Result() if err == redis.Nil { fmt.Println("no latest list, starting empty") } else if err != nil { panic(err) } else { json.Unmarshal([]byte(latestList), &appCtx.LatestList.LatestList) } // declare channel for collecting Kafka messages chRaw := make(chan model.Incoming_json, 2000) chApi := make(chan model.ApiUpdate, 2000) chLatest := make(chan model.Incoming_json, 2000) go consume(rawReader, chRaw) go consume(apiReader, chApi) go consume(latestReader, chLatest) go func() { ticker := time.NewTicker(1 * time.Second) defer ticker.Stop() for range ticker.C { appCtx.Beacons.Lock.Lock() data, _ := json.Marshal(appCtx.Beacons.Beacons) appCtx.Beacons.Lock.Unlock() err := client.Set(ctx, "beaconsList", data, 0).Err() if err != nil { fmt.Println("error saving to redis:", err) } appCtx.LatestList.Lock.Lock() ldata, _ := json.Marshal(appCtx.LatestList.LatestList) appCtx.LatestList.Lock.Unlock() err = client.Set(ctx, "latestList", ldata, 0).Err() if err != nil { fmt.Println("error saving latest list:", err) } } }() for { select { case msg := <-chRaw: processIncoming(msg, &appCtx) case msg := <-chApi: switch msg.Method { case "POST": fmt.Println("method POST") appCtx.Beacons.Lock.Lock() appCtx.Beacons.Beacons[msg.Beacon.Beacon_id] = msg.Beacon case "DELETE": _, exists := appCtx.Beacons.Beacons[msg.ID] if exists { appCtx.Beacons.Lock.Lock() delete(appCtx.Beacons.Beacons, msg.ID) } fmt.Println("method DELETE") default: fmt.Println("unknown method: ", msg.Method) } appCtx.Beacons.Lock.Unlock() case msg := <-chLatest: fmt.Println("latest msg: ", msg) } } } func kafkaWriter(kafkaURL, topic string) *kafka.Writer { return &kafka.Writer{ Addr: kafka.TCP(kafkaURL), Topic: topic, Balancer: &kafka.LeastBytes{}, BatchSize: 100, BatchTimeout: 10 * time.Millisecond, } } func kafkaReader(kafkaURL, topic, groupID string) *kafka.Reader { brokers := strings.Split(kafkaURL, ",") return kafka.NewReader(kafka.ReaderConfig{ Brokers: brokers, GroupID: groupID, Topic: topic, MinBytes: 1, MaxBytes: 10e6, }) } func consume[T any](r *kafka.Reader, ch chan<- T) { for { msg, err := r.ReadMessage(context.Background()) if err != nil { fmt.Println("error reading message:", err) continue } var data T if err := json.Unmarshal(msg.Value, &data); err != nil { fmt.Println("error decoding:", err) continue } ch <- data } } func processIncoming(incoming model.Incoming_json, ctx *model.AppContext) { defer func() { if err := recover(); err != nil { fmt.Println("work failed:", err) } }() incoming = mqttclient.IncomingBeaconFilter(incoming) id := mqttclient.GetBeaconID(incoming) now := time.Now().Unix() beacons := &ctx.Beacons beacons.Lock.Lock() defer beacons.Lock.Unlock() latestList := &ctx.LatestList latestList.Lock.Lock() defer latestList.Lock.Unlock() beacon, exists := beacons.Beacons[id] if !exists { fmt.Println("beacon does not yet exist") fmt.Println("time now: ", now) return } fmt.Println("Beacon does exist: ", beacon) }