forked from forgejo/forgejo
Backport #27000 by @wxiaoguang
This PR reduces the complexity of the system setting system.
It only needs one line to introduce a new option, and the option can be
used anywhere out-of-box.
It is still high-performant (and more performant) because the config
values are cached in the config system.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
a9d547f55b
commit
aaf35ee49c
21 changed files with 429 additions and 525 deletions
81
modules/setting/config/value.go
Normal file
81
modules/setting/config/value.go
Normal file
|
@ -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}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue