-
Notifications
You must be signed in to change notification settings - Fork 51
/
contextstore.go
135 lines (101 loc) · 3.13 KB
/
contextstore.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
package contextstore
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"go.uber.org/zap"
)
type store struct {
storebasePath string
}
const (
eventInfoFile = "eventInfo.data"
)
// NewContextStore returns a handle to a new context store
// The store is maintained in a file hierarchy so if the context id
// already exists calling a storecontext with new id will cause an overwrite
func NewContextStore(basePath string) ContextStore {
_, err := os.Stat(basePath)
if os.IsNotExist(err) {
if err := os.MkdirAll(basePath, 0700); err != nil {
zap.L().Fatal("Failed to create context store directory", zap.Error(err))
}
}
return &store{storebasePath: basePath}
}
// Store context writes to the store the eventInfo which can be used as a event to trireme
func (s *store) StoreContext(contextID string, eventInfo interface{}) error {
folder := filepath.Join(s.storebasePath, contextID)
if _, err := os.Stat(folder); os.IsNotExist(err) {
if err := os.MkdirAll(folder, 0700); err != nil {
return err
}
}
data, err := json.Marshal(eventInfo)
if err != nil {
return err
}
if err = ioutil.WriteFile(filepath.Join(folder, eventInfoFile), data, 0600); err != nil {
return err
}
return nil
}
// GetContextInfo the event corresponding to the store
func (s *store) GetContextInfo(contextID string, context interface{}) error {
folder := filepath.Join(s.storebasePath, contextID)
if _, err := os.Stat(folder); os.IsNotExist(err) {
return fmt.Errorf("Unknown ContextID %s", contextID)
}
data, err := ioutil.ReadFile(filepath.Join(folder, eventInfoFile))
if err != nil {
return fmt.Errorf("Unable to retrieve context from store %s", err.Error())
}
if err := json.Unmarshal(data, context); err != nil {
zap.L().Warn("Found invalid state for context - Cleaning up",
zap.String("contextID", contextID),
zap.Error(err),
)
if rerr := s.RemoveContext(contextID); rerr != nil {
return fmt.Errorf("Failed to remove invalide context for %s", rerr.Error())
}
return err
}
return nil
}
// RemoveContext the context reference from the store
func (s *store) RemoveContext(contextID string) error {
folder := filepath.Join(s.storebasePath, contextID)
if _, err := os.Stat(folder); os.IsNotExist(err) {
return fmt.Errorf("Unknown ContextID %s", contextID)
}
return os.RemoveAll(folder)
}
// Destroy will clean up the entire state for all services in the system
func (s *store) DestroyStore() error {
if _, err := os.Stat(s.storebasePath); os.IsNotExist(err) {
return fmt.Errorf("Store Not Initialized")
}
return os.RemoveAll(s.storebasePath)
}
// WalkStore retrieves all the context store information and returns it in a channel
func (s *store) WalkStore() (chan string, error) {
contextChannel := make(chan string, 1)
files, err := ioutil.ReadDir(s.storebasePath)
if err != nil {
close(contextChannel)
return contextChannel, fmt.Errorf("Store is empty")
}
go func() {
i := 0
for _, file := range files {
zap.L().Debug("File Name", zap.String("Path", file.Name()))
contextChannel <- file.Name()
i++
}
contextChannel <- ""
close(contextChannel)
}()
return contextChannel, nil
}