From 6c52f3f3f1d5bf0c80cf92b3bf6039550c0fb41a Mon Sep 17 00:00:00 2001 From: Josh Baker Date: Thu, 15 Dec 2016 10:00:08 -0700 Subject: [PATCH] added command filter for geofences It's now possible to mask the fence notifications based on the command. For example, if we only want "set" and "del" commands. NEARBY fleet FENCE COMMANDS set,del POINT 33 -115 10000 Suggested by @amorskoy, closes #99 --- controller/fence.go | 19 +++++++++++++++++-- controller/token.go | 25 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/controller/fence.go b/controller/fence.go index cd05b605f..4fde36fc7 100644 --- a/controller/fence.go +++ b/controller/fence.go @@ -5,6 +5,7 @@ import ( "strconv" "strings" + "github.com/tidwall/gjson" "github.com/tidwall/tile38/controller/glob" "github.com/tidwall/tile38/controller/server" "github.com/tidwall/tile38/geojson" @@ -14,11 +15,25 @@ var tmfmt = "2006-01-02T15:04:05.999999999Z07:00" // FenceMatch executes a fence match returns back json messages for fence detection. func FenceMatch(hookName string, sw *scanWriter, fence *liveFenceSwitches, details *commandDetailsT) []string { + msgs := fenceMatch(hookName, sw, fence, details) + if len(fence.accept) == 0 { + return msgs + } + nmsgs := make([]string, 0, len(msgs)) + for _, msg := range msgs { + if fence.accept[gjson.Get(msg, "command").String()] { + nmsgs = append(nmsgs, msg) + } + } + return nmsgs +} + +func fenceMatch(hookName string, sw *scanWriter, fence *liveFenceSwitches, details *commandDetailsT) []string { jshookName := jsonString(hookName) jstime := jsonString(details.timestamp.Format(tmfmt)) pattern := fence.glob if details.command == "drop" { - return []string{`{"cmd":"drop","hook":` + jshookName + `,"time":` + jstime + `}`} + return []string{`{"command":"drop","hook":` + jshookName + `,"time":` + jstime + `}`} } match := true if pattern != "" && pattern != "*" { @@ -150,7 +165,7 @@ func FenceMatch(hookName string, sw *scanWriter, fence *liveFenceSwitches, detai jskey := jsonString(details.key) ores := res - msgs := make([]string, 0, 2) + msgs := make([]string, 0, 4) if fence.detect == nil || fence.detect[detect] { if strings.HasPrefix(ores, "{") { res = `{"command":"` + details.command + `","group":"` + group + `","detect":"` + detect + `","hook":` + jshookName + `,"key":` + jskey + `,"time":` + jstime + `,` + ores[1:] diff --git a/controller/token.go b/controller/token.go index eb6695209..d9d9aaaa5 100644 --- a/controller/token.go +++ b/controller/token.go @@ -164,6 +164,7 @@ type searchScanBaseTokens struct { lineout string fence bool detect map[string]bool + accept map[string]bool glob string wheres []whereT nofields bool @@ -279,6 +280,30 @@ func parseSearchScanBaseTokens(cmd string, vs []resp.Value) (vsout []resp.Value, } t.fence = true continue + } else if (wtok[0] == 'C' || wtok[0] == 'c') && strings.ToLower(wtok) == "commands" { + vs = nvs + if t.accept != nil { + err = errDuplicateArgument(strings.ToUpper(wtok)) + return + } + t.accept = make(map[string]bool) + var peek string + if vs, peek, ok = tokenval(vs); !ok || peek == "" { + err = errInvalidNumberOfArguments + return + } + for _, s := range strings.Split(peek, ",") { + part := strings.TrimSpace(strings.ToLower(s)) + if t.accept[part] { + err = errDuplicateArgument(s) + return + } + t.accept[part] = true + } + if len(t.accept) == 0 { + t.accept = nil + } + continue } else if (wtok[0] == 'D' || wtok[0] == 'd') && strings.ToLower(wtok) == "detect" { vs = nvs if t.detect != nil {