-
Notifications
You must be signed in to change notification settings - Fork 2
/
hashStore.go
112 lines (94 loc) · 2.15 KB
/
hashStore.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
package hashStore
import (
"github.com/koestler/go-webcam/cameraClient"
"time"
)
type HashStore struct {
config Config
shutdown chan struct{}
closed chan struct{}
setChannel chan setRequest
getChannel chan getRequest
storage map[string]value
}
type Config interface {
HashTimeout() time.Duration
}
type setRequest struct {
hash string
cp cameraClient.CameraPicture
response chan struct{}
}
type getRequest struct {
hash string
response chan cameraClient.CameraPicture
}
type value struct {
cp cameraClient.CameraPicture
touched time.Time
}
func Run(config Config) *HashStore {
h := &HashStore{
config: config,
shutdown: make(chan struct{}),
closed: make(chan struct{}),
setChannel: make(chan setRequest, 16),
getChannel: make(chan getRequest, 16),
storage: make(map[string]value),
}
go h.worker()
return h
}
func (h *HashStore) Shutdown() {
// send remaining points
close(h.shutdown)
// wait for worker to shut down
<-h.closed
}
func (h *HashStore) Set(hash string, cp cameraClient.CameraPicture) {
response := make(chan struct{})
h.setChannel <- setRequest{hash, cp, response}
<-response
}
func (h *HashStore) Get(hash string) cameraClient.CameraPicture {
response := make(chan cameraClient.CameraPicture)
h.getChannel <- getRequest{hash, response}
return <-response
}
func (h *HashStore) Config() Config {
return h.config
}
func (h *HashStore) worker() {
defer close(h.closed)
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case setRequest := <-h.setChannel:
if v, ok := h.storage[setRequest.hash]; ok {
v.touched = time.Now()
} else {
h.storage[setRequest.hash] = value{
cp: setRequest.cp,
touched: time.Now(),
}
}
close(setRequest.response)
case getRequest := <-h.getChannel:
if v, ok := h.storage[getRequest.hash]; ok {
getRequest.response <- v.cp
} else {
getRequest.response <- nil
}
case <-ticker.C:
now := time.Now()
for k, v := range h.storage {
if v.touched.Add(h.config.HashTimeout()).Before(now) {
delete(h.storage, k)
}
}
case <-h.shutdown:
return // shutdown
}
}
}