-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstore.go
More file actions
68 lines (60 loc) · 1.77 KB
/
store.go
File metadata and controls
68 lines (60 loc) · 1.77 KB
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
package mppx
import (
"context"
"sync"
)
// Store is a generic key-value store interface for tracking used credentials,
// session state, and other payment-related state.
//
// Implement this interface to use Redis, Postgres, Cloudflare KV, etc.
type Store interface {
// Get retrieves a value by key. Returns ("", false, nil) if not found.
Get(ctx context.Context, key string) (string, bool, error)
// Put stores a value by key.
Put(ctx context.Context, key, value string) error
// Delete removes a value by key.
Delete(ctx context.Context, key string) error
}
// MemoryStore is a thread-safe in-memory Store implementation.
// Suitable for development and testing; does not persist across restarts.
type MemoryStore struct {
mu sync.RWMutex
data map[string]string
}
// NewMemoryStore creates a new in-memory store.
func NewMemoryStore() *MemoryStore {
return &MemoryStore{data: make(map[string]string)}
}
func (s *MemoryStore) Get(_ context.Context, key string) (value string, found bool, err error) {
s.mu.RLock()
defer s.mu.RUnlock()
v, ok := s.data[key]
return v, ok, nil
}
func (s *MemoryStore) Put(_ context.Context, key, value string) error {
s.mu.Lock()
defer s.mu.Unlock()
s.data[key] = value
return nil
}
func (s *MemoryStore) Delete(_ context.Context, key string) error {
s.mu.Lock()
defer s.mu.Unlock()
delete(s.data, key)
return nil
}
// MarkUsed marks a key as used in the store (for replay detection).
// Returns (true, nil) if the key was newly marked, (false, nil) if already used.
func MarkUsed(ctx context.Context, store Store, key string) (bool, error) {
_, exists, err := store.Get(ctx, key)
if err != nil {
return false, err
}
if exists {
return false, nil
}
if err := store.Put(ctx, key, "1"); err != nil {
return false, err
}
return true, nil
}