-
Notifications
You must be signed in to change notification settings - Fork 0
/
process.go
87 lines (72 loc) · 1.91 KB
/
process.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
package played
import (
"bytes"
"encoding/binary"
"strconv"
"time"
"github.com/apple/foundationdb/bindings/go/src/fdb"
"golang.org/x/xerrors"
)
func (s *Server) processPlayed(userID int64, game string) error {
s.whitelistMu.RLock()
_, whitelisted := s.whitelists[userID]
s.whitelistMu.RUnlock()
if !whitelisted {
return nil
}
var (
user = strconv.FormatInt(userID, 10)
fsKey = s.fmtFirstSeenKey(user)
curKey = s.fmtCurrentGameKey(user)
lastKey = s.fmtLastUpdatedKey(user)
)
_, err := s.db.Transact(func(t fdb.Transaction) (_ interface{}, err error) {
// because of the low cost of time.Now and PutUint64 i'd rather
// prefer idempotence because this will be retried if there is a conflict
//
// little endian is used because foundationdb's atomic add function
// requires little endian encoded uints
var (
timeNow = time.Now()
// 64 bit
now [8]byte
)
binary.LittleEndian.PutUint64(now[:], uint64(timeNow.Unix()))
first := t.Get(fsKey).MustGet()
if first == nil {
t.Set(fsKey, now[:])
}
curVal := t.Get(curKey).MustGet()
if curVal == nil {
t.Set(curKey, []byte(game))
t.Set(lastKey, now[:])
return
}
if bytes.Equal(curVal, []byte(game)) {
return
}
// we know now that the user changed games
lastChanged := timeNow
lastChangedRaw := t.Get(lastKey).MustGet()
if lastChangedRaw != nil && len(lastChangedRaw) == 8 {
lastChanged = time.Unix(int64(binary.LittleEndian.Uint64(lastChangedRaw)), 0)
}
t.Set(lastKey, now[:])
t.Set(curKey, []byte(game))
// if they just changed from not playing a game, theres no need to compute time played.
if len(curVal) == 0 {
return
}
toAdd := [8]byte{}
binary.LittleEndian.PutUint32(
toAdd[:],
uint32(timeNow.Sub(lastChanged).Seconds()),
)
t.Add(s.fmtPlayedUserGame(user, string(curVal)), toAdd[:])
return
})
if err != nil {
return xerrors.Errorf("transact: %w", err)
}
return nil
}