forked from AlanAutomated/wilson
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconfig.go
148 lines (105 loc) · 3.03 KB
/
config.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
147
148
package wilson
import(
"encoding/json"
"io/ioutil"
"log"
"net/http"
"time"
"github.com/xeipuuv/gojsonschema"
)
// Convert a JSON configuration to a Configuration struct
func decodeConfig(encodedConfig []byte) (Configuration, error) {
var config Configuration
err := json.Unmarshal(encodedConfig, &config)
if err != nil {
return config, err
}
return config, nil
}
// Download a JSON configuration and return the body
func downloadConfig(url string) ([]byte, error) {
result, err := http.Get(url)
if err != nil {
return nil, err
}
defer result.Body.Close()
body, err := ioutil.ReadAll(result.Body)
if err != nil {
return nil, err
}
if result.StatusCode != http.StatusOK {
return nil, err
}
return body, nil
}
// A generic function to read a local configuration file
func readFile(path string) ([]byte, error) {
config, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return config, nil
}
// Ensure the JSON confinguration conforms to the known schema
func validateConfig(config []byte, schema string) (bool, error) {
jsonDocument := gojsonschema.NewBytesLoader(config)
jsonSchema := gojsonschema.NewStringLoader(schema)
result, err := gojsonschema.Validate(jsonDocument, jsonSchema)
if err != nil {
return false, err
}
return result.Valid(), nil
}
// A generic function to write a local configuration file
func writeFile(config []byte, path string) (error) {
err := ioutil.WriteFile(path, config, 0644)
if err != nil {
return err
}
return nil
}
// Refresh the configuration on a given interval using a go routine
func RefreshConfig(seconds float64, url string) Configuration {
time.Sleep(time.Duration(seconds) * time.Second)
config := Config(url)
return config
}
// A public function to perform most of the lifting
func Config(url string) (Configuration) {
// Track whether a configuration has been read from disk
fromFile := false
encodedConfig, err := downloadConfig(url)
if err != nil {
// Read from the default configuration path since we don't have a config
// to tell us where to look
encodedConfig, err = readFile(".wilson")
if err != nil {
log.Fatal(ErrConfigNotFound)
}
fromFile = true
}
// First check for an error validating the configuration
valid, err := validateConfig(encodedConfig, Schema)
if err != nil {
log.Fatal(ErrConfigNotValid)
}
// Next, ensure gojsonschema validated the configuration
if !valid {
log.Fatal(ErrConfigNotValid)
}
// Decode the configuration from JSON
config, err := decodeConfig(encodedConfig)
if err != nil {
log.Fatal(ErrConfigDecodeFailed)
}
// If the file was downloaded from a URL, write it to desk for safe keeping
if !fromFile {
path := config.ConfigFile
err := writeFile(encodedConfig, path)
if err != nil {
log.Printf(WarnConfigWriteFailed)
}
}
// Finally, return the config and hope we accounted for all known errors
return config
}