94 lines · 2.0 KB · Go
RawDownload
// 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}}