diff options
author | Steve <nilslice@gmail.com> | 2017-01-16 16:14:00 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-01-16 16:14:00 -0800 |
commit | 2af951230eddc45ba429cff10d7566ad98fd343b (patch) | |
tree | 7543be03fae8aeeacc8eb48dbe16ab2d42fbca0b /system/db/config.go | |
parent | 3249b82b2a4f1aa0ae9e6943cd72dd7eebae8a4a (diff) |
[core] Adding toggle for CORS, GZIP in admin/cms configuration (#30)
This PR enables admins to disable/enable CORS and GZIP from within the admin CMS configuration page. Both are enabled by default.
Note: currently, the GZIP implementation is 100% on the fly, for every qualifying API endpoint request. This could add significant CPU usage, but dramatically decreases bandwidth. Will be considering other better implementations, but for now YMMV.
Possible optimizations:
- pooling gzip Writers vs. creating a new one for each response
- caching gzipped responses (in memory? on disk?)
- enforcing size threshold (only gzip content larger than N bytes)
Diffstat (limited to 'system/db/config.go')
-rw-r--r-- | system/db/config.go | 143 |
1 files changed, 101 insertions, 42 deletions
diff --git a/system/db/config.go b/system/db/config.go index 45b3952..5a93353 100644 --- a/system/db/config.go +++ b/system/db/config.go @@ -13,57 +13,62 @@ import ( "github.com/gorilla/schema" ) -var configCache url.Values +var configCache map[string]interface{} func init() { - configCache = make(url.Values) + configCache = make(map[string]interface{}) } // SetConfig sets key:value pairs in the db for configuration settings func SetConfig(data url.Values) error { - err := store.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("__config")) - - // check for any multi-value fields (ex. checkbox fields) - // and correctly format for db storage. Essentially, we need - // fieldX.0: value1, fieldX.1: value2 => fieldX: []string{value1, value2} - var discardKeys []string - for k, v := range data { - if strings.Contains(k, ".") { - key := strings.Split(k, ".")[0] - - if data.Get(key) == "" { - data.Set(key, v[0]) - } else { - data.Add(key, v[0]) - } - - discardKeys = append(discardKeys, k) + var j []byte + + // check for any multi-value fields (ex. checkbox fields) + // and correctly format for db storage. Essentially, we need + // fieldX.0: value1, fieldX.1: value2 => fieldX: []string{value1, value2} + var discardKeys []string + for k, v := range data { + if strings.Contains(k, ".") { + key := strings.Split(k, ".")[0] + + if data.Get(key) == "" { + data.Set(key, v[0]) + } else { + data.Add(key, v[0]) } - } - for _, discardKey := range discardKeys { - data.Del(discardKey) + discardKeys = append(discardKeys, k) } + } - cfg := &config.Config{} - dec := schema.NewDecoder() - dec.SetAliasTag("json") // allows simpler struct tagging when creating a content type - dec.IgnoreUnknownKeys(true) // will skip over form values submitted, but not in struct - err := dec.Decode(cfg, data) - if err != nil { - return err - } + for _, discardKey := range discardKeys { + data.Del(discardKey) + } - // check for "invalidate" value to reset the Etag - if len(cfg.CacheInvalidate) > 0 && cfg.CacheInvalidate[0] == "invalidate" { - cfg.Etag = NewEtag() - cfg.CacheInvalidate = []string{} - } + cfg := &config.Config{} + dec := schema.NewDecoder() + dec.SetAliasTag("json") // allows simpler struct tagging when creating a content type + dec.IgnoreUnknownKeys(true) // will skip over form values submitted, but not in struct + err := dec.Decode(cfg, data) + if err != nil { + return err + } - j, err := json.Marshal(cfg) - if err != nil { - return err + // check for "invalidate" value to reset the Etag + if len(cfg.CacheInvalidate) > 0 && cfg.CacheInvalidate[0] == "invalidate" { + cfg.Etag = NewEtag() + cfg.CacheInvalidate = []string{} + } + + j, err = json.Marshal(cfg) + if err != nil { + return err + } + + err = store.Update(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte("__config")) + if b == nil { + return bolt.ErrBucketNotFound } err = b.Put([]byte("settings"), j) @@ -77,7 +82,14 @@ func SetConfig(data url.Values) error { return err } - configCache = data + // convert json => map[string]interface{} + var kv map[string]interface{} + err = json.Unmarshal(j, &kv) + if err != nil { + return err + } + + configCache = kv return nil } @@ -108,6 +120,9 @@ func ConfigAll() ([]byte, error) { val := &bytes.Buffer{} err := store.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("__config")) + if b == nil { + return bolt.ErrBucketNotFound + } _, err := val.Write(b.Get([]byte("settings"))) if err != nil { return err @@ -131,6 +146,13 @@ func PutConfig(key string, value interface{}) error { return err } + if c == nil { + c, err = emptyConfig() + if err != nil { + return err + } + } + err = json.Unmarshal(c, &kv) if err != nil { return err @@ -166,6 +188,43 @@ func PutConfig(key string, value interface{}) error { // ConfigCache is a in-memory cache of the Configs for quicker lookups // 'key' is the JSON tag associated with the config field -func ConfigCache(key string) string { - return configCache.Get(key) +func ConfigCache(key string) interface{} { + return configCache[key] +} + +// LoadCacheConfig loads the config into a cache to be accessed by ConfigCache() +func LoadCacheConfig() error { + c, err := ConfigAll() + if err != nil { + return err + } + + if c == nil { + c, err = emptyConfig() + if err != nil { + return err + } + } + + // convert json => map[string]interface{} + var kv map[string]interface{} + err = json.Unmarshal(c, &kv) + if err != nil { + return err + } + + configCache = kv + + return nil +} + +func emptyConfig() ([]byte, error) { + cfg := &config.Config{} + + data, err := json.Marshal(cfg) + if err != nil { + return nil, err + } + + return data, nil } |