aboutsummaryrefslogtreecommitdiffstats
path: root/modules/setting/config/value.go
diff options
context:
space:
mode:
Diffstat (limited to 'modules/setting/config/value.go')
-rw-r--r--modules/setting/config/value.go81
1 files changed, 81 insertions, 0 deletions
diff --git a/modules/setting/config/value.go b/modules/setting/config/value.go
new file mode 100644
index 0000000000..817fcdb786
--- /dev/null
+++ b/modules/setting/config/value.go
@@ -0,0 +1,81 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package config
+
+import (
+ "context"
+ "strconv"
+ "sync"
+)
+
+type CfgSecKey struct {
+ Sec, Key string
+}
+
+type Value[T any] struct {
+ mu sync.RWMutex
+
+ cfgSecKey CfgSecKey
+ dynKey string
+
+ def, value T
+ revision int
+}
+
+func (value *Value[T]) parse(s string) (v T) {
+ switch any(v).(type) {
+ case bool:
+ b, _ := strconv.ParseBool(s)
+ return any(b).(T)
+ default:
+ panic("unsupported config type, please complete the code")
+ }
+}
+
+func (value *Value[T]) Value(ctx context.Context) (v T) {
+ dg := GetDynGetter()
+ if dg == nil {
+ // this is an edge case: the database is not initialized but the system setting is going to be used
+ // it should panic to avoid inconsistent config values (from config / system setting) and fix the code
+ panic("no config dyn value getter")
+ }
+
+ rev := dg.GetRevision(ctx)
+
+ // if the revision in database doesn't change, use the last value
+ value.mu.RLock()
+ if rev == value.revision {
+ v = value.value
+ value.mu.RUnlock()
+ return v
+ }
+ value.mu.RUnlock()
+
+ // try to parse the config and cache it
+ var valStr *string
+ if dynVal, has := dg.GetValue(ctx, value.dynKey); has {
+ valStr = &dynVal
+ } else if cfgVal, has := GetCfgSecKeyGetter().GetValue(value.cfgSecKey.Sec, value.cfgSecKey.Key); has {
+ valStr = &cfgVal
+ }
+ if valStr == nil {
+ v = value.def
+ } else {
+ v = value.parse(*valStr)
+ }
+
+ value.mu.Lock()
+ value.value = v
+ value.revision = rev
+ value.mu.Unlock()
+ return v
+}
+
+func (value *Value[T]) DynKey() string {
+ return value.dynKey
+}
+
+func Bool(def bool, cfgSecKey CfgSecKey, dynKey string) *Value[bool] {
+ return &Value[bool]{def: def, cfgSecKey: cfgSecKey, dynKey: dynKey}
+}