-
Notifications
You must be signed in to change notification settings - Fork 23
/
anomalies.go
130 lines (107 loc) · 3.18 KB
/
anomalies.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package unifi
import (
"fmt"
"sort"
"strconv"
"strings"
"time"
)
// anomaly is the type UniFi returns, but not the type this library returns.
type anomaly struct {
Anomaly string `json:"anomaly"`
MAC string `fake:"{macaddress}" json:"mac"`
Timestamps []int64 `fake:"{timestamps}" json:"timestamps"`
}
// Anomaly is the reformatted data type that this library returns.
type Anomaly struct {
// DeviceName string // we do not have this....
Anomaly string
Datetime time.Time `fake:"{recent_time}"`
DeviceMAC string `fake:"{macaddress}"`
SiteName string
SourceName string
}
// GetAnomalies returns Anomalies for a list of Sites.
func (u *Unifi) GetAnomalies(sites []*Site, timeRange ...time.Time) ([]*Anomaly, error) {
data := []*Anomaly{}
for _, site := range sites {
response, err := u.GetAnomaliesSite(site, timeRange...)
if err != nil {
return data, err
}
data = append(data, response...)
}
return data, nil
}
// GetAnomaliesSite retreives the Anomalies for a single Site.
func (u *Unifi) GetAnomaliesSite(site *Site, timeRange ...time.Time) ([]*Anomaly, error) {
if site == nil || site.Name == "" {
return nil, ErrNoSiteProvided
}
u.DebugLog("Polling Controller for Anomalies, site %s", site.SiteName)
var (
path = fmt.Sprintf(APIAnomaliesPath, site.Name)
anomalies = anomalies{}
data struct {
Data []*anomaly `json:"data"`
}
)
if params, err := makeAnomalyParams("hourly", timeRange...); err != nil {
return anomalies, err
} else if err := u.GetData(path+params, &data, ""); err != nil {
return anomalies, err
}
for _, d := range data.Data {
for _, ts := range d.Timestamps {
anomalies = append(anomalies, &Anomaly{
Datetime: time.Unix(ts/int64(time.Microsecond), 0),
SourceName: u.URL,
SiteName: site.SiteName,
Anomaly: d.Anomaly,
DeviceMAC: d.MAC,
// DeviceName: d.Anomaly,
})
}
}
sort.Sort(anomalies)
return anomalies, nil
}
// anomalies satisfies the sort.Sort interface.
type anomalies []*Anomaly
// Len satisfies sort.Interface.
func (a anomalies) Len() int {
return len(a)
}
// Swap satisfies sort.Interface.
func (a anomalies) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}
// Less satisfies sort.Interface. Sort our list by Datetime.
func (a anomalies) Less(i, j int) bool {
return a[i].Datetime.Before(a[j].Datetime)
}
func makeAnomalyParams(scale string, timeRange ...time.Time) (string, error) {
out := []string{}
if scale != "" {
out = append(out, "scale="+scale)
}
switch len(timeRange) {
case 0:
end := time.Now().Unix() * int64(time.Microsecond)
out = append(out, "end="+strconv.FormatInt(end, 10))
case 1:
start := timeRange[0].Unix() * int64(time.Microsecond)
end := time.Now().Unix() * int64(time.Microsecond)
out = append(out, "end="+strconv.FormatInt(end, 10), "start="+strconv.FormatInt(start, 10))
case 2: // nolint: gomnd
start := timeRange[0].Unix() * int64(time.Microsecond)
end := timeRange[1].Unix() * int64(time.Microsecond)
out = append(out, "end="+strconv.FormatInt(end, 10), "start="+strconv.FormatInt(start, 10))
default:
return "", ErrInvalidTimeRange
}
if len(out) == 0 {
return "", nil
}
return "?" + strings.Join(out, "&"), nil
}