-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvisigo.go
52 lines (45 loc) · 1.26 KB
/
visigo.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
package visigo
import (
"errors"
"net/http"
"github.com/axiomhq/hyperloglog"
"github.com/tomasen/realip"
)
var counter map[string]*hyperloglog.Sketch
// ErrCount - error returned when you try to get count but didn't register middleware
var ErrCount = errors.New("count not found or error in HyperLogLog")
// Visits - get visits for given URL
func Visits(r *http.Request) (uint64, error) {
if counter == nil {
// no, you didn't ...
panic("you need to register Visigo Counter first!")
}
if hll, found := counter[r.URL.String()]; found {
return hll.Estimate(), nil
}
return 0, ErrCount
}
// TotalVisits gets total visits to all sites
func TotalVisits() (uint64, error) {
hll := hyperloglog.New()
for _, s := range counter {
if err := hll.Merge(s); err != nil {
return 0, err
}
}
return hll.Estimate(), nil
}
// Counter - registers middleware for visits counting
func Counter(next http.Handler) http.Handler {
counter = make(map[string]*hyperloglog.Sketch)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if hll, found := counter[r.URL.String()]; found {
hll.Insert([]byte(realip.RealIP(r)))
} else {
l := hyperloglog.New()
l.Insert([]byte(realip.RealIP(r)))
counter[r.URL.String()] = l
}
next.ServeHTTP(w, r)
})
}