75 lines
1.7 KiB
Go
75 lines
1.7 KiB
Go
package web
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log"
|
|
|
|
. "openreplay/backend/pkg/messages"
|
|
)
|
|
|
|
/*
|
|
Handler name: ClickRage
|
|
Input event: MouseClick
|
|
Output event: IssueEvent
|
|
*/
|
|
|
|
const MAX_TIME_DIFF = 300
|
|
const MIN_CLICKS_IN_A_ROW = 3
|
|
|
|
type ClickRageDetector struct {
|
|
lastTimestamp uint64
|
|
lastLabel string
|
|
firstInARawTimestamp uint64
|
|
firstInARawMessageId uint64
|
|
countsInARow int
|
|
}
|
|
|
|
func (crd *ClickRageDetector) reset() {
|
|
crd.lastTimestamp = 0
|
|
crd.lastLabel = ""
|
|
crd.firstInARawTimestamp = 0
|
|
crd.firstInARawMessageId = 0
|
|
crd.countsInARow = 0
|
|
}
|
|
|
|
func (crd *ClickRageDetector) Build() Message {
|
|
defer crd.reset()
|
|
if crd.countsInARow >= MIN_CLICKS_IN_A_ROW {
|
|
payload, err := json.Marshal(struct{ Count int }{crd.countsInARow})
|
|
if err != nil {
|
|
log.Printf("can't marshal ClickRage payload to json: %s", err)
|
|
}
|
|
event := &IssueEvent{
|
|
Type: "click_rage",
|
|
ContextString: crd.lastLabel,
|
|
Payload: string(payload),
|
|
Timestamp: crd.firstInARawTimestamp,
|
|
MessageID: crd.firstInARawMessageId,
|
|
}
|
|
return event
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (crd *ClickRageDetector) Handle(message Message, messageID uint64, timestamp uint64) Message {
|
|
switch msg := message.(type) {
|
|
case *MouseClick:
|
|
// TODO: check if we it is ok to capture clickRage event without the connected ClickEvent in db.
|
|
if msg.Label == "" {
|
|
return crd.Build()
|
|
}
|
|
if crd.lastLabel == msg.Label && timestamp-crd.lastTimestamp < MAX_TIME_DIFF {
|
|
crd.lastTimestamp = timestamp
|
|
crd.countsInARow += 1
|
|
return nil
|
|
}
|
|
event := crd.Build()
|
|
crd.lastTimestamp = timestamp
|
|
crd.lastLabel = msg.Label
|
|
crd.firstInARawTimestamp = timestamp
|
|
crd.firstInARawMessageId = messageID
|
|
crd.countsInARow = 1
|
|
return event
|
|
}
|
|
return nil
|
|
}
|