// Copyright 2023 The Gitea Authors. All rights reserved.// SPDX-License-Identifier: MITpackage configimport ( "context" "sync" "forgejo.org/modules/json" "forgejo.org/modules/log" "forgejo.org/modules/util")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(key, valStr string) (v T) { v = value.def if valStr != "" { if err := json.Unmarshal(util.UnsafeStringToBytes(valStr), &v); err != nil { log.Error("Unable to unmarshal json config for key %q, err: %v", key, err) } } return v}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(value.dynKey, *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 (value *Value[T]) WithDefault(def T) *Value[T] { value.def = def return value}func (value *Value[T]) WithFileConfig(cfgSecKey CfgSecKey) *Value[T] { value.cfgSecKey = cfgSecKey return value}func ValueJSON[T any](dynKey string) *Value[T] { return &Value[T]{dynKey: dynKey}}
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package config
import (
"context"
"sync"
"forgejo.org/modules/json"
"forgejo.org/modules/log"
"forgejo.org/modules/util"
)
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(key, valStr string) (v T) {
v = value.def
if valStr != "" {
if err := json.Unmarshal(util.UnsafeStringToBytes(valStr), &v); err != nil {
log.Error("Unable to unmarshal json config for key %q, err: %v", key, err)
}
}
return v
}
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(value.dynKey, *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 (value *Value[T]) WithDefault(def T) *Value[T] {
value.def = def
return value
}
func (value *Value[T]) WithFileConfig(cfgSecKey CfgSecKey) *Value[T] {
value.cfgSecKey = cfgSecKey
return value
}
func ValueJSON[T any](dynKey string) *Value[T] {
return &Value[T]{dynKey: dynKey}
}