github.com/zhongdalu/gf@v1.0.0/g/frame/gins/gins.go (about)

     1  // Copyright 2017 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/zhongdalu/gf.
     6  
     7  // Package gins provides instances management and core components management.
     8  package gins
     9  
    10  import (
    11  	"fmt"
    12  	"time"
    13  
    14  	"github.com/zhongdalu/gf/g/container/gmap"
    15  	"github.com/zhongdalu/gf/g/database/gdb"
    16  	"github.com/zhongdalu/gf/g/database/gredis"
    17  	"github.com/zhongdalu/gf/g/os/gcfg"
    18  	"github.com/zhongdalu/gf/g/os/gfsnotify"
    19  	"github.com/zhongdalu/gf/g/os/glog"
    20  	"github.com/zhongdalu/gf/g/os/gview"
    21  	"github.com/zhongdalu/gf/g/text/gregex"
    22  	"github.com/zhongdalu/gf/g/text/gstr"
    23  	"github.com/zhongdalu/gf/g/util/gconv"
    24  )
    25  
    26  const (
    27  	gFRAME_CORE_COMPONENT_NAME_REDIS    = "gf.core.component.redis"
    28  	gFRAME_CORE_COMPONENT_NAME_DATABASE = "gf.core.component.database"
    29  )
    30  
    31  // 单例对象存储器
    32  var instances = gmap.NewStrAnyMap()
    33  
    34  // 获取单例对象
    35  func Get(key string) interface{} {
    36  	return instances.Get(key)
    37  }
    38  
    39  // 设置单例对象
    40  func Set(key string, value interface{}) {
    41  	instances.Set(key, value)
    42  }
    43  
    44  // 当键名存在时返回其键值,否则写入指定的键值
    45  func GetOrSet(key string, value interface{}) interface{} {
    46  	return instances.GetOrSet(key, value)
    47  }
    48  
    49  // 当键名存在时返回其键值,否则写入指定的键值,键值由指定的函数生成
    50  func GetOrSetFunc(key string, f func() interface{}) interface{} {
    51  	return instances.GetOrSetFunc(key, f)
    52  }
    53  
    54  // 与GetOrSetFunc不同的是,f是在写锁机制内执行
    55  func GetOrSetFuncLock(key string, f func() interface{}) interface{} {
    56  	return instances.GetOrSetFuncLock(key, f)
    57  }
    58  
    59  // 当键名不存在时写入,并返回true;否则返回false。
    60  func SetIfNotExist(key string, value interface{}) bool {
    61  	return instances.SetIfNotExist(key, value)
    62  }
    63  
    64  // View returns an instance of View with default settings.
    65  // The parameter <name> is the name for the instance.
    66  func View(name ...string) *gview.View {
    67  	return gview.Instance(name...)
    68  }
    69  
    70  // Config returns an instance of View with default settings.
    71  // The parameter <name> is the name for the instance.
    72  func Config(name ...string) *gcfg.Config {
    73  	return gcfg.Instance(name...)
    74  }
    75  
    76  // 数据库操作对象,使用了连接池
    77  func Database(name ...string) gdb.DB {
    78  	config := Config()
    79  	group := gdb.DEFAULT_GROUP_NAME
    80  	if len(name) > 0 {
    81  		group = name[0]
    82  	}
    83  	key := fmt.Sprintf("%s.%s", gFRAME_CORE_COMPONENT_NAME_DATABASE, group)
    84  	db := instances.GetOrSetFuncLock(key, func() interface{} {
    85  		if gdb.GetConfig(group) == nil {
    86  			m := config.GetMap("database")
    87  			if m == nil {
    88  				glog.Error(`database init failed: "database" node not found, is config file or configuration missing?`)
    89  				return nil
    90  			}
    91  			// Parse <m> as map-slice.
    92  			for group, groupConfig := range m {
    93  				cg := gdb.ConfigGroup{}
    94  				switch value := groupConfig.(type) {
    95  				case []interface{}:
    96  					for _, v := range value {
    97  						if node := parseDBConfigNode(v); node != nil {
    98  							cg = append(cg, *node)
    99  						}
   100  					}
   101  				case map[string]interface{}:
   102  					if node := parseDBConfigNode(value); node != nil {
   103  						cg = append(cg, *node)
   104  					}
   105  				}
   106  				if len(cg) > 0 {
   107  					gdb.AddConfigGroup(group, cg)
   108  				}
   109  			}
   110  			// Parse <m> as a single node configuration.
   111  			if node := parseDBConfigNode(m); node != nil {
   112  				cg := gdb.ConfigGroup{}
   113  				if node.LinkInfo != "" || node.Host != "" {
   114  					cg = append(cg, *node)
   115  				}
   116  				if len(cg) > 0 {
   117  					gdb.AddConfigGroup(group, cg)
   118  				}
   119  			}
   120  			addConfigMonitor(key, config)
   121  		}
   122  		if db, err := gdb.New(name...); err == nil {
   123  			return db
   124  		} else {
   125  			glog.Error(err)
   126  		}
   127  		return nil
   128  	})
   129  	if db != nil {
   130  		return db.(gdb.DB)
   131  	}
   132  	return nil
   133  }
   134  
   135  // 解析数据库配置节点项
   136  func parseDBConfigNode(value interface{}) *gdb.ConfigNode {
   137  	nodeMap, ok := value.(map[string]interface{})
   138  	if !ok {
   139  		return nil
   140  	}
   141  	node := &gdb.ConfigNode{}
   142  	if value, ok := nodeMap["host"]; ok {
   143  		node.Host = gconv.String(value)
   144  	}
   145  	if value, ok := nodeMap["port"]; ok {
   146  		node.Port = gconv.String(value)
   147  	}
   148  	if value, ok := nodeMap["user"]; ok {
   149  		node.User = gconv.String(value)
   150  	}
   151  	if value, ok := nodeMap["pass"]; ok {
   152  		node.Pass = gconv.String(value)
   153  	}
   154  	if value, ok := nodeMap["name"]; ok {
   155  		node.Name = gconv.String(value)
   156  	}
   157  	if value, ok := nodeMap["type"]; ok {
   158  		node.Type = gconv.String(value)
   159  	}
   160  	if value, ok := nodeMap["role"]; ok {
   161  		node.Role = gconv.String(value)
   162  	}
   163  	if value, ok := nodeMap["debug"]; ok {
   164  		node.Debug = gconv.Bool(value)
   165  	}
   166  	if value, ok := nodeMap["charset"]; ok {
   167  		node.Charset = gconv.String(value)
   168  	}
   169  	if value, ok := nodeMap["weight"]; ok {
   170  		node.Weight = gconv.Int(value)
   171  	}
   172  	if value, ok := nodeMap["linkinfo"]; ok {
   173  		node.LinkInfo = gconv.String(value)
   174  	}
   175  	if value, ok := nodeMap["link-info"]; ok {
   176  		node.LinkInfo = gconv.String(value)
   177  	}
   178  	if value, ok := nodeMap["linkInfo"]; ok {
   179  		node.LinkInfo = gconv.String(value)
   180  	}
   181  	if value, ok := nodeMap["link"]; ok {
   182  		node.LinkInfo = gconv.String(value)
   183  	}
   184  	if value, ok := nodeMap["max-idle"]; ok {
   185  		node.MaxIdleConnCount = gconv.Int(value)
   186  	}
   187  	if value, ok := nodeMap["maxIdle"]; ok {
   188  		node.MaxIdleConnCount = gconv.Int(value)
   189  	}
   190  	if value, ok := nodeMap["max-open"]; ok {
   191  		node.MaxOpenConnCount = gconv.Int(value)
   192  	}
   193  	if value, ok := nodeMap["maxOpen"]; ok {
   194  		node.MaxOpenConnCount = gconv.Int(value)
   195  	}
   196  	if value, ok := nodeMap["max-lifetime"]; ok {
   197  		node.MaxConnLifetime = gconv.Int(value)
   198  	}
   199  	if value, ok := nodeMap["maxLifetime"]; ok {
   200  		node.MaxConnLifetime = gconv.Int(value)
   201  	}
   202  	// Parse link syntax.
   203  	if node.LinkInfo != "" && node.Type == "" {
   204  		match, _ := gregex.MatchString(`([a-z]+):(.+)`, node.LinkInfo)
   205  		if len(match) == 3 {
   206  			node.Type = match[1]
   207  			node.LinkInfo = match[2]
   208  		}
   209  	}
   210  	return node
   211  }
   212  
   213  // Redis操作对象,使用了连接池
   214  func Redis(name ...string) *gredis.Redis {
   215  	config := Config()
   216  	group := "default"
   217  	if len(name) > 0 {
   218  		group = name[0]
   219  	}
   220  	key := fmt.Sprintf("%s.%s", gFRAME_CORE_COMPONENT_NAME_REDIS, group)
   221  	result := instances.GetOrSetFuncLock(key, func() interface{} {
   222  		if m := config.GetMap("redis"); m != nil {
   223  			// host:port[,db,pass?maxIdle=x&maxActive=x&idleTimeout=x&maxConnLifetime=x]
   224  			if v, ok := m[group]; ok {
   225  				line := gconv.String(v)
   226  				array, _ := gregex.MatchString(`(.+):(\d+),{0,1}(\d*),{0,1}(.*)\?(.+)`, line)
   227  				if len(array) == 6 {
   228  					parse, _ := gstr.Parse(array[5])
   229  					redisConfig := gredis.Config{
   230  						Host: array[1],
   231  						Port: gconv.Int(array[2]),
   232  						Db:   gconv.Int(array[3]),
   233  						Pass: array[4],
   234  					}
   235  					if v, ok := parse["maxIdle"]; ok {
   236  						redisConfig.MaxIdle = gconv.Int(v)
   237  					}
   238  					if v, ok := parse["maxActive"]; ok {
   239  						redisConfig.MaxActive = gconv.Int(v)
   240  					}
   241  					if v, ok := parse["idleTimeout"]; ok {
   242  						redisConfig.IdleTimeout = gconv.Duration(v) * time.Second
   243  					}
   244  					if v, ok := parse["maxConnLifetime"]; ok {
   245  						redisConfig.MaxConnLifetime = gconv.Duration(v) * time.Second
   246  					}
   247  					addConfigMonitor(key, config)
   248  					return gredis.New(redisConfig)
   249  				}
   250  				array, _ = gregex.MatchString(`(.+):(\d+),{0,1}(\d*),{0,1}(.*)`, line)
   251  				if len(array) == 5 {
   252  					addConfigMonitor(key, config)
   253  					return gredis.New(gredis.Config{
   254  						Host: array[1],
   255  						Port: gconv.Int(array[2]),
   256  						Db:   gconv.Int(array[3]),
   257  						Pass: array[4],
   258  					})
   259  				} else {
   260  					glog.Errorf(`invalid redis node configuration: "%s"`, line)
   261  				}
   262  			} else {
   263  				glog.Errorf(`configuration for redis not found for group "%s"`, group)
   264  			}
   265  		} else {
   266  			glog.Errorf(`incomplete configuration for redis: "redis" node not found in config file "%s"`, config.FilePath())
   267  		}
   268  		return nil
   269  	})
   270  	if result != nil {
   271  		return result.(*gredis.Redis)
   272  	}
   273  	return nil
   274  }
   275  
   276  // 添加对单例对象的配置文件inotify监控
   277  func addConfigMonitor(key string, config *gcfg.Config) {
   278  	// 使用gfsnotify进行文件监控,当配置文件有任何变化时,清空对象单例缓存
   279  	if path := config.FilePath(); path != "" {
   280  		gfsnotify.Add(path, func(event *gfsnotify.Event) {
   281  			instances.Remove(key)
   282  		})
   283  	}
   284  }
   285  
   286  // 模板内置方法:config
   287  func funcConfig(pattern string, file ...interface{}) string {
   288  	return Config().GetString(pattern, file...)
   289  }