Files
redis-go/config/config.go
2025-05-05 18:26:10 +08:00

164 lines
4.1 KiB
Go

package config
import (
"bufio"
"io"
"os"
"path/filepath"
"reflect"
"strconv"
"strings"
"time"
"github.com/hdt3213/godis/lib/utils"
"github.com/hdt3213/godis/lib/logger"
)
var (
ClusterMode = "cluster"
StandaloneMode = "standalone"
)
// ServerProperties defines global config properties
type ServerProperties struct {
// for Public configuration
RunID string `cfg:"runid"` // runID always different at every exec.
Bind string `cfg:"bind"`
Port int `cfg:"port"`
Dir string `cfg:"dir"`
AnnounceHost string `cfg:"announce-host"`
AppendOnly bool `cfg:"appendonly"`
AppendFilename string `cfg:"appendfilename"`
AppendFsync string `cfg:"appendfsync"`
AofUseRdbPreamble bool `cfg:"aof-use-rdb-preamble"`
MaxClients int `cfg:"maxclients"`
RequirePass string `cfg:"requirepass"`
Databases int `cfg:"databases"`
RDBFilename string `cfg:"dbfilename"`
MasterAuth string `cfg:"masterauth"`
SlaveAnnouncePort int `cfg:"slave-announce-port"`
SlaveAnnounceIP string `cfg:"slave-announce-ip"`
ReplTimeout int `cfg:"repl-timeout"`
ClusterEnable bool `cfg:"cluster-enable"`
ClusterAsSeed bool `cfg:"cluster-as-seed"`
ClusterSeed string `cfg:"cluster-seed"`
RaftListenAddr string `cfg:"raft-listen-address"`
RaftAdvertiseAddr string `cfg:"raft-advertise-address"`
MasterInCluster string `cfg:"master-in-cluster"`
// config file path
CfPath string `cfg:"cf,omitempty"`
}
type ServerInfo struct {
StartUpTime time.Time
}
func (p *ServerProperties) AnnounceAddress() string {
if p.AnnounceHost != "" {
return p.AnnounceHost + ":" + strconv.Itoa(p.Port)
}
return p.Bind + ":" + strconv.Itoa(p.Port)
}
// Properties holds global config properties
var Properties *ServerProperties
var EachTimeServerInfo *ServerInfo
func init() {
// A few stats we don't want to reset: server startup time, and peak mem.
EachTimeServerInfo = &ServerInfo{
StartUpTime: time.Now(),
}
// default config
Properties = &ServerProperties{
Bind: "127.0.0.1",
Port: 6379,
AppendOnly: false,
RunID: utils.RandString(40),
}
}
func parse(src io.Reader) *ServerProperties {
config := &ServerProperties{}
// read config file
rawMap := make(map[string]string)
scanner := bufio.NewScanner(src)
for scanner.Scan() {
line := scanner.Text()
if len(line) > 0 && strings.TrimLeft(line, " ")[0] == '#' {
continue
}
pivot := strings.IndexAny(line, " ")
if pivot > 0 && pivot < len(line)-1 { // separator found
key := line[0:pivot]
value := strings.Trim(line[pivot+1:], " ")
rawMap[strings.ToLower(key)] = value
}
}
if err := scanner.Err(); err != nil {
logger.Fatal(err)
}
// parse format
t := reflect.TypeOf(config)
v := reflect.ValueOf(config)
n := t.Elem().NumField()
for i := 0; i < n; i++ {
field := t.Elem().Field(i)
fieldVal := v.Elem().Field(i)
key, ok := field.Tag.Lookup("cfg")
if !ok || strings.TrimLeft(key, " ") == "" {
key = field.Name
}
value, ok := rawMap[strings.ToLower(key)]
if ok {
// fill config
switch field.Type.Kind() {
case reflect.String:
fieldVal.SetString(value)
case reflect.Int:
intValue, err := strconv.ParseInt(value, 10, 64)
if err == nil {
fieldVal.SetInt(intValue)
}
case reflect.Bool:
boolValue := "yes" == value
fieldVal.SetBool(boolValue)
case reflect.Slice:
if field.Type.Elem().Kind() == reflect.String {
slice := strings.Split(value, ",")
fieldVal.Set(reflect.ValueOf(slice))
}
}
}
}
return config
}
// SetupConfig read config file and store properties into Properties
func SetupConfig(configFilename string) {
file, err := os.Open(configFilename)
if err != nil {
panic(err)
}
defer file.Close()
Properties = parse(file)
Properties.RunID = utils.RandString(40)
configFilePath, err := filepath.Abs(configFilename)
if err != nil {
return
}
Properties.CfPath = configFilePath
if Properties.Dir == "" {
Properties.Dir = "."
}
}
func GetTmpDir() string {
return Properties.Dir + "/tmp"
}