-
Notifications
You must be signed in to change notification settings - Fork 37
/
config.go
144 lines (129 loc) · 3.76 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package config
import (
"fmt"
"math/big"
"reflect"
"strings"
"gopkg.in/yaml.v3"
)
// TenConfig is the top-level configuration struct for all TEN services.
// Fields are organised hierarchically, not all fields and structures will be used by all services.
//
// The default config is defined in yaml files formatted hierarchically like:
// ```
// network:
//
// chainId: 1234
// l1Contracts:
// managementContract: "0x1234567890abcdef1234567890abcdef12345678"
// ...
//
// node:
//
// nodeType: "validator"
// ...
//
// ```
// The config can be overridden by other yaml files formatted the same.
// But fields can also be overridden directly per yaml spec, e.g.:
// ```
// network.chainId: 5678
// node.nodeType: "sequencer"
// ```
//
// Fields can also be overridden by environment variables, with the key being the flattened path of the field, like:
// ```
// export NETWORK_CHAINID=5678
// export NODE_NODETYPE=sequencer
// ```
// For ease of reading only the top-level struct is defined in this file, the nested structs are defined in their own files.
type TenConfig struct {
Network *NetworkConfig `mapstructure:"network"`
Node *NodeConfig `mapstructure:"node"`
Host *HostConfig `mapstructure:"host"`
Enclave *EnclaveConfig `mapstructure:"enclave"`
}
//
// Note: Just TenConfig utility functions below here.
// All the top-level nested config structs are defined in their own files.
//
func (t *TenConfig) PrettyPrint() {
output, err := yaml.Marshal(t)
if err != nil {
fmt.Printf("Error printing config as YAML: %v\n", err)
return
}
fmt.Println(string(output))
}
// ToEnvironmentVariables converts the config structure into environment variables map
func (t *TenConfig) ToEnvironmentVariables() map[string]string {
return structToEnvMap("", t)
}
// ToEnvironmentVariablesRecursive recursively converts the config structure into environment variables map
func structToEnvMap(prefix string, cfg interface{}) map[string]string {
envMap := make(map[string]string)
value := reflect.ValueOf(cfg)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
if value.Kind() != reflect.Struct {
return envMap
}
valType := value.Type()
for i := 0; i < value.NumField(); i++ {
field := value.Field(i)
fieldType := valType.Field(i)
mapKey := fieldType.Tag.Get("mapstructure")
if mapKey == "" {
mapKey = fieldType.Name
}
// Convert mapstructure key to uppercase with underscores
envKey := strings.ToUpper(mapKey)
if prefix != "" {
envKey = prefix + "_" + envKey
}
// Handle *big.Int explicitly before the switch
if field.Type() == reflect.TypeOf(new(big.Int)) {
if !field.IsNil() {
envMap[envKey] = field.Interface().(*big.Int).String()
}
continue
} else if field.Type() == reflect.TypeOf(big.Int{}) {
ptrBigInt := field.Addr().Interface().(*big.Int)
envMap[envKey] = ptrBigInt.String()
continue
}
switch field.Kind() {
case reflect.Struct:
// Recursively handle nested structures
nestedMap := structToEnvMap(envKey, field.Interface())
for k, v := range nestedMap {
envMap[k] = v
}
case reflect.Slice:
// Handle string slices as comma-separated strings
if field.Type().Elem().Kind() == reflect.String {
strSlice := field.Interface().([]string)
envMap[envKey] = strings.Join(strSlice, ",")
} else {
// Handle other slice types, if needed
envMap[envKey] = fmt.Sprintf("%v", field.Interface())
}
case reflect.Ptr:
if !field.IsNil() {
// Handle pointer types
nestedMap := structToEnvMap(envKey, field.Interface())
for k, v := range nestedMap {
envMap[k] = v
}
}
default:
// Handle basic types
if !field.CanInterface() {
fmt.Println("Field cannot be interfaced:", prefix, envKey)
}
envMap[envKey] = fmt.Sprintf("%v", field.Interface())
}
}
return envMap
}