code.gitea.io/gitea@v1.22.3/modules/setting/config/value.go (about) 1 // Copyright 2023 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package config 5 6 import ( 7 "context" 8 "sync" 9 10 "code.gitea.io/gitea/modules/json" 11 "code.gitea.io/gitea/modules/log" 12 "code.gitea.io/gitea/modules/util" 13 ) 14 15 type CfgSecKey struct { 16 Sec, Key string 17 } 18 19 type Value[T any] struct { 20 mu sync.RWMutex 21 22 cfgSecKey CfgSecKey 23 dynKey string 24 25 def, value T 26 revision int 27 } 28 29 func (value *Value[T]) parse(key, valStr string) (v T) { 30 v = value.def 31 if valStr != "" { 32 if err := json.Unmarshal(util.UnsafeStringToBytes(valStr), &v); err != nil { 33 log.Error("Unable to unmarshal json config for key %q, err: %v", key, err) 34 } 35 } 36 return v 37 } 38 39 func (value *Value[T]) Value(ctx context.Context) (v T) { 40 dg := GetDynGetter() 41 if dg == nil { 42 // this is an edge case: the database is not initialized but the system setting is going to be used 43 // it should panic to avoid inconsistent config values (from config / system setting) and fix the code 44 panic("no config dyn value getter") 45 } 46 47 rev := dg.GetRevision(ctx) 48 49 // if the revision in database doesn't change, use the last value 50 value.mu.RLock() 51 if rev == value.revision { 52 v = value.value 53 value.mu.RUnlock() 54 return v 55 } 56 value.mu.RUnlock() 57 58 // try to parse the config and cache it 59 var valStr *string 60 if dynVal, has := dg.GetValue(ctx, value.dynKey); has { 61 valStr = &dynVal 62 } else if cfgVal, has := GetCfgSecKeyGetter().GetValue(value.cfgSecKey.Sec, value.cfgSecKey.Key); has { 63 valStr = &cfgVal 64 } 65 if valStr == nil { 66 v = value.def 67 } else { 68 v = value.parse(value.dynKey, *valStr) 69 } 70 71 value.mu.Lock() 72 value.value = v 73 value.revision = rev 74 value.mu.Unlock() 75 return v 76 } 77 78 func (value *Value[T]) DynKey() string { 79 return value.dynKey 80 } 81 82 func (value *Value[T]) WithDefault(def T) *Value[T] { 83 value.def = def 84 return value 85 } 86 87 func (value *Value[T]) WithFileConfig(cfgSecKey CfgSecKey) *Value[T] { 88 value.cfgSecKey = cfgSecKey 89 return value 90 } 91 92 func ValueJSON[T any](dynKey string) *Value[T] { 93 return &Value[T]{dynKey: dynKey} 94 }