func GetKnownKeys() []string {
	keys := make([]string, 0, len(knownKeys))
	keysMutex.Lock()
	defer keysMutex.Unlock()
	for k := range knownKeys {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	return keys
}
GetKnownKeys gets the known keys
package config
import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"math"
	"net/http"
	"os"
	"reflect"
	"sort"
	"strings"
	"sync"
	"time"
	"github.com/hyperledger/firefly/internal/i18n"
	"github.com/hyperledger/firefly/internal/log"
	"github.com/hyperledger/firefly/pkg/fftypes"
	"github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	lumberjack "gopkg.in/natefinch/lumberjack.v2"
)
var (
	APIDefaultFilterLimit = rootKey("api.defaultFilterLimit")
	APIMaxFilterLimit = rootKey("api.maxFilterLimit")
	APIMaxFilterSkip = rootKey("api.maxFilterLimit")
	APIRequestTimeout = rootKey("api.requestTimeout")
	APIRequestMaxTimeout = rootKey("api.requestMaxTimeout")
	APIShutdownTimeout = rootKey("api.shutdownTimeout")
	BatchManagerReadPageSize = rootKey("batch.manager.readPageSize")
	BatchManagerReadPollTimeout = rootKey("batch.manager.pollTimeout")
	BatchRetryFactor = rootKey("batch.retry.factor")
	BatchRetryInitDelay = rootKey("batch.retry.initDelay")
	BatchRetryMaxDelay = rootKey("batch.retry.maxDelay")
	BlockchainType = rootKey("blockchain.type")
	BroadcastBatchAgentTimeout = rootKey("broadcast.batch.agentTimeout")
	BroadcastBatchSize = rootKey("broadcast.batch.size")
	BroadcastBatchTimeout = rootKey("broadcast.batch.timeout")
	PrivateMessagingBatchAgentTimeout = rootKey("privatemessaging.batch.agentTimeout")
	PrivateMessagingBatchSize = rootKey("privatemessaging.batch.size")
	PrivateMessagingBatchTimeout = rootKey("privatemessaging.batch.timeout")
	PrivateMessagingOpCorrelationRetries = rootKey("privatemessaging.opCorrelationRetries")
	PrivateMessagingRetryFactor = rootKey("privatemessaging.retry.factor")
	PrivateMessagingRetryInitDelay = rootKey("privatemessaging.retry.initDelay")
	PrivateMessagingRetryMaxDelay = rootKey("privatemessaging.retry.maxDelay")
	CorsAllowCredentials = rootKey("cors.credentials")
	CorsAllowedHeaders = rootKey("cors.headers")
	CorsAllowedMethods = rootKey("cors.methods")
	CorsAllowedOrigins = rootKey("cors.origins")
	CorsDebug = rootKey("cors.debug")
	CorsEnabled = rootKey("cors.enabled")
	CorsMaxAge = rootKey("cors.maxAge")
	DataexchangeType = rootKey("dataexchange.type")
	DatabaseType = rootKey("database.type")
	TokensList = rootKey("tokens")
	DebugPort = rootKey("debug.port")
	EventTransportsDefault = rootKey("event.transports.default")
	EventTransportsEnabled = rootKey("event.transports.enabled")
	EventAggregatorFirstEvent = rootKey("event.aggregator.firstEvent")
	EventAggregatorBatchSize = rootKey("event.aggregator.batchSize")
	EventAggregatorBatchTimeout = rootKey("event.aggregator.batchTimeout")
	EventAggregatorOpCorrelationRetries = rootKey("event.aggregator.opCorrelationRetries")
	EventAggregatorPollTimeout = rootKey("event.aggregator.pollTimeout")
	EventAggregatorRetryFactor = rootKey("event.aggregator.retry.factor")
	EventAggregatorRetryInitDelay = rootKey("event.aggregator.retry.initDelay")
	EventAggregatorRetryMaxDelay = rootKey("event.aggregator.retry.maxDelay")
	EventDispatcherPollTimeout = rootKey("event.dispatcher.pollTimeout")
	EventDispatcherBufferLength = rootKey("event.dispatcher.bufferLength")
	EventDispatcherBatchTimeout = rootKey("event.dispatcher.batchTimeout")
	EventDispatcherRetryFactor = rootKey("event.dispatcher.retry.factor")
	EventDispatcherRetryInitDelay = rootKey("event.dispatcher.retry.initDelay")
	EventDispatcherRetryMaxDelay = rootKey("event.dispatcher.retry.maxDelay")
	EventDBEventsBufferSize = rootKey("event.dbevents.bufferSize")
	GroupCacheSize = rootKey("group.cache.size")
	GroupCacheTTL = rootKey("group.cache.ttl")
	AdminEnabled = rootKey("admin.enabled")
	AdminPreinit = rootKey("admin.preinit")
	IdentityType = rootKey("identity.type")
	IdentityManagerCacheTTL = rootKey("identity.manager.cache.ttl")
	IdentityManagerCacheLimit = rootKey("identity.manager.cache.limit")
	Lang = rootKey("lang")
	LogForceColor = rootKey("log.forceColor")
	LogLevel = rootKey("log.level")
	LogNoColor = rootKey("log.noColor")
	LogTimeFormat = rootKey("log.timeFormat")
	LogUTC = rootKey("log.utc")
	LogFilename = rootKey("log.filename")
	LogFilesize = rootKey("log.filesize")
	LogMaxBackups = rootKey("log.maxBackups")
	LogMaxAge = rootKey("log.maxAge")
	LogCompress = rootKey("log.compress")
	NamespacesDefault = rootKey("namespaces.default")
	NamespacesPredefined = rootKey("namespaces.predefined")
	NodeName = rootKey("node.name")
	NodeDescription = rootKey("node.description")
	OrgName = rootKey("org.name")
	OrgIdentityDeprecated = rootKey("org.identity")
	OrgKey = rootKey("org.key")
	OrgDescription = rootKey("org.description")
	OrchestratorStartupAttempts = rootKey("orchestrator.startupAttempts")
	PublicStorageType = rootKey("publicstorage.type")
	SubscriptionDefaultsReadAhead = rootKey("subscription.defaults.batchSize")
	SubscriptionMax = rootKey("subscription.max")
	SubscriptionsRetryInitialDelay = rootKey("subscription.retry.initDelay")
	SubscriptionsRetryMaxDelay = rootKey("subscription.retry.maxDelay")
	SubscriptionsRetryFactor = rootKey("subscription.retry.factor")
	AssetManagerRetryInitialDelay = rootKey("asset.manager.retry.initDelay")
	AssetManagerRetryMaxDelay = rootKey("asset.manager.retry.maxDelay")
	AssetManagerRetryFactor = rootKey("asset.manager.retry.factor")
	UIEnabled = rootKey("ui.enabled")
	UIPath = rootKey("ui.path")
	ValidatorCacheSize = rootKey("validator.cache.size")
	ValidatorCacheTTL = rootKey("validator.cache.ttl")
)
type KeySet interface {
	AddKnownKey(key string, defValue ...interface{})
}
type Prefix interface {
	KeySet
	SetDefault(key string, defValue interface{})
	SubPrefix(suffix string) Prefix
	Array() PrefixArray
	Set(key string, value interface{})
	Resolve(key string) string
	GetString(key string) string
	GetBool(key string) bool
	GetInt(key string) int
	GetInt64(key string) int64
	GetByteSize(key string) int64
	GetUint(key string) uint
	GetDuration(key string) time.Duration
	GetStringSlice(key string) []string
	GetObject(key string) fftypes.JSONObject
	GetObjectArray(key string) fftypes.JSONObjectArray
	Get(key string) interface{}
}
type PrefixArray interface {
	KeySet
	ArraySize() int
	ArrayEntry(i int) Prefix
}
type RootKey string
func Reset() {
	viper.Reset()
	viper.SetDefault(string(APIDefaultFilterLimit), 25)
	viper.SetDefault(string(APIRequestTimeout), "120s")
	viper.SetDefault(string(APIRequestMaxTimeout), "10m")
	viper.SetDefault(string(APIMaxFilterLimit), 250)
	viper.SetDefault(string(APIMaxFilterSkip), 1000)  
	viper.SetDefault(string(APIRequestTimeout), "120s")
	viper.SetDefault(string(APIShutdownTimeout), "10s")
	viper.SetDefault(string(BatchManagerReadPageSize), 100)
	viper.SetDefault(string(BatchManagerReadPollTimeout), "30s")
	viper.SetDefault(string(BatchRetryFactor), 2.0)
	viper.SetDefault(string(BatchRetryFactor), 2.0)
	viper.SetDefault(string(BatchRetryInitDelay), "250ms")
	viper.SetDefault(string(BatchRetryInitDelay), "250ms")
	viper.SetDefault(string(BatchRetryMaxDelay), "30s")
	viper.SetDefault(string(BatchRetryMaxDelay), "30s")
	viper.SetDefault(string(BroadcastBatchAgentTimeout), "2m")
	viper.SetDefault(string(BroadcastBatchSize), 200)
	viper.SetDefault(string(BroadcastBatchTimeout), "1s")
	viper.SetDefault(string(CorsAllowCredentials), true)
	viper.SetDefault(string(CorsAllowedHeaders), []string{"*"})
	viper.SetDefault(string(CorsAllowedMethods), []string{http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete})
	viper.SetDefault(string(CorsAllowedOrigins), []string{"*"})
	viper.SetDefault(string(CorsEnabled), true)
	viper.SetDefault(string(CorsMaxAge), 600)
	viper.SetDefault(string(DataexchangeType), "https")
	viper.SetDefault(string(DebugPort), -1)
	viper.SetDefault(string(EventAggregatorFirstEvent), fftypes.SubOptsFirstEventOldest)
	viper.SetDefault(string(EventAggregatorBatchSize), 50)
	viper.SetDefault(string(EventAggregatorBatchTimeout), "250ms")
	viper.SetDefault(string(EventAggregatorPollTimeout), "30s")
	viper.SetDefault(string(EventAggregatorRetryFactor), 2.0)
	viper.SetDefault(string(EventAggregatorRetryInitDelay), "100ms")
	viper.SetDefault(string(EventAggregatorRetryMaxDelay), "30s")
	viper.SetDefault(string(EventAggregatorOpCorrelationRetries), 3)
	viper.SetDefault(string(EventDBEventsBufferSize), 100)
	viper.SetDefault(string(EventDispatcherBufferLength), 5)
	viper.SetDefault(string(EventDispatcherBatchTimeout), "0")
	viper.SetDefault(string(EventDispatcherPollTimeout), "30s")
	viper.SetDefault(string(EventTransportsEnabled), []string{"websockets", "webhooks"})
	viper.SetDefault(string(EventTransportsDefault), "websockets")
	viper.SetDefault(string(GroupCacheSize), "1Mb")
	viper.SetDefault(string(GroupCacheTTL), "1h")
	viper.SetDefault(string(AdminEnabled), false)
	viper.SetDefault(string(IdentityType), "onchain")
	viper.SetDefault(string(Lang), "en")
	viper.SetDefault(string(LogLevel), "info")
	viper.SetDefault(string(LogTimeFormat), "2006-01-02T15:04:05.000Z07:00")
	viper.SetDefault(string(LogUTC), false)
	viper.SetDefault(string(LogFilesize), "100m")
	viper.SetDefault(string(LogMaxAge), "24h")
	viper.SetDefault(string(LogMaxBackups), 2)
	viper.SetDefault(string(NamespacesDefault), "default")
	viper.SetDefault(string(NamespacesPredefined), fftypes.JSONObjectArray{{"name": "default", "description": "Default predefined namespace"}})
	viper.SetDefault(string(OrchestratorStartupAttempts), 5)
	viper.SetDefault(string(PrivateMessagingRetryFactor), 2.0)
	viper.SetDefault(string(PrivateMessagingRetryInitDelay), "100ms")
	viper.SetDefault(string(PrivateMessagingRetryMaxDelay), "30s")
	viper.SetDefault(string(PrivateMessagingOpCorrelationRetries), 3)
	viper.SetDefault(string(PrivateMessagingBatchAgentTimeout), "2m")
	viper.SetDefault(string(PrivateMessagingBatchSize), 200)
	viper.SetDefault(string(PrivateMessagingBatchTimeout), "1s")
	viper.SetDefault(string(SubscriptionDefaultsReadAhead), 0)
	viper.SetDefault(string(SubscriptionMax), 500)
	viper.SetDefault(string(SubscriptionsRetryInitialDelay), "250ms")
	viper.SetDefault(string(SubscriptionsRetryMaxDelay), "30s")
	viper.SetDefault(string(SubscriptionsRetryFactor), 2.0)
	viper.SetDefault(string(AssetManagerRetryInitialDelay), "250ms")
	viper.SetDefault(string(AssetManagerRetryMaxDelay), "30s")
	viper.SetDefault(string(AssetManagerRetryFactor), 2.0)
	viper.SetDefault(string(UIEnabled), true)
	viper.SetDefault(string(ValidatorCacheSize), "1Mb")
	viper.SetDefault(string(ValidatorCacheTTL), "1h")
	viper.SetDefault(string(IdentityManagerCacheLimit), 100  )
	viper.SetDefault(string(IdentityManagerCacheTTL), "1h")
	i18n.SetLang(GetString(Lang))
}
func ReadConfig(cfgFile string) error {
	viper.SetEnvPrefix("firefly")
	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
	viper.AutomaticEnv()
	viper.SetConfigType("yaml")
	if cfgFile != "" {
		f, err := os.Open(cfgFile)
		if err == nil {
			defer f.Close()
			err = viper.ReadConfig(f)
		}
		return err
	}
	viper.SetConfigName("firefly.core")
	viper.AddConfigPath("/etc/firefly/")
	viper.AddConfigPath("$HOME/.firefly")
	viper.AddConfigPath(".")
	return viper.ReadInConfig()
}
func MergeConfig(configRecords []*fftypes.ConfigRecord) error {
	for _, c := range configRecords {
		s := viper.New()
		s.SetConfigType("json")
		var val interface{}
		if err := json.Unmarshal(c.Value, &val); err != nil {
			return err
		}
		switch val.(type) {
		case map[string]interface{}:
			_ = s.ReadConfig(bytes.NewBuffer(c.Value))
			for _, k := range s.AllKeys() {
				viper.Set(fmt.Sprintf("%s.%s", c.Key, k), s.Get(k))
			}
		default:
			viper.Set(c.Key, val)
		}
	}
	return nil
}
var knownKeys = map[string]bool{}  
var keysMutex sync.Mutex
var root = &configPrefix{}
func rootKey(k string) RootKey {
	root.AddKnownKey(k)
	return RootKey(k)
}