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

2 years ago
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
}