mirror of https://github.com/tidwall/tile38.git
158 lines
4.1 KiB
Go
158 lines
4.1 KiB
Go
package controller
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/tidwall/tile38/controller/server"
|
|
"github.com/tidwall/tile38/geojson"
|
|
)
|
|
|
|
var tmfmt = "2006-01-02T15:04:05.999999999Z07:00"
|
|
|
|
func FenceMatch(hookName string, sw *scanWriter, fence *liveFenceSwitches, details *commandDetailsT) []string {
|
|
jshookName := jsonString(hookName)
|
|
jstime := jsonString(details.timestamp.Format(tmfmt))
|
|
glob := fence.glob
|
|
if details.command == "drop" {
|
|
return []string{`{"cmd":"drop","hook":` + jshookName + `,"time":` + jstime + `}`}
|
|
}
|
|
match := true
|
|
if glob != "" && glob != "*" {
|
|
match, _ = globMatch(glob, details.id)
|
|
}
|
|
if !match {
|
|
return nil
|
|
}
|
|
|
|
sw.mu.Lock()
|
|
nofields := sw.nofields
|
|
sw.mu.Unlock()
|
|
|
|
if details.obj == nil || (details.command == "fset" && nofields) {
|
|
return nil
|
|
}
|
|
match = false
|
|
detect := "outside"
|
|
if fence != nil {
|
|
match1 := fenceMatchObject(fence, details.oldObj)
|
|
match2 := fenceMatchObject(fence, details.obj)
|
|
if match1 && match2 {
|
|
match = true
|
|
detect = "inside"
|
|
} else if match1 && !match2 {
|
|
match = true
|
|
detect = "exit"
|
|
} else if !match1 && match2 {
|
|
match = true
|
|
detect = "enter"
|
|
if details.command == "fset" {
|
|
detect = "inside"
|
|
}
|
|
} else {
|
|
if details.command != "fset" {
|
|
// Maybe the old object and new object create a line that crosses the fence.
|
|
// Must detect for that possibility.
|
|
if details.oldObj != nil {
|
|
ls := geojson.LineString{
|
|
Coordinates: []geojson.Position{
|
|
details.oldObj.CalculatedPoint(),
|
|
details.obj.CalculatedPoint(),
|
|
},
|
|
}
|
|
temp := false
|
|
if fence.cmd == "within" {
|
|
// because we are testing if the line croses the area we need to use
|
|
// "intersects" instead of "within".
|
|
fence.cmd = "intersects"
|
|
temp = true
|
|
}
|
|
if fenceMatchObject(fence, ls) {
|
|
match = true
|
|
detect = "cross"
|
|
}
|
|
if temp {
|
|
fence.cmd = "within"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if details.command == "del" {
|
|
return []string{`{"command":"del","hook":` + jshookName + `,"id":` + jsonString(details.id) + `,"time":` + jstime + `}`}
|
|
}
|
|
if details.fmap == nil {
|
|
return nil
|
|
}
|
|
sw.mu.Lock()
|
|
sw.fmap = details.fmap
|
|
sw.fullFields = true
|
|
sw.msg.OutputType = server.JSON
|
|
sw.writeObject(details.id, details.obj, details.fields, true)
|
|
if sw.wr.Len() == 0 {
|
|
sw.mu.Unlock()
|
|
return nil
|
|
}
|
|
res := sw.wr.String()
|
|
resb := make([]byte, len(res))
|
|
copy(resb, res)
|
|
res = string(resb)
|
|
sw.wr.Reset()
|
|
if sw.output == outputIDs {
|
|
res = `{"id":` + res + `}`
|
|
}
|
|
sw.mu.Unlock()
|
|
|
|
if strings.HasPrefix(res, ",") {
|
|
res = res[1:]
|
|
}
|
|
|
|
jskey := jsonString(details.key)
|
|
ores := res
|
|
msgs := make([]string, 0, 2)
|
|
if fence.detect == nil || fence.detect[detect] {
|
|
if strings.HasPrefix(ores, "{") {
|
|
res = `{"command":"` + details.command + `","detect":"` + detect + `","hook":` + jshookName + `,"key":` + jskey + `,"time":` + jstime + `,` + ores[1:]
|
|
}
|
|
msgs = append(msgs, res)
|
|
}
|
|
switch detect {
|
|
case "enter":
|
|
if fence.detect == nil || fence.detect["inside"] {
|
|
msgs = append(msgs, `{"command":"`+details.command+`","detect":"inside","hook":`+jshookName+`,"key":`+jskey+`,"time":`+jstime+`,`+ores[1:])
|
|
}
|
|
case "exit", "cross":
|
|
if fence.detect == nil || fence.detect["outside"] {
|
|
msgs = append(msgs, `{"command":"`+details.command+`","detect":"outside","hook":`+jshookName+`,"key":`+jskey+`,"time":`+jstime+`,`+ores[1:])
|
|
}
|
|
}
|
|
return msgs
|
|
}
|
|
|
|
func fenceMatchObject(fence *liveFenceSwitches, obj geojson.Object) bool {
|
|
if obj == nil {
|
|
return false
|
|
}
|
|
if fence.cmd == "nearby" {
|
|
return obj.Nearby(geojson.Position{X: fence.lon, Y: fence.lat, Z: 0}, fence.meters)
|
|
} else if fence.cmd == "within" {
|
|
if fence.o != nil {
|
|
return obj.Within(fence.o)
|
|
} else {
|
|
return obj.WithinBBox(geojson.BBox{
|
|
Min: geojson.Position{X: fence.minLon, Y: fence.minLat, Z: 0},
|
|
Max: geojson.Position{X: fence.maxLon, Y: fence.maxLat, Z: 0},
|
|
})
|
|
}
|
|
} else if fence.cmd == "intersects" {
|
|
if fence.o != nil {
|
|
return obj.Intersects(fence.o)
|
|
} else {
|
|
return obj.IntersectsBBox(geojson.BBox{
|
|
Min: geojson.Position{X: fence.minLon, Y: fence.minLat, Z: 0},
|
|
Max: geojson.Position{X: fence.maxLon, Y: fence.maxLat, Z: 0},
|
|
})
|
|
}
|
|
}
|
|
return false
|
|
}
|