-
Notifications
You must be signed in to change notification settings - Fork 18
/
state.go
146 lines (123 loc) · 2.68 KB
/
state.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
137
138
139
140
141
142
143
144
145
146
package flow
import (
"bytes"
"errors"
"text/template"
)
var errStateNotFound = errors.New("flow state not found")
// State is the "app"'s state
type State map[string]interface{}
func (s State) MergeWith(update State) State {
n := State{}
for k, v := range s {
n[k] = v
}
for k, v := range update {
n[k] = v
}
return n
}
// GetString return the value to a given key as a string.
// If the key is not found or isn't a string, an empty string is returned.
func (s State) GetString(key string) string {
vRaw, ok := s[key]
if ok {
v, ok := vRaw.(string)
if ok {
return v
}
}
return ""
}
// GetInt return the value to a given key as a int.
// If the key is not found or isn't an int, zero is returned.
func (s State) GetInt(key string) int {
vRaw, ok := s[key]
if ok {
v, ok := vRaw.(int)
if ok {
return v
}
}
return 0
}
// GetBool return the value to a given key as a bool.
// If the key is not found or isn't a bool, false is returned.
func (s State) GetBool(key string) bool {
vRaw, ok := s[key]
if ok {
v, ok := vRaw.(bool)
if ok {
return v
}
}
return false
}
// JSON-serializable flow state.
type flowState struct {
// The name of the step.
StepName Name
Done bool
// ID of the post produced by the step.
PostID string
// Application-level state.
AppState State
}
func (f *Flow) storeState(state flowState) error {
if f.UserID == "" {
return errors.New("no user specified")
}
// Set AppState to differentiate an existing flow
if state.AppState == nil {
state.AppState = State{}
}
ok, err := f.api.KV.Set(kvKey(f.UserID, f.name), state)
if err != nil {
return err
}
if !ok {
return errors.New("value not set without errors")
}
f.state = &state
return nil
}
func (f *Flow) getState() (flowState, error) {
if f.UserID == "" {
return flowState{}, errors.New("no user specified")
}
if f.state != nil {
return *f.state, nil
}
state := flowState{}
err := f.api.KV.Get(kvKey(f.UserID, f.name), &state)
if err != nil {
return flowState{}, err
}
if state.AppState == nil {
return flowState{}, errStateNotFound
}
f.state = &state
return state, err
}
func (f *Flow) removeState() error {
if f.UserID == "" {
return errors.New("no user specified")
}
f.state = nil
return f.api.KV.Delete(kvKey(f.UserID, f.name))
}
func kvKey(userID string, flowName Name) string {
return "_flow-" + userID + "-" + string(flowName)
}
func formatState(source string, state State) string {
t, err := template.New("message").Parse(source)
if err != nil {
return source + " ###ERROR: " + err.Error()
}
buf := bytes.NewBuffer(nil)
err = t.Execute(buf, state)
if err != nil {
return source + " ###ERROR: " + err.Error()
}
return buf.String()
}