mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
improve configuration feature for glog/ghttp.Server
This commit is contained in:
@ -1,41 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func AddAPKCmdTask11(assistantId int, cmd int32, cmdData []byte, FromClientId string, desc string, priority int, status int32, cmdkey string) (int64, error) {
|
||||
//var res, err = g.DB("test").Insert("assistant_tasks", g.Map{
|
||||
// "assistant_id": assistantId,
|
||||
// "cmd": cmd,
|
||||
// "cmdData": cmdData,
|
||||
// "status": status,
|
||||
// "FromClientId": FromClientId,
|
||||
// "desc": desc,
|
||||
// "priority": priority,
|
||||
// "cmdkey": cmdkey,
|
||||
//})
|
||||
var res, err = g.DB("test").Table("assistant_tasks").Data(g.Map{
|
||||
"assistant_id": assistantId,
|
||||
"cmd": cmd,
|
||||
"cmdData": cmdData,
|
||||
"status": status,
|
||||
"FromClientId": FromClientId,
|
||||
"desc": desc,
|
||||
"priority": priority,
|
||||
"cmdkey": cmdkey,
|
||||
}).Insert()
|
||||
|
||||
if err != nil {
|
||||
glog.Error("插入手机任务队列报错", err.Error())
|
||||
return 0, err
|
||||
}
|
||||
taskId, err := res.LastInsertId()
|
||||
return taskId, err
|
||||
}
|
||||
|
||||
func main() {
|
||||
g.DB().SetDebug(true)
|
||||
AddAPKCmdTask11(1, 2058, []byte(""), "", "", 60, 0, "")
|
||||
replaceCharReg, err := regexp.Compile(`[\-\.\_\s]+`)
|
||||
fmt.Println(err)
|
||||
fmt.Println(replaceCharReg.ReplaceAllString("s--s.s.a b", ""))
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ import (
|
||||
|
||||
// Server returns an instance of http server with specified name.
|
||||
func Server(name ...interface{}) *ghttp.Server {
|
||||
return ghttp.GetServer(name...)
|
||||
return gins.Server(name...)
|
||||
}
|
||||
|
||||
// TCPServer returns an instance of tcp server with specified name.
|
||||
|
||||
@ -9,6 +9,8 @@ package gins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/internal/intlog"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
|
||||
@ -28,6 +30,7 @@ import (
|
||||
const (
|
||||
gFRAME_CORE_COMPONENT_NAME_REDIS = "gf.core.component.redis"
|
||||
gFRAME_CORE_COMPONENT_NAME_LOGGER = "gf.core.component.logger"
|
||||
gFRAME_CORE_COMPONENT_NAME_SERVER = "gf.core.component.server"
|
||||
gFRAME_CORE_COMPONENT_NAME_DATABASE = "gf.core.component.database"
|
||||
)
|
||||
|
||||
@ -100,7 +103,6 @@ func I18n(name ...string) *gi18n.Manager {
|
||||
// Log returns an instance of glog.Logger.
|
||||
// The parameter <name> is the name for the instance.
|
||||
func Log(name ...string) *glog.Logger {
|
||||
config := Config()
|
||||
instanceName := glog.DEFAULT_NAME
|
||||
if len(name) > 0 && name[0] != "" {
|
||||
instanceName = name[0]
|
||||
@ -108,9 +110,12 @@ func Log(name ...string) *glog.Logger {
|
||||
instanceKey := fmt.Sprintf("%s.%s", gFRAME_CORE_COMPONENT_NAME_LOGGER, instanceName)
|
||||
return instances.GetOrSetFuncLock(instanceKey, func() interface{} {
|
||||
logger := glog.Instance(instanceName)
|
||||
if m := config.GetMap("logging"); m != nil {
|
||||
if err := logger.SetConfigWithMap(m); err != nil {
|
||||
glog.Error(err)
|
||||
// To avoid file no found error while it's not necessary.
|
||||
if Config().FilePath() != "" {
|
||||
if m := Config().GetMap("logging"); m != nil {
|
||||
if err := logger.SetConfigWithMap(m); err != nil {
|
||||
glog.Panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return logger
|
||||
@ -130,13 +135,13 @@ func Database(name ...string) gdb.DB {
|
||||
if gdb.GetConfig(group) != nil {
|
||||
db, err := gdb.Instance(group)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
glog.Panic(err)
|
||||
}
|
||||
return db
|
||||
}
|
||||
m := config.GetMap("database")
|
||||
if m == nil {
|
||||
glog.Error(`database init failed: "database" node not found, is config file or configuration missing?`)
|
||||
glog.Panic(`database init failed: "database" node not found, is config file or configuration missing?`)
|
||||
return nil
|
||||
}
|
||||
// Parse <m> as map-slice.
|
||||
@ -173,7 +178,7 @@ func Database(name ...string) gdb.DB {
|
||||
if db, err := gdb.New(name...); err == nil {
|
||||
return db
|
||||
} else {
|
||||
glog.Error(err)
|
||||
glog.Panic(err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@ -191,7 +196,7 @@ func parseDBConfigNode(value interface{}) *gdb.ConfigNode {
|
||||
node := &gdb.ConfigNode{}
|
||||
err := gconv.Struct(nodeMap, node)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
glog.Panic(err)
|
||||
}
|
||||
if value, ok := nodeMap["link"]; ok {
|
||||
node.LinkInfo = gconv.String(value)
|
||||
@ -210,7 +215,7 @@ func parseDBConfigNode(value interface{}) *gdb.ConfigNode {
|
||||
// Redis returns an instance of redis client with specified configuration group name.
|
||||
func Redis(name ...string) *gredis.Redis {
|
||||
config := Config()
|
||||
group := "default"
|
||||
group := gredis.DEFAULT_GROUP_NAME
|
||||
if len(name) > 0 && name[0] != "" {
|
||||
group = name[0]
|
||||
}
|
||||
@ -225,16 +230,16 @@ func Redis(name ...string) *gredis.Redis {
|
||||
if v, ok := m[group]; ok {
|
||||
redisConfig, err := gredis.ConfigFromStr(gconv.String(v))
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
glog.Panic(err)
|
||||
return nil
|
||||
}
|
||||
addConfigMonitor(instanceKey, config)
|
||||
return gredis.New(redisConfig)
|
||||
} else {
|
||||
glog.Errorf(`configuration for redis not found for group "%s"`, group)
|
||||
glog.Panicf(`configuration for redis not found for group "%s"`, group)
|
||||
}
|
||||
} else {
|
||||
glog.Errorf(`incomplete configuration for redis: "redis" node not found in config file "%s"`, config.FilePath())
|
||||
glog.Panicf(`incomplete configuration for redis: "redis" node not found in config file "%s"`, config.FilePath())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@ -244,10 +249,30 @@ func Redis(name ...string) *gredis.Redis {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Server returns an instance of http server with specified name.
|
||||
func Server(name ...interface{}) *ghttp.Server {
|
||||
instanceKey := fmt.Sprintf("%s.%v", gFRAME_CORE_COMPONENT_NAME_SERVER, name)
|
||||
return instances.GetOrSetFuncLock(instanceKey, func() interface{} {
|
||||
s := ghttp.GetServer(name...)
|
||||
// To avoid file no found error while it's not necessary.
|
||||
if Config().FilePath() != "" {
|
||||
if m := Config().GetMap("server"); m != nil {
|
||||
if err := s.SetConfigWithMap(m); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return s
|
||||
}).(*ghttp.Server)
|
||||
}
|
||||
|
||||
func addConfigMonitor(key string, config *gcfg.Config) {
|
||||
if path := config.FilePath(); path != "" && gfile.Exists(path) {
|
||||
gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
||||
_, err := gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
||||
instances.Remove(key)
|
||||
})
|
||||
if err != nil {
|
||||
intlog.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,7 +234,9 @@ func (r *Response) ClearBuffer() {
|
||||
|
||||
// Output outputs the buffer content to the client.
|
||||
func (r *Response) Output() {
|
||||
r.Header().Set("Server", r.Server.config.ServerAgent)
|
||||
if r.Server.config.ServerAgent != "" {
|
||||
r.Header().Set("Server", r.Server.config.ServerAgent)
|
||||
}
|
||||
//r.handleGzip()
|
||||
r.Writer.OutputBuffer()
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
package ghttp
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/gins"
|
||||
"github.com/gogf/gf/os/gcfg"
|
||||
"github.com/gogf/gf/os/gview"
|
||||
"github.com/gogf/gf/util/gmode"
|
||||
)
|
||||
@ -57,14 +57,14 @@ func (r *Response) ParseTplContent(content string, params ...gview.Params) (stri
|
||||
|
||||
// 内置变量/对象
|
||||
func (r *Response) buildInVars(params ...map[string]interface{}) map[string]interface{} {
|
||||
vars := map[string]interface{}(nil)
|
||||
var vars map[string]interface{}
|
||||
if len(params) > 0 && params[0] != nil {
|
||||
vars = params[0]
|
||||
} else {
|
||||
vars = make(map[string]interface{})
|
||||
}
|
||||
// 当配置文件不存在时就不赋值该模板变量,不然会报错
|
||||
if c := gins.Config(); c.FilePath() != "" {
|
||||
if c := gcfg.Instance(); c.FilePath() != "" {
|
||||
vars["Config"] = c.GetMap(".")
|
||||
}
|
||||
vars["Get"] = r.Request.GetQueryMap()
|
||||
|
||||
@ -227,7 +227,9 @@ func GetServer(name ...interface{}) *Server {
|
||||
logger: glog.New(),
|
||||
}
|
||||
// 初始化时使用默认配置
|
||||
s.SetConfig(c)
|
||||
if err := s.SetConfig(c); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// 记录到全局ServerMap中
|
||||
serverMapping.Set(serverName, s)
|
||||
return s
|
||||
@ -368,7 +370,7 @@ func (s *Server) GetRouteMap() string {
|
||||
m[item.domain].Add(item)
|
||||
}
|
||||
}
|
||||
itemFunc := s.config.Addr
|
||||
itemFunc := s.config.Address
|
||||
if s.config.HTTPSAddr != "" {
|
||||
if len(itemFunc) > 0 {
|
||||
itemFunc += ","
|
||||
@ -424,9 +426,9 @@ func (s *Server) startServer(fdMap listenerFdMap) {
|
||||
// HTTPS
|
||||
// ================
|
||||
if len(s.config.HTTPSAddr) == 0 {
|
||||
if len(s.config.Addr) > 0 {
|
||||
s.config.HTTPSAddr = s.config.Addr
|
||||
s.config.Addr = ""
|
||||
if len(s.config.Address) > 0 {
|
||||
s.config.HTTPSAddr = s.config.Address
|
||||
s.config.Address = ""
|
||||
} else {
|
||||
s.config.HTTPSAddr = gDEFAULT_HTTPS_ADDR
|
||||
}
|
||||
@ -464,14 +466,14 @@ func (s *Server) startServer(fdMap listenerFdMap) {
|
||||
// HTTP
|
||||
// ================
|
||||
// 当HTTPS服务未启用时,默认HTTP地址才会生效
|
||||
if !httpsEnabled && len(s.config.Addr) == 0 {
|
||||
s.config.Addr = gDEFAULT_HTTP_ADDR
|
||||
if !httpsEnabled && len(s.config.Address) == 0 {
|
||||
s.config.Address = gDEFAULT_HTTP_ADDR
|
||||
}
|
||||
var array []string
|
||||
if v, ok := fdMap["http"]; ok && len(v) > 0 {
|
||||
array = strings.Split(v, ",")
|
||||
} else {
|
||||
array = strings.Split(s.config.Addr, ",")
|
||||
array = strings.Split(s.config.Address, ",")
|
||||
}
|
||||
for _, v := range array {
|
||||
if len(v) == 0 {
|
||||
|
||||
@ -37,7 +37,7 @@ type LogHandler func(r *Request, err ...error)
|
||||
|
||||
// HTTP Server 设置结构体,静态配置
|
||||
type ServerConfig struct {
|
||||
Addr string // 监听IP和端口,监听本地所有IP使用":端口"(支持多个地址,使用","号分隔)
|
||||
Address string // Server listening address like ":port", multiple addresses separated using ','
|
||||
HTTPSAddr string // HTTPS服务监听地址(支持多个地址,使用","号分隔)
|
||||
HTTPSCertPath string // HTTPS证书文件路径
|
||||
HTTPSKeyPath string // HTTPS签名文件路径
|
||||
@ -81,7 +81,7 @@ type ServerConfig struct {
|
||||
|
||||
// 默认HTTP Server配置
|
||||
var defaultServerConfig = ServerConfig{
|
||||
Addr: "",
|
||||
Address: "",
|
||||
HTTPSAddr: "",
|
||||
Handler: nil,
|
||||
ReadTimeout: 60 * time.Second,
|
||||
@ -116,12 +116,12 @@ func Config() ServerConfig {
|
||||
}
|
||||
|
||||
// 通过Map创建Config配置对象,Map没有传递的属性将会使用模块的默认值
|
||||
func ConfigFromMap(m map[string]interface{}) ServerConfig {
|
||||
func ConfigFromMap(m map[string]interface{}) (ServerConfig, error) {
|
||||
config := defaultServerConfig
|
||||
if err := gconv.Struct(m, &config); err != nil {
|
||||
panic(err)
|
||||
return config, err
|
||||
}
|
||||
return config
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// http server setting设置。
|
||||
@ -140,24 +140,28 @@ func (s *Server) SetConfig(c ServerConfig) error {
|
||||
|
||||
// 通过map设置http server setting。
|
||||
// 注意使用该方法进行http server配置时,需要配置所有的配置项,否则没有配置的属性将会默认变量为空
|
||||
func (s *Server) SetConfigWithMap(m map[string]interface{}) {
|
||||
s.SetConfig(ConfigFromMap(m))
|
||||
func (s *Server) SetConfigWithMap(m map[string]interface{}) error {
|
||||
config, err := ConfigFromMap(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.SetConfig(config)
|
||||
}
|
||||
|
||||
// 设置http server参数 - Addr
|
||||
func (s *Server) SetAddr(address string) {
|
||||
s.config.Addr = address
|
||||
s.config.Address = address
|
||||
}
|
||||
|
||||
// 设置http server参数 - Port
|
||||
func (s *Server) SetPort(port ...int) {
|
||||
if len(port) > 0 {
|
||||
s.config.Addr = ""
|
||||
s.config.Address = ""
|
||||
for _, v := range port {
|
||||
if len(s.config.Addr) > 0 {
|
||||
s.config.Addr += ","
|
||||
if len(s.config.Address) > 0 {
|
||||
s.config.Address += ","
|
||||
}
|
||||
s.config.Addr += ":" + strconv.Itoa(v)
|
||||
s.config.Address += ":" + strconv.Itoa(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,19 +21,35 @@ import (
|
||||
func Test_ConfigFromMap(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := g.Map{
|
||||
"addr": ":8199",
|
||||
"address": ":8199",
|
||||
"readTimeout": "60s",
|
||||
"indexFiles": g.Slice{"index.php", "main.php"},
|
||||
"errorLogEnabled": true,
|
||||
"cookieMaxAge": "1y",
|
||||
}
|
||||
config := ghttp.ConfigFromMap(m)
|
||||
config, err := ghttp.ConfigFromMap(m)
|
||||
gtest.Assert(err, nil)
|
||||
d1, _ := time.ParseDuration(gconv.String(m["readTimeout"]))
|
||||
d2, _ := time.ParseDuration(gconv.String(m["cookieMaxAge"]))
|
||||
gtest.Assert(config.Addr, m["addr"])
|
||||
gtest.Assert(config.Address, m["address"])
|
||||
gtest.Assert(config.ReadTimeout, d1)
|
||||
gtest.Assert(config.CookieMaxAge, d2)
|
||||
gtest.Assert(config.IndexFiles, m["indexFiles"])
|
||||
gtest.Assert(config.ErrorLogEnabled, m["errorLogEnabled"])
|
||||
})
|
||||
}
|
||||
|
||||
func Test_SetConfigWithMap(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := g.Map{
|
||||
"address": ":8199",
|
||||
"readTimeout": "60s",
|
||||
"indexFiles": g.Slice{"index.php", "main.php"},
|
||||
"errorLogEnabled": true,
|
||||
"cookieMaxAge": "1y",
|
||||
}
|
||||
s := g.Server()
|
||||
err := s.SetConfigWithMap(m)
|
||||
gtest.Assert(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -10,12 +10,19 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/internal/structs"
|
||||
"github.com/gogf/gf/internal/utilstr"
|
||||
)
|
||||
|
||||
var (
|
||||
// replaceCharReg is the regular expression object for replacing chars
|
||||
// in map keys and attribute names.
|
||||
replaceCharReg, _ = regexp.Compile(`[\-\.\_\s]+`)
|
||||
)
|
||||
|
||||
// Struct maps the params key-value pairs to the corresponding struct object's properties.
|
||||
// The third parameter <mapping> is unnecessary, indicating the mapping rules between the custom key name
|
||||
// and the attribute name(case sensitive).
|
||||
@ -35,6 +42,7 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin
|
||||
if pointer == nil {
|
||||
return errors.New("object pointer cannot be nil")
|
||||
}
|
||||
// paramsMap is the map[string]interface{} type variable for params.
|
||||
paramsMap := Map(params)
|
||||
if paramsMap == nil {
|
||||
return fmt.Errorf("invalid params: %v", params)
|
||||
@ -53,7 +61,7 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin
|
||||
}
|
||||
elem = rv.Elem()
|
||||
}
|
||||
// Auto create struct object.
|
||||
// It automatically creates struct object if necessary.
|
||||
// For example, if <pointer> is **User, then <elem> is *User, which is a pointer to User.
|
||||
if elem.Type().Kind() == reflect.Ptr && (!elem.IsValid() || elem.IsNil()) {
|
||||
e := reflect.New(elem.Type().Elem()).Elem()
|
||||
@ -61,13 +69,14 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin
|
||||
elem = e
|
||||
}
|
||||
// It only performs one converting to the same attribute.
|
||||
// doneMap is used to check repeated converting.
|
||||
doneMap := make(map[string]bool)
|
||||
// doneMap is used to check repeated converting, its key is the attribute name of the struct.
|
||||
doneMap := make(map[string]struct{})
|
||||
// It first checks the passed mapping rules.
|
||||
if len(mapping) > 0 && len(mapping[0]) > 0 {
|
||||
for mapK, mapV := range mapping[0] {
|
||||
// mapV is the the attribute name of the struct.
|
||||
if v, ok := paramsMap[mapK]; ok {
|
||||
doneMap[mapV] = true
|
||||
doneMap[mapV] = struct{}{}
|
||||
if err := bindVarToStructAttr(elem, mapV, v); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -77,65 +86,67 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin
|
||||
// It secondly checks the tags of attributes.
|
||||
tagMap := structs.TagMapName(pointer, structTagPriority, true)
|
||||
for tagK, tagV := range tagMap {
|
||||
// tagV is the the attribute name of the struct.
|
||||
if _, ok := doneMap[tagV]; ok {
|
||||
continue
|
||||
}
|
||||
if v, ok := paramsMap[tagK]; ok {
|
||||
doneMap[tagV] = true
|
||||
doneMap[tagV] = struct{}{}
|
||||
if err := bindVarToStructAttr(elem, tagV, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
// It finally do the converting with default rules.
|
||||
attrMap := make(map[string]struct{})
|
||||
// The key of the map is the attribute name of the struct,
|
||||
// and the value is its replaced name for later comparison to improve performance.
|
||||
attrMap := make(map[string]string)
|
||||
elemType := elem.Type()
|
||||
tempName := ""
|
||||
for i := 0; i < elem.NumField(); i++ {
|
||||
// Only do converting to public attributes.
|
||||
if !utilstr.IsLetterUpper(elemType.Field(i).Name[0]) {
|
||||
continue
|
||||
}
|
||||
attrMap[elemType.Field(i).Name] = struct{}{}
|
||||
tempName = elemType.Field(i).Name
|
||||
attrMap[tempName] = replaceCharReg.ReplaceAllString(tempName, "")
|
||||
}
|
||||
if len(attrMap) == 0 {
|
||||
return nil
|
||||
}
|
||||
var attrName, checkName string
|
||||
for mapK, mapV := range paramsMap {
|
||||
name := ""
|
||||
for _, checkName := range []string{
|
||||
utilstr.UcFirst(mapK),
|
||||
utilstr.ReplaceByMap(mapK, map[string]string{
|
||||
"_": "",
|
||||
"-": "",
|
||||
" ": "",
|
||||
})} {
|
||||
if _, ok := doneMap[checkName]; ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := tagMap[checkName]; ok {
|
||||
continue
|
||||
}
|
||||
// Loop to find the matched attribute name.
|
||||
for value, _ := range attrMap {
|
||||
if strings.EqualFold(checkName, value) {
|
||||
name = value
|
||||
break
|
||||
}
|
||||
if strings.EqualFold(checkName, strings.Replace(value, "_", "", -1)) {
|
||||
name = value
|
||||
break
|
||||
}
|
||||
}
|
||||
doneMap[checkName] = true
|
||||
if name != "" {
|
||||
attrName = ""
|
||||
checkName = replaceCharReg.ReplaceAllString(mapK, "")
|
||||
// Loop to find the matched attribute name with or without
|
||||
// string cases and chars like '-'/'_'/'.'/' '.
|
||||
for attrK, attrV := range attrMap {
|
||||
// Eg:
|
||||
// UserName eq user_name
|
||||
// User-Name eq username
|
||||
// username eq userName
|
||||
// etc.
|
||||
if strings.EqualFold(checkName, attrV) {
|
||||
attrName = attrK
|
||||
break
|
||||
}
|
||||
}
|
||||
// If the attribute name is already checked converting, then skip it.
|
||||
if attrName != "" {
|
||||
if _, ok := doneMap[attrName]; ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := tagMap[attrName]; ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
// No matching, give up this attribute converting.
|
||||
if name == "" {
|
||||
if attrName == "" {
|
||||
continue
|
||||
}
|
||||
if err := bindVarToStructAttr(elem, name, mapV); err != nil {
|
||||
// Mark it done.
|
||||
doneMap[attrName] = struct{}{}
|
||||
if err := bindVarToStructAttr(elem, attrName, mapV); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,11 +7,42 @@
|
||||
// Package gutil provides utility functions.
|
||||
package gutil
|
||||
|
||||
// CopyMap does memory from map <data> to <copy>.
|
||||
func CopyMap(data map[string]interface{}) (copy map[string]interface{}) {
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// replaceCharReg is the regular expression object for replacing chars in map keys.
|
||||
replaceCharReg, _ = regexp.Compile(`[\-\.\_\s]+`)
|
||||
)
|
||||
|
||||
// MapCopy does memory from map <data> to <copy>.
|
||||
func MapCopy(data map[string]interface{}) (copy map[string]interface{}) {
|
||||
copy = make(map[string]interface{}, len(data))
|
||||
for k, v := range data {
|
||||
copy[k] = v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MapValueForPossibleKey tries to find the possible value for given key with or without
|
||||
// cases or chars '-'/'_'/'.'/' '.
|
||||
//
|
||||
// Note that this function might be of low performance.
|
||||
func MapPossibleValueForKey(data map[string]interface{}, key string) interface{} {
|
||||
if v, ok := data[key]; ok {
|
||||
return v
|
||||
}
|
||||
replacedKey := replaceCharReg.ReplaceAllString(key, "")
|
||||
if v, ok := data[replacedKey]; ok {
|
||||
return v
|
||||
}
|
||||
// Loop for check.
|
||||
for k, v := range data {
|
||||
if strings.EqualFold(replaceCharReg.ReplaceAllString(k, ""), replacedKey) {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user