package main import ( "bytes" "encoding/binary" "encoding/json" "fmt" "io" "os" "sync" "github.com/AFASystems/presence/internal/pkg/model" ) type parserConfig struct { Length int `json:"length"` Offset int `json:"offset"` Order string `json:"order"` } type beaconParser struct { name string canParse func([]byte) bool configs map[string]parserConfig } type parserRegistry struct { parserList []beaconParser rw sync.RWMutex } type config struct { Name string `json:"name"` Min int `json:"min"` Max int `json:"max"` Pattern []string `json:"pattern"` Configs map[string]parserConfig `json:"configs"` } func (pc parserConfig) GetOrder() binary.ByteOrder { if pc.Order == "bigendian" { return binary.BigEndian } return binary.LittleEndian } func (p *parserRegistry) Register(name string, c config) { p.rw.Lock() defer p.rw.Unlock() b := beaconParser{ name: name, canParse: func(ad []byte) bool { return len(ad) >= c.Min && len(ad) <= c.Max && bytes.HasPrefix(ad, c.GetPatternBytes()) }, configs: c.Configs, } p.parserList = append(p.parserList, b) } func (b *beaconParser) Parse(ad []byte) (model.BeaconEvent, bool) { flag := false event := model.BeaconEvent{Type: b.name} if cfg, ok := b.configs["battery"]; ok { event.Battery = uint32(b.extract(ad, cfg)) flag = true } if cfg, ok := b.configs["accX"]; ok { event.AccX = int16(b.extract(ad, cfg)) flag = true } if cfg, ok := b.configs["accY"]; ok { event.AccY = int16(b.extract(ad, cfg)) flag = true } if cfg, ok := b.configs["accZ"]; ok { event.AccZ = int16(b.extract(ad, cfg)) flag = true } return event, flag } func (b *beaconParser) extract(ad []byte, pc parserConfig) uint16 { if len(ad) < pc.Offset+pc.Length { return 0 } data := ad[pc.Offset : pc.Offset+pc.Length] if pc.Length == 1 { return uint16(data[0]) } return pc.GetOrder().Uint16(data) } func (c config) GetPatternBytes() []byte { res := make([]byte, len(c.Pattern)) for i, s := range c.Pattern { fmt.Sscanf(s, "0x%02x", &res[i]) } return res } func main() { parserRegistry := parserRegistry{ parserList: make([]beaconParser, 0), } seq := []byte{0x02, 0x01, 0x06, 0x64, 0x01, 0xF4, 0x00, 0x0A, 0xFF, 0x05} jsonFile, err := os.Open("configs.json") if err != nil { fmt.Println(err) } fmt.Println("succesfully opened json file") b, _ := io.ReadAll(jsonFile) var configs []config json.Unmarshal(b, &configs) for _, config := range configs { parserRegistry.Register(config.Name, config) } for _, parser := range parserRegistry.parserList { if parser.canParse(seq) { event, ok := parser.Parse(seq) if ok { fmt.Printf("Device: %s | Battery: %d%% | AccX: %d | AccY: %d | AccZ: %d\n", event.Type, event.Battery, event.AccX, event.AccY, event.AccZ) } } } fmt.Printf("configs: %+v\n", configs) jsonFile.Close() }