github.com/rudderlabs/rudder-go-kit@v0.30.0/config/hotreloadable.go (about)

     1  package config
     2  
     3  import (
     4  	"strings"
     5  	"sync"
     6  	"time"
     7  )
     8  
     9  // RegisterIntConfigVariable registers int config variable
    10  //
    11  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
    12  // e.g. asking for the same keys but in a different order can result in a different value to be returned
    13  //
    14  // Deprecated: use GetIntVar or GetReloadableIntVar instead
    15  func RegisterIntConfigVariable(defaultValue int, ptr *int, isHotReloadable bool, valueScale int, orderedKeys ...string) {
    16  	Default.RegisterIntConfigVariable(defaultValue, ptr, isHotReloadable, valueScale, orderedKeys...)
    17  }
    18  
    19  // GetIntVar registers a not hot-reloadable int config variable
    20  //
    21  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
    22  // e.g. asking for the same keys but in a different order can result in a different value to be returned
    23  func GetIntVar(defaultValue, valueScale int, orderedKeys ...string) int {
    24  	return Default.GetIntVar(defaultValue, valueScale, orderedKeys...)
    25  }
    26  
    27  // GetReloadableIntVar registers a hot-reloadable int config variable
    28  //
    29  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
    30  // e.g. asking for the same keys but in a different order can result in a different value to be returned
    31  func GetReloadableIntVar(defaultValue, valueScale int, orderedKeys ...string) *Reloadable[int] {
    32  	return Default.GetReloadableIntVar(defaultValue, valueScale, orderedKeys...)
    33  }
    34  
    35  // RegisterIntConfigVariable registers int config variable
    36  //
    37  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
    38  // e.g. asking for the same keys but in a different order can result in a different value to be returned
    39  //
    40  // Deprecated: use GetIntVar or GetReloadableIntVar instead
    41  func (c *Config) RegisterIntConfigVariable(
    42  	defaultValue int, ptr *int, isHotReloadable bool, valueScale int, orderedKeys ...string,
    43  ) {
    44  	c.registerIntVar(defaultValue, ptr, isHotReloadable, valueScale, func(v int) {
    45  		*ptr = v
    46  	}, orderedKeys...)
    47  }
    48  
    49  // GetIntVar registers a not hot-reloadable int config variable
    50  //
    51  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
    52  // e.g. asking for the same keys but in a different order can result in a different value to be returned
    53  func (c *Config) GetIntVar(defaultValue, valueScale int, orderedKeys ...string) int {
    54  	var ret int
    55  	c.registerIntVar(defaultValue, nil, false, valueScale, func(v int) {
    56  		ret = v
    57  	}, orderedKeys...)
    58  	return ret
    59  }
    60  
    61  // GetReloadableIntVar registers a hot-reloadable int config variable
    62  //
    63  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
    64  // e.g. asking for the same keys but in a different order can result in a different value to be returned
    65  func (c *Config) GetReloadableIntVar(defaultValue, valueScale int, orderedKeys ...string) *Reloadable[int] {
    66  	ptr, exists := getOrCreatePointer(
    67  		c.reloadableVars, c.reloadableVarsMisuses, &c.reloadableVarsLock, defaultValue*valueScale, orderedKeys...,
    68  	)
    69  	if !exists {
    70  		c.registerIntVar(defaultValue, ptr, true, valueScale, func(v int) {
    71  			ptr.store(v)
    72  		}, orderedKeys...)
    73  	}
    74  	return ptr
    75  }
    76  
    77  func (c *Config) registerIntVar(
    78  	defaultValue int, ptr any, isHotReloadable bool, valueScale int, store func(int), orderedKeys ...string,
    79  ) {
    80  	configVar := configValue{
    81  		value:        ptr,
    82  		multiplier:   valueScale,
    83  		defaultValue: defaultValue,
    84  		keys:         orderedKeys,
    85  	}
    86  
    87  	if isHotReloadable {
    88  		c.hotReloadableConfigLock.Lock()
    89  		c.appendVarToConfigMaps(orderedKeys, &configVar)
    90  		c.hotReloadableConfigLock.Unlock()
    91  	}
    92  
    93  	for _, key := range orderedKeys {
    94  		if c.IsSet(key) {
    95  			store(c.GetInt(key, defaultValue) * valueScale)
    96  			return
    97  		}
    98  	}
    99  	store(defaultValue * valueScale)
   100  }
   101  
   102  // RegisterBoolConfigVariable registers bool config variable
   103  //
   104  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   105  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   106  //
   107  // Deprecated: use GetBoolVar or GetReloadableBoolVar instead
   108  func RegisterBoolConfigVariable(defaultValue bool, ptr *bool, isHotReloadable bool, orderedKeys ...string) {
   109  	Default.RegisterBoolConfigVariable(defaultValue, ptr, isHotReloadable, orderedKeys...)
   110  }
   111  
   112  // GetBoolVar registers a not hot-reloadable bool config variable
   113  //
   114  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   115  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   116  func GetBoolVar(defaultValue bool, orderedKeys ...string) bool {
   117  	return Default.GetBoolVar(defaultValue, orderedKeys...)
   118  }
   119  
   120  // GetReloadableBoolVar registers a hot-reloadable bool config variable
   121  //
   122  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   123  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   124  func GetReloadableBoolVar(defaultValue bool, orderedKeys ...string) *Reloadable[bool] {
   125  	return Default.GetReloadableBoolVar(defaultValue, orderedKeys...)
   126  }
   127  
   128  // RegisterBoolConfigVariable registers bool config variable
   129  //
   130  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   131  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   132  //
   133  // Deprecated: use GetBoolVar or GetReloadableBoolVar instead
   134  func (c *Config) RegisterBoolConfigVariable(defaultValue bool, ptr *bool, isHotReloadable bool, orderedKeys ...string) {
   135  	c.registerBoolVar(defaultValue, ptr, isHotReloadable, func(v bool) {
   136  		*ptr = v
   137  	}, orderedKeys...)
   138  }
   139  
   140  // GetBoolVar registers a not hot-reloadable bool config variable
   141  //
   142  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   143  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   144  func (c *Config) GetBoolVar(defaultValue bool, orderedKeys ...string) bool {
   145  	var ret bool
   146  	c.registerBoolVar(defaultValue, nil, false, func(v bool) {
   147  		ret = v
   148  	}, orderedKeys...)
   149  	return ret
   150  }
   151  
   152  // GetReloadableBoolVar registers a hot-reloadable bool config variable
   153  //
   154  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   155  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   156  func (c *Config) GetReloadableBoolVar(defaultValue bool, orderedKeys ...string) *Reloadable[bool] {
   157  	ptr, exists := getOrCreatePointer(
   158  		c.reloadableVars, c.reloadableVarsMisuses, &c.reloadableVarsLock, defaultValue, orderedKeys...,
   159  	)
   160  	if !exists {
   161  		c.registerBoolVar(defaultValue, ptr, true, func(v bool) {
   162  			ptr.store(v)
   163  		}, orderedKeys...)
   164  	}
   165  	return ptr
   166  }
   167  
   168  func (c *Config) registerBoolVar(defaultValue bool, ptr any, isHotReloadable bool, store func(bool), orderedKeys ...string) {
   169  	configVar := configValue{
   170  		value:        ptr,
   171  		defaultValue: defaultValue,
   172  		keys:         orderedKeys,
   173  	}
   174  
   175  	if isHotReloadable {
   176  		c.hotReloadableConfigLock.Lock()
   177  		c.appendVarToConfigMaps(orderedKeys, &configVar)
   178  		c.hotReloadableConfigLock.Unlock()
   179  	}
   180  
   181  	for _, key := range orderedKeys {
   182  		c.bindEnv(key)
   183  		if c.IsSet(key) {
   184  			store(c.GetBool(key, defaultValue))
   185  			return
   186  		}
   187  	}
   188  	store(defaultValue)
   189  }
   190  
   191  // RegisterFloat64ConfigVariable registers float64 config variable
   192  //
   193  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   194  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   195  //
   196  // Deprecated: use GetFloat64Var or GetReloadableFloat64Var instead
   197  func RegisterFloat64ConfigVariable(defaultValue float64, ptr *float64, isHotReloadable bool, orderedKeys ...string) {
   198  	Default.RegisterFloat64ConfigVariable(defaultValue, ptr, isHotReloadable, orderedKeys...)
   199  }
   200  
   201  // GetFloat64Var registers a not hot-reloadable float64 config variable
   202  //
   203  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   204  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   205  func GetFloat64Var(defaultValue float64, orderedKeys ...string) float64 {
   206  	return Default.GetFloat64Var(defaultValue, orderedKeys...)
   207  }
   208  
   209  // GetReloadableFloat64Var registers a hot-reloadable float64 config variable
   210  //
   211  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   212  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   213  func GetReloadableFloat64Var(defaultValue float64, orderedKeys ...string) *Reloadable[float64] {
   214  	return Default.GetReloadableFloat64Var(defaultValue, orderedKeys...)
   215  }
   216  
   217  // RegisterFloat64ConfigVariable registers float64 config variable
   218  //
   219  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   220  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   221  //
   222  // Deprecated: use GetFloat64Var or GetReloadableFloat64Var instead
   223  func (c *Config) RegisterFloat64ConfigVariable(
   224  	defaultValue float64, ptr *float64, isHotReloadable bool, orderedKeys ...string,
   225  ) {
   226  	c.registerFloat64Var(defaultValue, ptr, isHotReloadable, func(v float64) {
   227  		*ptr = v
   228  	}, orderedKeys...)
   229  }
   230  
   231  // GetFloat64Var registers a not hot-reloadable float64 config variable
   232  //
   233  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   234  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   235  func (c *Config) GetFloat64Var(defaultValue float64, orderedKeys ...string) float64 {
   236  	var ret float64
   237  	c.registerFloat64Var(defaultValue, nil, false, func(v float64) {
   238  		ret = v
   239  	}, orderedKeys...)
   240  	return ret
   241  }
   242  
   243  // GetReloadableFloat64Var registers a hot-reloadable float64 config variable
   244  //
   245  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   246  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   247  func (c *Config) GetReloadableFloat64Var(defaultValue float64, orderedKeys ...string) *Reloadable[float64] {
   248  	ptr, exists := getOrCreatePointer(
   249  		c.reloadableVars, c.reloadableVarsMisuses, &c.reloadableVarsLock, defaultValue, orderedKeys...,
   250  	)
   251  	if !exists {
   252  		c.registerFloat64Var(defaultValue, ptr, true, func(v float64) {
   253  			ptr.store(v)
   254  		}, orderedKeys...)
   255  	}
   256  	return ptr
   257  }
   258  
   259  func (c *Config) registerFloat64Var(
   260  	defaultValue float64, ptr any, isHotReloadable bool, store func(float64), orderedKeys ...string,
   261  ) {
   262  	configVar := configValue{
   263  		value:        ptr,
   264  		multiplier:   1.0,
   265  		defaultValue: defaultValue,
   266  		keys:         orderedKeys,
   267  	}
   268  
   269  	if isHotReloadable {
   270  		c.hotReloadableConfigLock.Lock()
   271  		c.appendVarToConfigMaps(orderedKeys, &configVar)
   272  		c.hotReloadableConfigLock.Unlock()
   273  	}
   274  
   275  	for _, key := range orderedKeys {
   276  		c.bindEnv(key)
   277  		if c.IsSet(key) {
   278  			store(c.GetFloat64(key, defaultValue))
   279  			return
   280  		}
   281  	}
   282  	store(defaultValue)
   283  }
   284  
   285  // RegisterInt64ConfigVariable registers int64 config variable
   286  //
   287  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   288  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   289  //
   290  // Deprecated: use GetInt64Var or GetReloadableInt64Var instead
   291  func RegisterInt64ConfigVariable(defaultValue int64, ptr *int64, isHotReloadable bool, valueScale int64, orderedKeys ...string) {
   292  	Default.RegisterInt64ConfigVariable(defaultValue, ptr, isHotReloadable, valueScale, orderedKeys...)
   293  }
   294  
   295  // GetInt64Var registers a not hot-reloadable int64 config variable
   296  //
   297  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   298  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   299  func GetInt64Var(defaultValue, valueScale int64, orderedKeys ...string) int64 {
   300  	return Default.GetInt64Var(defaultValue, valueScale, orderedKeys...)
   301  }
   302  
   303  // GetReloadableInt64Var registers a hot-reloadable int64 config variable
   304  //
   305  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   306  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   307  func GetReloadableInt64Var(defaultValue, valueScale int64, orderedKeys ...string) *Reloadable[int64] {
   308  	return Default.GetReloadableInt64Var(defaultValue, valueScale, orderedKeys...)
   309  }
   310  
   311  // RegisterInt64ConfigVariable registers int64 config variable
   312  //
   313  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   314  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   315  //
   316  // Deprecated: use GetInt64Var or GetReloadableInt64Var instead
   317  func (c *Config) RegisterInt64ConfigVariable(
   318  	defaultValue int64, ptr *int64, isHotReloadable bool, valueScale int64, orderedKeys ...string,
   319  ) {
   320  	c.registerInt64Var(defaultValue, ptr, isHotReloadable, valueScale, func(v int64) {
   321  		*ptr = v
   322  	}, orderedKeys...)
   323  }
   324  
   325  // GetInt64Var registers a not hot-reloadable int64 config variable
   326  //
   327  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   328  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   329  func (c *Config) GetInt64Var(defaultValue, valueScale int64, orderedKeys ...string) int64 {
   330  	var ret int64
   331  	c.registerInt64Var(defaultValue, nil, false, valueScale, func(v int64) {
   332  		ret = v
   333  	}, orderedKeys...)
   334  	return ret
   335  }
   336  
   337  // GetReloadableInt64Var registers a not hot-reloadable int64 config variable
   338  //
   339  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   340  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   341  func (c *Config) GetReloadableInt64Var(defaultValue, valueScale int64, orderedKeys ...string) *Reloadable[int64] {
   342  	ptr, exists := getOrCreatePointer(
   343  		c.reloadableVars, c.reloadableVarsMisuses, &c.reloadableVarsLock, defaultValue*valueScale, orderedKeys...,
   344  	)
   345  	if !exists {
   346  		c.registerInt64Var(defaultValue, ptr, true, valueScale, func(v int64) {
   347  			ptr.store(v)
   348  		}, orderedKeys...)
   349  	}
   350  	return ptr
   351  }
   352  
   353  func (c *Config) registerInt64Var(
   354  	defaultValue int64, ptr any, isHotReloadable bool, valueScale int64, store func(int64), orderedKeys ...string,
   355  ) {
   356  	configVar := configValue{
   357  		value:        ptr,
   358  		multiplier:   valueScale,
   359  		defaultValue: defaultValue,
   360  		keys:         orderedKeys,
   361  	}
   362  
   363  	if isHotReloadable {
   364  		c.hotReloadableConfigLock.Lock()
   365  		c.appendVarToConfigMaps(orderedKeys, &configVar)
   366  		c.hotReloadableConfigLock.Unlock()
   367  	}
   368  
   369  	for _, key := range orderedKeys {
   370  		c.bindEnv(key)
   371  		if c.IsSet(key) {
   372  			store(c.GetInt64(key, defaultValue) * valueScale)
   373  			return
   374  		}
   375  	}
   376  	store(defaultValue * valueScale)
   377  }
   378  
   379  // RegisterDurationConfigVariable registers duration config variable
   380  //
   381  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   382  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   383  //
   384  // Deprecated: use GetDurationVar or GetReloadableDurationVar instead
   385  func RegisterDurationConfigVariable(
   386  	defaultValueInTimescaleUnits int64, ptr *time.Duration, isHotReloadable bool, timeScale time.Duration, orderedKeys ...string,
   387  ) {
   388  	Default.RegisterDurationConfigVariable(defaultValueInTimescaleUnits, ptr, isHotReloadable, timeScale, orderedKeys...)
   389  }
   390  
   391  // GetDurationVar registers a not hot-reloadable duration config variable
   392  //
   393  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   394  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   395  func GetDurationVar(
   396  	defaultValueInTimescaleUnits int64, timeScale time.Duration, orderedKeys ...string,
   397  ) time.Duration {
   398  	return Default.GetDurationVar(defaultValueInTimescaleUnits, timeScale, orderedKeys...)
   399  }
   400  
   401  // GetReloadableDurationVar registers a not hot-reloadable duration config variable
   402  //
   403  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   404  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   405  func GetReloadableDurationVar(defaultValueInTimescaleUnits int64, timeScale time.Duration, orderedKeys ...string) *Reloadable[time.Duration] {
   406  	return Default.GetReloadableDurationVar(defaultValueInTimescaleUnits, timeScale, orderedKeys...)
   407  }
   408  
   409  // RegisterDurationConfigVariable registers duration config variable
   410  //
   411  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   412  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   413  //
   414  // Deprecated: use GetDurationVar or GetReloadableDurationVar instead
   415  func (c *Config) RegisterDurationConfigVariable(
   416  	defaultValueInTimescaleUnits int64, ptr *time.Duration, isHotReloadable bool, timeScale time.Duration, orderedKeys ...string,
   417  ) {
   418  	c.registerDurationVar(defaultValueInTimescaleUnits, ptr, isHotReloadable, timeScale, func(v time.Duration) {
   419  		*ptr = v
   420  	}, orderedKeys...)
   421  }
   422  
   423  // GetDurationVar registers a not hot-reloadable duration config variable
   424  //
   425  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   426  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   427  func (c *Config) GetDurationVar(
   428  	defaultValueInTimescaleUnits int64, timeScale time.Duration, orderedKeys ...string,
   429  ) time.Duration {
   430  	var ret time.Duration
   431  	c.registerDurationVar(defaultValueInTimescaleUnits, nil, false, timeScale, func(v time.Duration) {
   432  		ret = v
   433  	}, orderedKeys...)
   434  	return ret
   435  }
   436  
   437  // GetReloadableDurationVar registers a hot-reloadable duration config variable
   438  //
   439  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   440  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   441  func (c *Config) GetReloadableDurationVar(
   442  	defaultValueInTimescaleUnits int64, timeScale time.Duration, orderedKeys ...string,
   443  ) *Reloadable[time.Duration] {
   444  	ptr, exists := getOrCreatePointer(
   445  		c.reloadableVars, c.reloadableVarsMisuses, &c.reloadableVarsLock,
   446  		time.Duration(defaultValueInTimescaleUnits)*timeScale, orderedKeys...,
   447  	)
   448  	if !exists {
   449  		c.registerDurationVar(defaultValueInTimescaleUnits, ptr, true, timeScale, func(v time.Duration) {
   450  			ptr.store(v)
   451  		}, orderedKeys...)
   452  	}
   453  	return ptr
   454  }
   455  
   456  func (c *Config) registerDurationVar(
   457  	defaultValueInTimescaleUnits int64, ptr any, isHotReloadable bool, timeScale time.Duration,
   458  	store func(time.Duration), orderedKeys ...string,
   459  ) {
   460  	configVar := configValue{
   461  		value:        ptr,
   462  		multiplier:   timeScale,
   463  		defaultValue: defaultValueInTimescaleUnits,
   464  		keys:         orderedKeys,
   465  	}
   466  
   467  	if isHotReloadable {
   468  		c.hotReloadableConfigLock.Lock()
   469  		c.appendVarToConfigMaps(orderedKeys, &configVar)
   470  		c.hotReloadableConfigLock.Unlock()
   471  	}
   472  
   473  	for _, key := range orderedKeys {
   474  		if c.IsSet(key) {
   475  			store(c.GetDuration(key, defaultValueInTimescaleUnits, timeScale))
   476  			return
   477  		}
   478  	}
   479  	store(time.Duration(defaultValueInTimescaleUnits) * timeScale)
   480  }
   481  
   482  // RegisterStringConfigVariable registers string config variable
   483  //
   484  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   485  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   486  //
   487  // Deprecated: use GetStringVar or GetReloadableStringVar instead
   488  func RegisterStringConfigVariable(defaultValue string, ptr *string, isHotReloadable bool, orderedKeys ...string) {
   489  	Default.RegisterStringConfigVariable(defaultValue, ptr, isHotReloadable, orderedKeys...)
   490  }
   491  
   492  // GetStringVar registers a not hot-reloadable string config variable
   493  //
   494  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   495  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   496  func GetStringVar(defaultValue string, orderedKeys ...string) string {
   497  	return Default.GetStringVar(defaultValue, orderedKeys...)
   498  }
   499  
   500  // GetReloadableStringVar registers a hot-reloadable string config variable
   501  //
   502  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   503  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   504  func GetReloadableStringVar(defaultValue string, orderedKeys ...string) *Reloadable[string] {
   505  	return Default.GetReloadableStringVar(defaultValue, orderedKeys...)
   506  }
   507  
   508  // RegisterStringConfigVariable registers string config variable
   509  //
   510  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   511  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   512  //
   513  // Deprecated: use GetStringVar or GetReloadableStringVar instead
   514  func (c *Config) RegisterStringConfigVariable(
   515  	defaultValue string, ptr *string, isHotReloadable bool, orderedKeys ...string,
   516  ) {
   517  	c.registerStringVar(defaultValue, ptr, isHotReloadable, func(v string) {
   518  		*ptr = v
   519  	}, orderedKeys...)
   520  }
   521  
   522  // GetStringVar registers a not hot-reloadable string config variable
   523  //
   524  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   525  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   526  func (c *Config) GetStringVar(defaultValue string, orderedKeys ...string) string {
   527  	var ret string
   528  	c.registerStringVar(defaultValue, nil, false, func(v string) {
   529  		ret = v
   530  	}, orderedKeys...)
   531  	return ret
   532  }
   533  
   534  // GetReloadableStringVar registers a hot-reloadable string config variable
   535  //
   536  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   537  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   538  func (c *Config) GetReloadableStringVar(defaultValue string, orderedKeys ...string) *Reloadable[string] {
   539  	ptr, exists := getOrCreatePointer(
   540  		c.reloadableVars, c.reloadableVarsMisuses, &c.reloadableVarsLock, defaultValue, orderedKeys...,
   541  	)
   542  	if !exists {
   543  		c.registerStringVar(defaultValue, ptr, true, func(v string) {
   544  			ptr.store(v)
   545  		}, orderedKeys...)
   546  	}
   547  	return ptr
   548  }
   549  
   550  func (c *Config) registerStringVar(
   551  	defaultValue string, ptr any, isHotReloadable bool, store func(string), orderedKeys ...string,
   552  ) {
   553  	configVar := configValue{
   554  		value:        ptr,
   555  		defaultValue: defaultValue,
   556  		keys:         orderedKeys,
   557  	}
   558  
   559  	if isHotReloadable {
   560  		c.hotReloadableConfigLock.Lock()
   561  		c.appendVarToConfigMaps(orderedKeys, &configVar)
   562  		c.hotReloadableConfigLock.Unlock()
   563  	}
   564  
   565  	for _, key := range orderedKeys {
   566  		if c.IsSet(key) {
   567  			store(c.GetString(key, defaultValue))
   568  			return
   569  		}
   570  	}
   571  	store(defaultValue)
   572  }
   573  
   574  // RegisterStringSliceConfigVariable registers string slice config variable
   575  //
   576  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   577  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   578  //
   579  // Deprecated: use GetStringSliceVar or GetReloadableStringSliceVar instead
   580  func RegisterStringSliceConfigVariable(defaultValue []string, ptr *[]string, isHotReloadable bool, orderedKeys ...string) {
   581  	Default.RegisterStringSliceConfigVariable(defaultValue, ptr, isHotReloadable, orderedKeys...)
   582  }
   583  
   584  // GetStringSliceVar registers a not hot-reloadable string slice config variable
   585  //
   586  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   587  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   588  func GetStringSliceVar(defaultValue []string, orderedKeys ...string) []string {
   589  	return Default.GetStringSliceVar(defaultValue, orderedKeys...)
   590  }
   591  
   592  // GetReloadableStringSliceVar registers a hot-reloadable string slice config variable
   593  //
   594  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   595  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   596  func GetReloadableStringSliceVar(defaultValue []string, orderedKeys ...string) *Reloadable[[]string] {
   597  	return Default.GetReloadableStringSliceVar(defaultValue, orderedKeys...)
   598  }
   599  
   600  // RegisterStringSliceConfigVariable registers string slice config variable
   601  //
   602  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   603  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   604  //
   605  // Deprecated: use GetStringSliceVar or GetReloadableStringSliceVar instead
   606  func (c *Config) RegisterStringSliceConfigVariable(
   607  	defaultValue []string, ptr *[]string, isHotReloadable bool, orderedKeys ...string,
   608  ) {
   609  	c.registerStringSliceVar(defaultValue, ptr, isHotReloadable, func(v []string) {
   610  		*ptr = v
   611  	}, orderedKeys...)
   612  }
   613  
   614  // GetStringSliceVar registers a not hot-reloadable string slice config variable
   615  //
   616  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   617  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   618  func (c *Config) GetStringSliceVar(defaultValue []string, orderedKeys ...string) []string {
   619  	var ret []string
   620  	c.registerStringSliceVar(defaultValue, ret, false, func(v []string) {
   621  		ret = v
   622  	}, orderedKeys...)
   623  	return ret
   624  }
   625  
   626  // GetReloadableStringSliceVar registers a hot-reloadable string slice config variable
   627  //
   628  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   629  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   630  func (c *Config) GetReloadableStringSliceVar(defaultValue []string, orderedKeys ...string) *Reloadable[[]string] {
   631  	ptr, exists := getOrCreatePointer(
   632  		c.reloadableVars, c.reloadableVarsMisuses, &c.reloadableVarsLock, defaultValue, orderedKeys...,
   633  	)
   634  	if !exists {
   635  		c.registerStringSliceVar(defaultValue, ptr, true, func(v []string) {
   636  			ptr.store(v)
   637  		}, orderedKeys...)
   638  	}
   639  	return ptr
   640  }
   641  
   642  func (c *Config) registerStringSliceVar(
   643  	defaultValue []string, ptr any, isHotReloadable bool, store func([]string), orderedKeys ...string,
   644  ) {
   645  	configVar := configValue{
   646  		value:        ptr,
   647  		defaultValue: defaultValue,
   648  		keys:         orderedKeys,
   649  	}
   650  
   651  	if isHotReloadable {
   652  		c.hotReloadableConfigLock.Lock()
   653  		c.appendVarToConfigMaps(orderedKeys, &configVar)
   654  		c.hotReloadableConfigLock.Unlock()
   655  	}
   656  
   657  	for _, key := range orderedKeys {
   658  		if c.IsSet(key) {
   659  			store(c.GetStringSlice(key, defaultValue))
   660  			return
   661  		}
   662  	}
   663  	store(defaultValue)
   664  }
   665  
   666  // RegisterStringMapConfigVariable registers string map config variable
   667  //
   668  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   669  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   670  //
   671  // Deprecated: use GetStringMapVar or GetReloadableStringMapVar instead
   672  func RegisterStringMapConfigVariable(
   673  	defaultValue map[string]interface{}, ptr *map[string]interface{}, isHotReloadable bool, orderedKeys ...string,
   674  ) {
   675  	Default.RegisterStringMapConfigVariable(defaultValue, ptr, isHotReloadable, orderedKeys...)
   676  }
   677  
   678  // GetStringMapVar registers a not hot-reloadable string map config variable
   679  //
   680  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   681  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   682  func GetStringMapVar(defaultValue map[string]interface{}, orderedKeys ...string) map[string]interface{} {
   683  	return Default.GetStringMapVar(defaultValue, orderedKeys...)
   684  }
   685  
   686  // GetReloadableStringMapVar registers a hot-reloadable string map config variable
   687  //
   688  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   689  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   690  func GetReloadableStringMapVar(
   691  	defaultValue map[string]interface{}, orderedKeys ...string,
   692  ) *Reloadable[map[string]interface{}] {
   693  	return Default.GetReloadableStringMapVar(defaultValue, orderedKeys...)
   694  }
   695  
   696  // RegisterStringMapConfigVariable registers string map config variable
   697  //
   698  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   699  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   700  //
   701  // Deprecated: use GetStringMapVar or GetReloadableStringMapVar instead
   702  func (c *Config) RegisterStringMapConfigVariable(
   703  	defaultValue map[string]interface{}, ptr *map[string]interface{}, isHotReloadable bool, orderedKeys ...string,
   704  ) {
   705  	c.registerStringMapVar(defaultValue, ptr, isHotReloadable, func(v map[string]interface{}) {
   706  		*ptr = v
   707  	}, orderedKeys...)
   708  }
   709  
   710  // GetStringMapVar registers a not hot-reloadable string map config variable
   711  //
   712  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   713  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   714  func (c *Config) GetStringMapVar(
   715  	defaultValue map[string]interface{}, orderedKeys ...string,
   716  ) map[string]interface{} {
   717  	var ret map[string]interface{}
   718  	c.registerStringMapVar(defaultValue, nil, false, func(v map[string]interface{}) {
   719  		ret = v
   720  	}, orderedKeys...)
   721  	return ret
   722  }
   723  
   724  // GetReloadableStringMapVar registers a hot-reloadable string map config variable
   725  //
   726  // WARNING: keys are being looked up in requested order and the value of the first found key is returned,
   727  // e.g. asking for the same keys but in a different order can result in a different value to be returned
   728  func (c *Config) GetReloadableStringMapVar(
   729  	defaultValue map[string]interface{}, orderedKeys ...string,
   730  ) *Reloadable[map[string]interface{}] {
   731  	ptr, exists := getOrCreatePointer(
   732  		c.reloadableVars, c.reloadableVarsMisuses, &c.reloadableVarsLock, defaultValue, orderedKeys...,
   733  	)
   734  	if !exists {
   735  		c.registerStringMapVar(defaultValue, ptr, true, func(v map[string]interface{}) {
   736  			ptr.store(v)
   737  		}, orderedKeys...)
   738  	}
   739  	return ptr
   740  }
   741  
   742  func (c *Config) registerStringMapVar(
   743  	defaultValue map[string]interface{}, ptr any, isHotReloadable bool, store func(map[string]interface{}), orderedKeys ...string,
   744  ) {
   745  	configVar := configValue{
   746  		value:        ptr,
   747  		defaultValue: defaultValue,
   748  		keys:         orderedKeys,
   749  	}
   750  
   751  	if isHotReloadable {
   752  		c.hotReloadableConfigLock.Lock()
   753  		c.appendVarToConfigMaps(orderedKeys, &configVar)
   754  		c.hotReloadableConfigLock.Unlock()
   755  	}
   756  
   757  	for _, key := range orderedKeys {
   758  		if c.IsSet(key) {
   759  			store(c.GetStringMap(key, defaultValue))
   760  			return
   761  		}
   762  	}
   763  	store(defaultValue)
   764  }
   765  
   766  func (c *Config) appendVarToConfigMaps(keys []string, configVar *configValue) {
   767  	key := strings.Join(keys, ",")
   768  	if _, ok := c.hotReloadableConfig[key]; !ok {
   769  		c.hotReloadableConfig[key] = make([]*configValue, 0)
   770  	}
   771  	c.hotReloadableConfig[key] = append(c.hotReloadableConfig[key], configVar)
   772  }
   773  
   774  type configTypes interface {
   775  	int | int64 | string | time.Duration | bool | float64 | []string | map[string]interface{}
   776  }
   777  
   778  // Reloadable is used as a wrapper for hot-reloadable config variables
   779  type Reloadable[T configTypes] struct {
   780  	value T
   781  	lock  sync.RWMutex
   782  }
   783  
   784  // Load should be used to read the underlying value without worrying about data races
   785  func (a *Reloadable[T]) Load() T {
   786  	a.lock.RLock()
   787  	v := a.value
   788  	a.lock.RUnlock()
   789  	return v
   790  }
   791  
   792  func (a *Reloadable[T]) store(v T) {
   793  	a.lock.Lock()
   794  	a.value = v
   795  	a.lock.Unlock()
   796  }
   797  
   798  // swapIfNotEqual is used internally to swap the value of a hot-reloadable config variable
   799  // if the new value is not equal to the old value
   800  func (a *Reloadable[T]) swapIfNotEqual(new T, compare func(old, new T) bool) (old T, swapped bool) {
   801  	a.lock.Lock()
   802  	defer a.lock.Unlock()
   803  	if !compare(a.value, new) {
   804  		old := a.value
   805  		a.value = new
   806  		return old, true
   807  	}
   808  	return a.value, false
   809  }
   810  
   811  func compare[T comparable]() func(a, b T) bool {
   812  	return func(a, b T) bool {
   813  		return a == b
   814  	}
   815  }