aboutsummaryrefslogtreecommitdiff
path: root/src/gnunet/config/config.go
blob: 1a5394101615a0f2204c45f98eefb5544ee1f3d4 (plain) (blame)
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
145
146
147
148
149
150
151
152
153
154
155
156
package config

import (
	"encoding/json"
	"io/ioutil"
	"reflect"
	"regexp"
	"strings"

	"github.com/bfix/gospel/crypto/ed25519"
	"github.com/bfix/gospel/logger"
	"gnunet/util"
)

///////////////////////////////////////////////////////////////////////
// GNS configuration

// GNSConfig
type GNSConfig struct {
	Endpoint     string            `json:"endpoint"`     // end-point of GNS service
	DHTReplLevel int               `json:"dhtReplLevel"` // DHT replication level
	RootZones    map[string]string `json:"rootZones"`    // pre-configured root zones
}

// GetRootZoneKey returns the zone key (PKEY) for a pre-configured root with given name.
func (gns *GNSConfig) GetRootZoneKey(name string) *ed25519.PublicKey {
	// lookup key in the dictionary
	if dStr, ok := gns.RootZones[name]; ok {
		if data, err := util.DecodeStringToBinary(dStr, 32); err == nil {
			return ed25519.NewPublicKeyFromBytes(data)
		}
	}
	// no pkey found.
	return nil
}

///////////////////////////////////////////////////////////////////////
// DHT configuration

// DHTConfig
type DHTConfig struct {
	Endpoint string `json:"endpoint"` // end-point of DHT service
}

///////////////////////////////////////////////////////////////////////
// Namecache configuration

// NamecacheConfig
type NamecacheConfig struct {
	Endpoint string `json:"endpoint"` // end-point of Namecache service
}

///////////////////////////////////////////////////////////////////////

// Environment settings
type Environ map[string]string

// Config is the aggregated configuration for GNUnet.
type Config struct {
	Env       Environ          `json:"environ"`
	DHT       *DHTConfig       `json:"dht"`
	GNS       *GNSConfig       `json:"gns"`
	Namecache *NamecacheConfig `json:"namecache"`
}

var (
	Cfg *Config
)

// Parse a JSON-encoded configuration file map it to the Config data structure.
func ParseConfig(fileName string) (err error) {
	// parse configuration file
	file, err := ioutil.ReadFile(fileName)
	if err != nil {
		return
	}
	// unmarshal to Config data structure
	Cfg = new(Config)
	if err = json.Unmarshal(file, Cfg); err == nil {
		// process all string-based config settings and apply
		// string substitutions.
		applySubstitutions(Cfg, Cfg.Env)
	}
	return
}

var (
	rx = regexp.MustCompile("\\$\\{([^\\}]*)\\}")
)

func substString(s string, env map[string]string) string {
	matches := rx.FindAllStringSubmatch(s, -1)
	for _, m := range matches {
		if len(m[1]) != 0 {
			subst, ok := env[m[1]]
			if !ok {
				continue
			}
			s = strings.Replace(s, "${"+m[1]+"}", subst, -1)
		}
	}
	return s
}

// applySubstitutions
func applySubstitutions(x interface{}, env map[string]string) {

	var process func(v reflect.Value)
	process = func(v reflect.Value) {
		for i := 0; i < v.NumField(); i++ {
			fld := v.Field(i)
			if fld.CanSet() {
				switch fld.Kind() {
				case reflect.String:
					// check for substitution
					s := fld.Interface().(string)
					for {
						s1 := substString(s, env)
						if s1 == s {
							break
						}
						logger.Printf(logger.DBG, "[config] %s --> %s\n", s, s1)
						fld.SetString(s1)
						s = s1
					}

				case reflect.Struct:
					// handle nested struct
					process(fld)

				case reflect.Ptr:
					// handle pointer
					e := fld.Elem()
					if e.IsValid() {
						process(fld.Elem())
					} else {
						logger.Printf(logger.ERROR, "[config] 'nil' pointer encountered")
					}
				}
			}
		}
	}

	v := reflect.ValueOf(x)
	switch v.Kind() {
	case reflect.Ptr:
		e := v.Elem()
		if e.IsValid() {
			process(e)
		} else {
			logger.Printf(logger.ERROR, "[config] 'nil' pointer encountered")
		}
	case reflect.Struct:
		process(v)
	}
}