-
Notifications
You must be signed in to change notification settings - Fork 24
/
events.go
138 lines (116 loc) · 3.31 KB
/
events.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
131
132
133
134
135
136
137
138
package hcaptcha
import (
"github.com/go-gl/mathgl/mgl64"
"github.com/iancoleman/orderedmap"
"github.com/justtaldevelops/go-hcaptcha/agents"
)
// Event is a movement event.
type Event struct {
// Point is the position of the event.
Point mgl64.Vec2
// Type represents the type of event. For example, a "mouse up" event would be "mu".
Type string
// Timestamp is the time the event was recorded.
Timestamp int64
}
// EventRecorder helps record and retrieve movement events.
type EventRecorder struct {
recording bool
agent agents.Agent
manifest *orderedmap.OrderedMap
timeBuffers map[string]*EventContainer
}
// NewEventRecorder creates a new EventRecorder.
func NewEventRecorder(agent agents.Agent) *EventRecorder {
return &EventRecorder{
agent: agent,
manifest: orderedmap.New(),
timeBuffers: make(map[string]*EventContainer),
}
}
// Record records a new event.
func (e *EventRecorder) Record() {
e.manifest.Set("st", e.agent.Unix())
e.recording = true
}
// Data records the events to the manifest and returns it.
func (e *EventRecorder) Data() *orderedmap.OrderedMap {
for event, container := range e.timeBuffers {
e.manifest.Set(event, container.Data())
e.manifest.Set(event+"-mp", container.MeanPeriod())
}
return e.manifest
}
// SetData sets data in the manifest of the EventRecorder.
func (e *EventRecorder) SetData(name string, value interface{}) {
e.manifest.Set(name, value)
}
// RecordEvent records a new event.
func (e *EventRecorder) RecordEvent(event Event) {
if !e.recording {
return
}
if _, ok := e.timeBuffers[event.Type]; !ok {
e.timeBuffers[event.Type] = NewEventContainer(e.agent, 16, 15e3)
}
e.timeBuffers[event.Type].Push(event)
}
// EventContainer is a container for event data.
type EventContainer struct {
agent agents.Agent
period, interval int64
date []int64
data [][]int64
previousTimestamp int64
meanPeriod int64
meanCounter int64
}
// NewEventContainer creates a new EventContainer.
func NewEventContainer(agent agents.Agent, period, interval int64) *EventContainer {
return &EventContainer{
agent: agent,
period: period,
interval: interval,
}
}
// MeanPeriod returns the mean period of the event container.
func (e *EventContainer) MeanPeriod() int64 {
return e.meanPeriod
}
// Data returns the data of the event container.
func (e *EventContainer) Data() [][]int64 {
e.cleanStaleData()
return e.data
}
// Push adds a new event to the event container.
func (e *EventContainer) Push(event Event) {
e.cleanStaleData()
var timestamp int64
notFirst := len(e.date) > 0
if notFirst {
timestamp = e.date[len(e.date)-1]
}
if event.Timestamp-timestamp >= e.period {
e.date = append(e.date, event.Timestamp)
e.data = append(e.data, []int64{int64(event.Point.X()), int64(event.Point.Y()), event.Timestamp})
if notFirst {
delta := event.Timestamp - e.previousTimestamp
e.meanPeriod = (e.meanPeriod*e.meanCounter + delta) / (e.meanCounter + 1)
e.meanCounter++
}
}
e.previousTimestamp = event.Timestamp
}
// cleanStaleData removes stale data from the event container.
func (e *EventContainer) cleanStaleData() {
date := e.agent.Unix()
t := len(e.date) - 1
for t >= 0 {
if date-e.date[t] >= e.interval {
e.date = e.date[:t+1]
e.date = e.date[:t+1]
break
}
t -= 1
}
}