Merge pull request #4 from 30x/XAPID-824

Make viper calls thread safe.
diff --git a/config/config.go b/config/config.go
index 9fe19a4..b9e9a94 100644
--- a/config/config.go
+++ b/config/config.go
@@ -4,8 +4,10 @@
 	"github.com/30x/apid-core"
 	"github.com/spf13/viper"
 	"log"
-	"strings"
 	"os"
+	"strings"
+	"sync"
+	"time"
 )
 
 const (
@@ -22,39 +24,106 @@
 	defaultConfigPath     = "."
 )
 
-var cfg *viper.Viper
+var configlock sync.Mutex
+
+type ConfigMgr struct {
+	sync.Mutex
+	vcfg *viper.Viper
+}
+
+// Wrapper function to make the viper calls thread safe
+var cfg *ConfigMgr
+
+func (c *ConfigMgr) SetDefault(key string, value interface{}) {
+	c.Lock()
+	c.vcfg.SetDefault(key, value)
+	c.Unlock()
+}
+
+func (c *ConfigMgr) Set(key string, value interface{}) {
+	c.Lock()
+	c.vcfg.Set(key, value)
+	c.Unlock()
+}
+
+func (c *ConfigMgr) Get(key string) interface{} {
+	c.Lock()
+	defer c.Unlock()
+	return c.vcfg.Get(key)
+}
+
+func (c *ConfigMgr) GetBool(key string) bool {
+	c.Lock()
+	defer c.Unlock()
+	return c.vcfg.GetBool(key)
+}
+
+func (c *ConfigMgr) GetFloat64(key string) float64 {
+	c.Lock()
+	defer c.Unlock()
+	return c.vcfg.GetFloat64(key)
+}
+
+func (c *ConfigMgr) GetInt(key string) int {
+	c.Lock()
+	defer c.Unlock()
+	return c.vcfg.GetInt(key)
+}
+
+func (c *ConfigMgr) GetString(key string) string {
+	cfg.Lock()
+	defer cfg.Unlock()
+	return c.vcfg.GetString(key)
+}
+
+func (c *ConfigMgr) GetDuration(key string) time.Duration {
+	cfg.Lock()
+	defer cfg.Unlock()
+	return c.vcfg.GetDuration(key)
+}
+
+func (c *ConfigMgr) IsSet(key string) bool {
+	c.Lock()
+	defer c.Unlock()
+	return c.vcfg.IsSet(key)
+}
 
 func GetConfig() apid.ConfigService {
+	configlock.Lock()
+	defer configlock.Unlock()
 	if cfg == nil {
 
-		cfg = viper.New()
+		vcfg := viper.New()
 
 		// for config file search path
-		cfg.SetConfigType(configFileType)
+		vcfg.SetConfigType(configFileType)
 
-		cfg.SetDefault(configPathKey, defaultConfigPath)
-		configFilePath := cfg.GetString(configPathKey)
-		cfg.AddConfigPath(configFilePath)
+		vcfg.SetDefault(configPathKey, defaultConfigPath)
+		configFilePath := vcfg.GetString(configPathKey)
+		vcfg.AddConfigPath(configFilePath)
 
-		cfg.SetDefault(configFileNameKey, defaultConfigFilename)
-		configFileName := cfg.GetString(configFileNameKey)
+		vcfg.SetDefault(configFileNameKey, defaultConfigFilename)
+		configFileName := vcfg.GetString(configFileNameKey)
 		configFileName = strings.TrimSuffix(configFileName, ".yaml")
-		cfg.SetConfigName(configFileName)
+		vcfg.SetConfigName(configFileName)
 
 		// for user-specified absolute config file
-		configFile, ok := os.LookupEnv(configFileEnvVar); if ok {
-			cfg.SetConfigFile(configFile)
+		configFile, ok := os.LookupEnv(configFileEnvVar)
+		if ok {
+			vcfg.SetConfigFile(configFile)
 		}
 
-		cfg.SetDefault(localStoragePathKey, localStoragePathDefault)
+		vcfg.SetDefault(localStoragePathKey, localStoragePathDefault)
 
-		err := cfg.ReadInConfig()
+		err := vcfg.ReadInConfig()
 		if err != nil {
 			log.Printf("Error in config file '%s': %s", configFileNameKey, err)
 		}
 
-		cfg.SetEnvPrefix("apid") // eg. env var "APID_SOMETHING" will bind to config var "something"
-		cfg.AutomaticEnv()
+		vcfg.SetEnvPrefix("apid") // eg. env var "APID_SOMETHING" will bind to config var "something"
+		vcfg.AutomaticEnv()
+
+		cfg = &ConfigMgr{vcfg: vcfg}
 	}
 	return cfg
 }