You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

436 lines
7.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package confm
import (
"errors"
"gopkg.in/yaml.v3"
"log"
"os"
"strconv"
"strings"
)
//变量
//实例池
var pool = map[string]*config{}
//默认选项值
var optionDefault = Option{
Path: "./configs/",
Ext: ".yml",
Sep: ".",
}
//类型
//配置内容
type contents = map[string]map[string]interface{}
type config struct {
option Option
//配置文件内容解码缓存
contents
}
type Option struct {
Name string
Path string
Ext string
Sep string
}
// New 创建对象
func New(option ...Option) *config {
verifiedOption := optionVerify(option...)
return create(verifiedOption)
}
// Get 存在直接返回,否则创建、存储再返回
func Get(option ...Option) *config {
verifiedOption := optionVerify(option...)
if !Has(verifiedOption.Name) {
pool[verifiedOption.Name] = create(verifiedOption)
}
return pool[verifiedOption.Name]
}
// Has 存在返回 true否则返回 false
func Has(name string) bool {
_, has := pool[name]
return has
}
func create(option Option) *config {
return &config{
option: option,
contents: contents{},
}
}
func optionVerify(option ...Option) Option {
opt := optionDefault
if len(option) > 0 {
opt.Name = option[0].Name
if option[0].Path != "" {
opt.Path = option[0].Path
}
if option[0].Ext != "" {
opt.Ext = option[0].Ext
if !strings.HasPrefix(opt.Ext, ".") {
opt.Ext = "." + opt.Ext
}
}
if option[0].Sep != "" {
opt.Sep = option[0].Sep
}
}
return opt
}
//可导出包方法
// Bool Getter|Setter
func (c config) Bool(key string) bool {
valueIf, err := c.value(key)
if err != nil {
return false
}
value, ok := valueIf.(bool)
if !ok {
return false
}
return value
}
func (c config) String(key string) string {
valueIf, err := c.value(key)
if err != nil {
return ""
}
return assertString(valueIf)
}
func (c config) Int(key string) int {
valueIf, err := c.value(key)
if err != nil {
log.Println(err)
return 0
}
value, ok := valueIf.(int)
if !ok {
return 0
}
return value
}
func (c config) Uint(key string) uint {
valueIf, err := c.value(key)
if err != nil {
log.Println(err)
return 0
}
value, ok := valueIf.(uint)
if !ok {
return 0
}
return value
}
func (c config) Float64(key string) float64 {
valueIf, err := c.value(key)
if err != nil {
return 0
}
return assertFloat64(valueIf)
}
func (c config) Float32(key string) float32 {
valueIf, err := c.value(key)
if err != nil {
return 0
}
return assertFloat32(valueIf)
}
func (c config) BoolSlice(key string) []bool {
valueIf, err := c.value(key)
if err != nil {
return []bool{}
}
//
sli, ok := valueIf.([]interface{})
if !ok {
return []bool{}
}
value := make([]bool, len(sli))
for i, vi := range sli {
v, ok := vi.(bool)
if ok {
value[i] = v
}
}
return value
}
func (c config) IntSlice(key string) []int {
valueIf, err := c.value(key)
if err != nil {
return []int{}
}
//
sli, ok := valueIf.([]interface{})
if !ok {
return []int{}
}
value := make([]int, len(sli))
for i, vi := range sli {
v, ok := vi.(int)
if ok {
value[i] = v
}
}
return value
}
func (c config) StringSlice(key string) []string {
valueIf, err := c.value(key)
if err != nil {
return []string{}
}
//
sli, ok := valueIf.([]interface{})
if !ok {
return []string{}
}
value := make([]string, len(sli))
for i, vi := range sli {
value[i] = assertString(vi)
}
return value
}
func (c config) Float64Slice(key string) []float64 {
valueIf, err := c.value(key)
if err != nil {
return []float64{}
}
//
sli, ok := valueIf.([]interface{})
if !ok {
return []float64{}
}
value := make([]float64, len(sli))
for i, vi := range sli {
value[i] = assertFloat64(vi)
}
return value
}
func (c config) Float32Slice(key string) []float32 {
valueIf, err := c.value(key)
if err != nil {
return []float32{}
}
//
sli, ok := valueIf.([]interface{})
if !ok {
return []float32{}
}
value := make([]float32, len(sli))
for i, vi := range sli {
value[i] = assertFloat32(vi)
}
return value
}
func (c config) BoolMap(key string) map[string]bool {
valueIf, err := c.value(key)
if err != nil {
return map[string]bool{}
}
//
mp, ok := valueIf.(map[string]interface{})
if !ok {
return map[string]bool{}
}
value := map[string]bool{}
for k, vk := range mp {
value[k] = false
v, ok := vk.(bool)
if ok {
value[k] = v
}
}
return value
}
func (c config) IntMap(key string) map[string]int {
valueIf, err := c.value(key)
if err != nil {
return map[string]int{}
}
//
mp, ok := valueIf.(map[string]interface{})
if !ok {
return map[string]int{}
}
value := map[string]int{}
for k, vk := range mp {
value[k] = 0
v, ok := vk.(int)
if ok {
value[k] = v
}
}
return value
}
func (c config) Float64Map(key string) map[string]float64 {
valueIf, err := c.value(key)
if err != nil {
return map[string]float64{}
}
//
mp, ok := valueIf.(map[string]interface{})
if !ok {
return map[string]float64{}
}
value := map[string]float64{}
for k, vk := range mp {
value[k] = assertFloat64(vk)
}
return value
}
func (c config) Float32Map(key string) map[string]float32 {
valueIf, err := c.value(key)
if err != nil {
return map[string]float32{}
}
//
mp, ok := valueIf.(map[string]interface{})
if !ok {
return map[string]float32{}
}
value := map[string]float32{}
for k, vk := range mp {
value[k] = assertFloat32(vk)
}
return value
}
func (c config) StringMap(key string) map[string]string {
valueIf, err := c.value(key)
if err != nil {
return map[string]string{}
}
//
mp, ok := valueIf.(map[string]interface{})
if !ok {
return map[string]string{}
}
value := map[string]string{}
for k, vk := range mp {
value[k] = assertString(vk)
}
return value
}
//非导出方法
//利用 key 获取 值
func (c config) value(key string) (interface{}, error) {
filename, keys := c.parseKey(key)
if data, exists := c.contents[filename]; !exists {
var (
content = []byte{}
err error
)
if content, err = c.getContent(filename); err != nil {
log.Println(err)
return nil, err
}
if err = yaml.Unmarshal(content, &data); err != nil {
log.Println(err)
return nil, err
}
c.contents[filename] = data
}
//解析
for i, l, currLevel := 0, len(keys), c.contents[filename]; i < l; i++ {
//最后一级 key
if i == l-1 {
if value, exists := currLevel[keys[i]]; exists {
return value, nil
} else {
return nil, errors.New("key is not exists")
}
}
//不是最后一级,继续解析
var exists bool
currLevel, exists = currLevel[keys[i]].(map[string]interface{})
if !exists {
return nil, errors.New("key is not exists")
}
}
return nil, nil
}
//解析 key
func (c config) parseKey(key string) (string, []string) {
strs := strings.Split(key, c.option.Sep)
if len(strs) == 1 {
strs = append([]string{"app"}, strs...)
}
return strs[0], strs[1:]
}
//读取配置文件
func (c config) getContent(filename string) ([]byte, error) {
return os.ReadFile(c.option.Path + filename + c.option.Ext)
}
//断言 Interface{} to string
func assertString(valueIf interface{}) (value string) {
switch v := valueIf.(type) {
case string:
value = v
case int:
value = strconv.FormatInt(int64(v), 10) //string(v)
case float64:
value = strconv.FormatFloat(v, 'f', -1, 64)
case float32:
value = strconv.FormatFloat(float64(v), 'f', -1, 64)
case bool:
value = strconv.FormatBool(v)
}
return
}
//断言 Interface{} to float32
func assertFloat32(valueIf interface{}) (value float32) {
switch v := valueIf.(type) {
case float64:
value = float32(v)
case float32:
value = v
case int:
value = float32(v)
}
return
}
//断言 Interface{} to float64
func assertFloat64(valueIf interface{}) (value float64) {
switch v := valueIf.(type) {
case float64:
value = v
case float32:
value = float64(v)
case int:
value = float64(v)
}
return
}