|
1 | 1 | package memory |
2 | 2 |
|
3 | 3 | import ( |
4 | | - "context" |
5 | | - "sync" |
6 | | - "time" |
| 4 | + "context" |
| 5 | + "sync" |
| 6 | + "time" |
7 | 7 |
|
8 | | - "gamifykit/core" |
| 8 | + "gamifykit/core" |
9 | 9 | ) |
10 | 10 |
|
11 | 11 | // Store is a concurrent in-memory Storage implementation. |
12 | 12 | type Store struct { |
13 | | - users sync.Map // map[core.UserID]*userRecord |
| 13 | + users sync.Map // map[core.UserID]*userRecord |
14 | 14 | } |
15 | 15 |
|
16 | 16 | type userRecord struct { |
17 | | - mu sync.Mutex |
18 | | - state core.UserState |
| 17 | + mu sync.Mutex |
| 18 | + state core.UserState |
19 | 19 | } |
20 | 20 |
|
21 | 21 | func New() *Store { return &Store{} } |
22 | 22 |
|
23 | 23 | func (s *Store) getOrCreate(user core.UserID) *userRecord { |
24 | | - if v, ok := s.users.Load(user); ok { |
25 | | - return v.(*userRecord) |
26 | | - } |
27 | | - rec := &userRecord{state: core.UserState{ |
28 | | - UserID: user, |
29 | | - Points: map[core.Metric]int64{}, |
30 | | - Badges: map[core.Badge]struct{}{}, |
31 | | - Levels: map[core.Metric]int64{}, |
32 | | - Updated: time.Now().UTC(), |
33 | | - }} |
34 | | - actual, _ := s.users.LoadOrStore(user, rec) |
35 | | - return actual.(*userRecord) |
| 24 | + if v, ok := s.users.Load(user); ok { |
| 25 | + return v.(*userRecord) |
| 26 | + } |
| 27 | + rec := &userRecord{state: core.UserState{ |
| 28 | + UserID: user, |
| 29 | + Points: map[core.Metric]int64{}, |
| 30 | + Badges: map[core.Badge]struct{}{}, |
| 31 | + Levels: map[core.Metric]int64{}, |
| 32 | + Updated: time.Now().UTC(), |
| 33 | + }} |
| 34 | + actual, _ := s.users.LoadOrStore(user, rec) |
| 35 | + return actual.(*userRecord) |
36 | 36 | } |
37 | 37 |
|
38 | 38 | func (s *Store) AddPoints(_ context.Context, user core.UserID, metric core.Metric, delta int64) (int64, error) { |
39 | | - rec := s.getOrCreate(user) |
40 | | - rec.mu.Lock() |
41 | | - defer rec.mu.Unlock() |
42 | | - current := rec.state.Points[metric] |
43 | | - next, err := core.AddSafe(current, delta) |
44 | | - if err != nil { return 0, err } |
45 | | - rec.state.Points[metric] = next |
46 | | - rec.state.Updated = time.Now().UTC() |
47 | | - return next, nil |
| 39 | + rec := s.getOrCreate(user) |
| 40 | + rec.mu.Lock() |
| 41 | + defer rec.mu.Unlock() |
| 42 | + current := rec.state.Points[metric] |
| 43 | + next, err := core.AddSafe(current, delta) |
| 44 | + if err != nil { |
| 45 | + return 0, err |
| 46 | + } |
| 47 | + rec.state.Points[metric] = next |
| 48 | + rec.state.Updated = time.Now().UTC() |
| 49 | + return next, nil |
48 | 50 | } |
49 | 51 |
|
50 | 52 | func (s *Store) AwardBadge(_ context.Context, user core.UserID, badge core.Badge) error { |
51 | | - rec := s.getOrCreate(user) |
52 | | - rec.mu.Lock(); defer rec.mu.Unlock() |
53 | | - rec.state.Badges[badge] = struct{}{} |
54 | | - rec.state.Updated = time.Now().UTC() |
55 | | - return nil |
| 53 | + rec := s.getOrCreate(user) |
| 54 | + rec.mu.Lock() |
| 55 | + defer rec.mu.Unlock() |
| 56 | + rec.state.Badges[badge] = struct{}{} |
| 57 | + rec.state.Updated = time.Now().UTC() |
| 58 | + return nil |
56 | 59 | } |
57 | 60 |
|
58 | 61 | func (s *Store) GetState(_ context.Context, user core.UserID) (core.UserState, error) { |
59 | | - rec := s.getOrCreate(user) |
60 | | - rec.mu.Lock(); defer rec.mu.Unlock() |
61 | | - return rec.state.Clone(), nil |
| 62 | + rec := s.getOrCreate(user) |
| 63 | + rec.mu.Lock() |
| 64 | + defer rec.mu.Unlock() |
| 65 | + return rec.state.Clone(), nil |
62 | 66 | } |
63 | 67 |
|
64 | 68 | func (s *Store) SetLevel(_ context.Context, user core.UserID, metric core.Metric, level int64) error { |
65 | | - rec := s.getOrCreate(user) |
66 | | - rec.mu.Lock(); defer rec.mu.Unlock() |
67 | | - rec.state.Levels[metric] = level |
68 | | - rec.state.Updated = time.Now().UTC() |
69 | | - return nil |
| 69 | + rec := s.getOrCreate(user) |
| 70 | + rec.mu.Lock() |
| 71 | + defer rec.mu.Unlock() |
| 72 | + rec.state.Levels[metric] = level |
| 73 | + rec.state.Updated = time.Now().UTC() |
| 74 | + return nil |
70 | 75 | } |
71 | 76 |
|
72 | | -var _ interface{ AddPoints(context.Context, core.UserID, core.Metric, int64) (int64, error); AwardBadge(context.Context, core.UserID, core.Badge) error; GetState(context.Context, core.UserID) (core.UserState, error); SetLevel(context.Context, core.UserID, core.Metric, int64) error } = (*Store)(nil) |
73 | | - |
74 | | - |
| 77 | +var _ interface { |
| 78 | + AddPoints(context.Context, core.UserID, core.Metric, int64) (int64, error) |
| 79 | + AwardBadge(context.Context, core.UserID, core.Badge) error |
| 80 | + GetState(context.Context, core.UserID) (core.UserState, error) |
| 81 | + SetLevel(context.Context, core.UserID, core.Metric, int64) error |
| 82 | +} = (*Store)(nil) |
0 commit comments