-
Notifications
You must be signed in to change notification settings - Fork 1
/
vault.go
136 lines (120 loc) · 2.79 KB
/
vault.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
package globalsign
import (
"sync"
"time"
)
// VaultItem represents a record identity.
type VaultItem struct {
sync.RWMutex
data *DSSIdentity
expires *time.Time
}
// expire immediate expiration of vault item.
func (item *VaultItem) expire() {
item.Lock()
expiration := time.Now()
item.expires = &expiration
item.Unlock()
}
func (item *VaultItem) touch(duration time.Duration) {
item.Lock()
expiration := time.Now().Add(duration)
item.expires = &expiration
item.Unlock()
}
// expired return `true` if vault item expired.
func (item *VaultItem) expired() bool {
var value bool
item.RLock()
if item.expires == nil {
value = true
} else {
value = item.expires.Before(time.Now())
}
item.RUnlock()
return value
}
// ExpiredIdentityFunc is a callback which will be called once identity expired.
type ExpiredIdentityFunc func(key string, identity *DSSIdentity)
// IdentityVault store DSS identity until its expired.
type IdentityVault struct {
mutex sync.RWMutex
ttl time.Duration
items map[string]*VaultItem
expfunc ExpiredIdentityFunc
}
// Set is a thread-safe way to add identity to cache.
func (cache *IdentityVault) Set(key string, identity *DSSIdentity) {
cache.mutex.Lock()
item := &VaultItem{data: identity}
item.touch(cache.ttl)
cache.items[key] = item
cache.mutex.Unlock()
}
// Get is a thread-safe way to lookup items.
func (cache *IdentityVault) Get(key string) (data *DSSIdentity, found bool) {
cache.mutex.Lock()
item, exists := cache.items[key]
if !exists || item.expired() {
data = nil
found = false
} else {
data = item.data
found = true
}
cache.mutex.Unlock()
return
}
// Count returns the number of items in the cache
// (helpful for tracking memory leaks).
func (cache *IdentityVault) Count() int {
cache.mutex.RLock()
count := len(cache.items)
cache.mutex.RUnlock()
return count
}
// Del remove item without trigger callback.
func (cache *IdentityVault) Del(key string) {
cache.mutex.Lock()
_, exists := cache.items[key]
if exists {
delete(cache.items, key)
}
cache.mutex.Unlock()
}
func (cache *IdentityVault) cleanup() {
cache.mutex.Lock()
for key, item := range cache.items {
if item.expired() {
delete(cache.items, key)
if cache.expfunc != nil {
cache.expfunc(key, item.data)
}
}
}
cache.mutex.Unlock()
}
func (cache *IdentityVault) startCleanupTimer() {
duration := cache.ttl / 2
if duration < time.Second {
duration = time.Second
}
ticker := time.Tick(duration)
go (func() {
for {
select {
case <-ticker:
cache.cleanup()
}
}
})()
}
// NewIdentityVault is a helper to create instance of the identities vault struct.
func NewIdentityVault(duration time.Duration) *IdentityVault {
cache := &IdentityVault{
ttl: duration,
items: map[string]*VaultItem{},
}
cache.startCleanupTimer()
return cache
}