mirror of
https://github.com/safing/portbase
synced 2025-04-23 02:39:09 +00:00
125 lines
2.4 KiB
Go
125 lines
2.4 KiB
Go
package config
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"strings"
|
|
|
|
"github.com/safing/portbase/log"
|
|
)
|
|
|
|
var (
|
|
configFilePath string
|
|
)
|
|
|
|
func loadConfig() error {
|
|
data, err := ioutil.ReadFile(configFilePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
m, err := JSONToMap(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return setConfig(m)
|
|
}
|
|
|
|
func saveConfig() (err error) {
|
|
data, err := MapToJSON(userConfig)
|
|
if err == nil {
|
|
err = ioutil.WriteFile(configFilePath, data, 0600)
|
|
}
|
|
|
|
if err != nil {
|
|
log.Errorf("config: failed to save config: %s", err)
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// JSONToMap parses and flattens a hierarchical json object.
|
|
func JSONToMap(jsonData []byte) (map[string]interface{}, error) {
|
|
loaded := make(map[string]interface{})
|
|
err := json.Unmarshal(jsonData, &loaded)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
flatten(loaded, loaded, "")
|
|
return loaded, nil
|
|
}
|
|
|
|
func flatten(rootMap, subMap map[string]interface{}, subKey string) {
|
|
for key, entry := range subMap {
|
|
|
|
// get next level key
|
|
subbedKey := key
|
|
if subKey != "" {
|
|
subbedKey = fmt.Sprintf("%s/%s", subKey, key)
|
|
}
|
|
|
|
// check for next subMap
|
|
nextSub, ok := entry.(map[string]interface{})
|
|
if ok {
|
|
flatten(rootMap, nextSub, subbedKey)
|
|
delete(rootMap, key)
|
|
} else if subKey != "" {
|
|
// only set if not on root level
|
|
rootMap[subbedKey] = entry
|
|
}
|
|
}
|
|
}
|
|
|
|
// MapToJSON expands a flattened map and returns it as json.
|
|
func MapToJSON(mapData map[string]interface{}) ([]byte, error) {
|
|
configLock.RLock()
|
|
defer configLock.RUnlock()
|
|
|
|
new := make(map[string]interface{})
|
|
for key, value := range mapData {
|
|
new[key] = value
|
|
}
|
|
|
|
expand(new)
|
|
return json.MarshalIndent(new, "", " ")
|
|
}
|
|
|
|
// expand expands a flattened map.
|
|
func expand(mapData map[string]interface{}) {
|
|
var newMaps []map[string]interface{}
|
|
for key, entry := range mapData {
|
|
if strings.Contains(key, "/") {
|
|
parts := strings.SplitN(key, "/", 2)
|
|
if len(parts) == 2 {
|
|
|
|
// get subMap
|
|
var subMap map[string]interface{}
|
|
v, ok := mapData[parts[0]]
|
|
if ok {
|
|
subMap, ok = v.(map[string]interface{})
|
|
if !ok {
|
|
subMap = make(map[string]interface{})
|
|
newMaps = append(newMaps, subMap)
|
|
mapData[parts[0]] = subMap
|
|
}
|
|
} else {
|
|
subMap = make(map[string]interface{})
|
|
newMaps = append(newMaps, subMap)
|
|
mapData[parts[0]] = subMap
|
|
}
|
|
|
|
// set entry
|
|
subMap[parts[1]] = entry
|
|
// delete entry from
|
|
delete(mapData, key)
|
|
|
|
}
|
|
}
|
|
}
|
|
for _, entry := range newMaps {
|
|
expand(entry)
|
|
}
|
|
}
|