stillbox/pkg/calls/filter.go
2024-11-15 11:34:54 -05:00

113 lines
2.5 KiB
Go

package calls
import (
"context"
"dynatron.me/x/stillbox/pkg/database"
"dynatron.me/x/stillbox/pkg/pb"
tgs "dynatron.me/x/stillbox/pkg/talkgroups"
)
type TalkgroupFilter struct {
Talkgroups []tgs.ID `json:"talkgroups,omitempty"`
TalkgroupsNot []tgs.ID `json:"talkgroupsNot,omitempty"`
TalkgroupTagsAll []string `json:"talkgroupTagsAll,omitempty"`
TalkgroupTagsAny []string `json:"talkgroupTagsAny,omitempty"`
TalkgroupTagsNot []string `json:"talkgroupTagsNot,omitempty"`
talkgroups map[tgs.ID]bool
}
func TalkgroupFilterFromPB(ctx context.Context, p *pb.Filter) (*TalkgroupFilter, error) {
tgf := &TalkgroupFilter{
TalkgroupTagsAll: p.TalkgroupTagsAll,
TalkgroupTagsAny: p.TalkgroupTagsAny,
TalkgroupTagsNot: p.TalkgroupTagsNot,
}
if l := len(p.Talkgroups); l > 0 {
tgf.Talkgroups = make([]tgs.ID, l)
for i, t := range p.Talkgroups {
tgf.Talkgroups[i] = tgs.ID{
System: uint32(t.System),
Talkgroup: uint32(t.Talkgroup),
}
}
}
if l := len(p.TalkgroupsNot); l > 0 {
tgf.TalkgroupsNot = make([]tgs.ID, l)
for i, t := range p.TalkgroupsNot {
tgf.TalkgroupsNot[i] = tgs.ID{
System: uint32(t.System),
Talkgroup: uint32(t.Talkgroup),
}
}
}
return tgf, tgf.compile(ctx)
}
func (f *TalkgroupFilter) hasTags() bool {
return len(f.TalkgroupTagsAny) > 0 || len(f.TalkgroupTagsAll) > 0 || len(f.TalkgroupTagsNot) > 0
}
func (f *TalkgroupFilter) GetFinalTalkgroups() map[tgs.ID]bool {
return f.talkgroups
}
func (f *TalkgroupFilter) compile(ctx context.Context) error {
f.talkgroups = make(map[tgs.ID]bool)
for _, tg := range f.Talkgroups {
f.talkgroups[tg] = true
}
if f.hasTags() { // don't bother with DB if no tags
db := database.FromCtx(ctx)
tagTGs, err := db.GetTalkgroupIDsByTags(ctx, f.TalkgroupTagsAny, f.TalkgroupTagsAll, f.TalkgroupTagsNot)
if err != nil {
return err
}
for _, tg := range tagTGs {
f.talkgroups[tgs.ID{System: uint32(tg.SystemID), Talkgroup: uint32(tg.TGID)}] = true
}
}
for _, tg := range f.TalkgroupsNot {
f.talkgroups[tg] = false
}
return nil
}
func (f *TalkgroupFilter) Test(ctx context.Context, call *Call) bool {
if f == nil { // no filter means all calls
return true
}
if f.talkgroups == nil {
err := f.compile(ctx)
if err != nil {
panic(err)
}
}
tg := call.TalkgroupTuple()
tgRes, have := f.talkgroups[tg]
if have {
return tgRes
}
for _, patch := range call.Patches {
tg.Talkgroup = uint32(patch)
tgRes, have := f.talkgroups[tg]
if have {
return tgRes
}
}
return false
}