package config import ( "bufio" "io" "os" "reflect" "strconv" "strings" "github.com/runningwater/go-redis/lib/logger" ) // ServerProperties 定义了服务器的全局配置属性 type ServerProperties struct { // Bind 服务器绑定的IP地址 Bind string `cfg:"bind"` // Port 服务器监听的端口号 Port int `cfg:"port"` // AppendOnly 是否启用AOF持久化模式 AppendOnly bool `cfg:"appendOnly"` // AppendFilename AOF文件名 AppendFilename string `cfg:"appendFilename"` // AppendFsyncInterval AOF文件同步间隔 AppendFsyncInterval int `cfg:"appendFsyncInterval"` // MaxClients 最大客户端连接数 MaxClients int `cfg:"maxclients"` // RequirePass 访问服务器所需的密码 RequirePass string `cfg:"requirepass"` // Databases 数据库数量 Databases int `cfg:"databases"` // Peers 集群中其他节点地址列表 Peers []string `cfg:"peers"` // Self 当前节点在集群中的地址 Self string `cfg:"self"` } // Properties 持有全局配置属性的实例 var Properties *ServerProperties func init() { // 默认配置 Properties = &ServerProperties{ Bind: "127.0.0.1", Port: 6379, AppendOnly: false, } } // parse 解析配置文件,将配置项映射到ServerProperties结构体中 func parse(src io.Reader) *ServerProperties { config := &ServerProperties{} // 读取配置文件 rawMap := make(map[string]string) scanner := bufio.NewScanner(src) for scanner.Scan() { line := scanner.Text() // 跳过注释行(以#开头的行) if len(line) > 0 && line[0] == '#' { continue } // 查找第一个空格位置,分离键和值 pivot := strings.IndexAny(line, " ") if pivot > 0 && pivot < len(line)-1 { // 找到分隔符 key := line[0:pivot] value := strings.Trim(line[pivot+1:], " ") rawMap[strings.ToLower(key)] = value } } if err := scanner.Err(); err != nil { logger.Fatal(err) } // 使用反射解析配置格式 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) // 获取cfg标签作为配置键名,如果没有则使用字段名 key, ok := field.Tag.Lookup("cfg") if !ok { key = field.Name } value, ok := rawMap[strings.ToLower(key)] if ok { // 根据字段类型填充配置值 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 := value == "yes" fieldVal.SetBool(boolValue) case reflect.Slice: if field.Type.Elem().Kind() == reflect.String { slice := strings.Split(value, ",") fieldVal.Set(reflect.ValueOf(slice)) } default: // 未处理的类型 panic("unhandled default case") } } } return config } // SetupConfig 读取配置文件并将属性存储到Properties变量中 func SetupConfig(configFilename string) { file, err := os.Open(configFilename) if err != nil { panic(err) } defer func() { closeErr := file.Close() if closeErr != nil { panic(closeErr) } }() Properties = parse(file) }