1/*
2   Package config is a simple tool to handle key-value config, like Redis's configuration:
3
4       # commet
5       key = value
6
7*/
8package config
9
10import (
11	"errors"
12	"fmt"
13	"strconv"
14	"strings"
15)
16
17var (
18	ErrNil = errors.New("nil value")
19)
20
21type Config struct {
22	Values map[string]string
23}
24
25func NewConfig() *Config {
26	c := &Config{}
27	c.Values = make(map[string]string)
28	return c
29}
30
31/*
32   bool: true, false, 0, 1, or ""
33*/
34func (c *Config) GetBool(key string) (bool, error) {
35	v, err := c.GetString(key)
36	if err != nil {
37		return false, err
38	}
39
40	v = strings.ToLower(v)
41	switch v {
42	case "true", "1":
43		return true, nil
44	case "false", "0", "":
45		return false, nil
46	default:
47		return false, fmt.Errorf("invalid bool format %s", v)
48	}
49}
50
51/*
52   int may be pure number or below format:
53
54       # 1k => 1000 bytes
55       # 1kb => 1024 bytes
56       # 1m => 1000000 bytes
57       # 1mb => 1024*1024 bytes
58       # 1g => 1000000000 bytes
59       # 1gb => 1024*1024*1024 bytes
60
61*/
62func (c *Config) GetInt64(key string) (int64, error) {
63	v, err := c.GetString(key)
64	if err != nil {
65		return 0, err
66	}
67
68	if len(v) == 0 {
69		return 0, ErrNil
70	}
71
72	var scale int64 = 1
73	v = strings.ToLower(v)
74
75	var b bool = false
76	if v[len(v)-1] == 'b' {
77		v = v[0 : len(v)-1]
78		b = true
79	}
80
81	if len(v) == 0 {
82		return 0, fmt.Errorf("invalid number format %s", v)
83	}
84
85	switch v[len(v)-1] {
86	case 'k':
87		v = v[0 : len(v)-1]
88		if b {
89			scale = 1024
90		} else {
91			scale = 1000
92		}
93		break
94	case 'm':
95		v = v[0 : len(v)-1]
96		if b {
97			scale = 1024 * 1024
98		} else {
99			scale = 1000 * 1000
100		}
101	case 'g':
102		v = v[0 : len(v)-1]
103		if b {
104			scale = 1024 * 1024 * 1024
105		} else {
106			scale = 1000 * 1000 * 1000
107		}
108	}
109
110	var n int64
111	n, err = strconv.ParseInt(v, 10, 64)
112	if err != nil {
113		return 0, err
114	}
115
116	return n * scale, nil
117}
118
119func (c *Config) GetUint64(key string) (uint64, error) {
120	v, err := c.GetInt64(key)
121	if v < 0 {
122		return 0, fmt.Errorf("negative number %d", v)
123	}
124	return uint64(v), err
125}
126
127func (c *Config) GetInt(key string) (int, error) {
128	v, err := c.GetInt64(key)
129	return int(v), err
130}
131
132func (c *Config) GetString(key string) (string, error) {
133	v, ok := c.Values[key]
134	if !ok {
135		return "", ErrNil
136	} else {
137		return v, nil
138	}
139}
140
141func (c *Config) SetString(key string, value string) {
142	c.Values[key] = value
143}
144
145func (c *Config) SetInt64(key string, n int64) {
146	c.Values[key] = strconv.FormatInt(n, 10)
147}
148
149func (c *Config) SetUint64(key string, n uint64) {
150	c.Values[key] = strconv.FormatUint(n, 10)
151}
152
153func (c *Config) SetInt(key string, n int) {
154	c.SetInt64(key, int64(n))
155}
156
157func (c *Config) SetBool(key string, v bool) {
158	if v {
159		c.Values[key] = "true"
160	} else {
161		c.Values[key] = "false"
162	}
163}
164