github.com/abolfazlbeh/zhycan@v0.0.0-20230819144214-24cf38237387/internal/config/wrapper.go (about) 1 package config 2 3 import ( 4 "bytes" 5 "github.com/fsnotify/fsnotify" 6 "github.com/spf13/viper" 7 "log" 8 "sync" 9 "time" 10 ) 11 12 // MARK: ViperWrapper 13 14 // ViperWrapper object 15 type ViperWrapper struct { 16 Instance *viper.Viper 17 ConfigPath []string 18 ConfigName string 19 ConfigEnvPrefix string 20 ConfigResourcePlace string 21 lastModified time.Time 22 wg sync.WaitGroup 23 lock sync.Mutex 24 } 25 26 // MARK: Public Methods 27 28 // Load - It creates new instance of Viper and load config file base on ConfigName 29 func (w *ViperWrapper) Load() error { 30 w.wg.Add(1) 31 defer w.wg.Done() 32 33 w.Instance = viper.New() 34 for _, path := range w.ConfigPath { 35 w.Instance.AddConfigPath(path) 36 } 37 w.Instance.SetConfigName(w.ConfigName) 38 err := w.Instance.ReadInConfig() 39 if err != nil { 40 return err 41 } 42 43 // Get env variables and bind them if exist in config file 44 env, exist := w.Get("env", true) 45 if env != nil && exist { 46 envArray := make([]string, len(env.([]interface{}))) 47 for i, v := range env.([]interface{}) { 48 envArray[i] = v.(string) 49 } 50 51 if len(envArray) > 0 { 52 w.Instance.SetEnvPrefix(w.ConfigEnvPrefix) 53 54 for _, e := range envArray { 55 _ = w.Instance.BindEnv(e) 56 } 57 } 58 } 59 60 return nil 61 } 62 63 // LoadFromRemote - loads the configs from the remote server 64 func (w *ViperWrapper) LoadFromRemote(data []byte) error { 65 w.wg.Add(1) 66 defer w.wg.Done() 67 68 if w.Instance == nil { 69 w.Instance = viper.New() 70 } 71 72 err := w.Instance.ReadConfig(bytes.NewBuffer(data)) 73 if err != nil { 74 return err 75 } 76 77 // Get env variables and bind them if exist in config file 78 env, exist := w.Get("env", true) 79 if env != nil && exist { 80 envArray := make([]string, len(env.([]interface{}))) 81 for i, v := range env.([]interface{}) { 82 envArray[i] = v.(string) 83 } 84 85 if len(envArray) > 0 { 86 w.Instance.SetEnvPrefix(w.ConfigEnvPrefix) 87 88 for _, e := range envArray { 89 _ = w.Instance.BindEnv(e) 90 } 91 } 92 } 93 94 return nil 95 } 96 97 // RegisterChangeCallback - get function and call it when config file changed 98 func (w *ViperWrapper) RegisterChangeCallback(fn func() interface{}) { 99 w.wg.Wait() 100 101 w.Instance.WatchConfig() 102 w.Instance.OnConfigChange(func(e fsnotify.Event) { 103 log.Println(w.ConfigName, "Config file changed: ", e.Name) 104 105 if fn != nil { 106 fn() 107 } 108 }) 109 } 110 111 // Get method - returns value base on key 112 func (w *ViperWrapper) Get(key string, bypass bool) (interface{}, bool) { 113 if !bypass { 114 w.wg.Wait() 115 } 116 117 w.lock.Lock() 118 defer w.lock.Unlock() 119 120 exist := w.Instance.InConfig(key) 121 return w.Instance.Get(key), exist 122 } 123 124 // Set method - set value by given key and write it back to file 125 func (w *ViperWrapper) Set(key string, value interface{}, bypass bool) error { 126 if !bypass { 127 w.wg.Wait() 128 } 129 130 w.lock.Lock() 131 defer w.lock.Unlock() 132 133 w.Instance.Set(key, value) 134 return w.Instance.SafeWriteConfig() 135 }