gf/frame/gins/gins.go

300 lines
8.9 KiB
Go
Raw Normal View History

// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
2017-12-29 16:03:30 +08:00
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
2017-12-29 16:03:30 +08:00
// Package gins provides instances management and core components management.
package gins
2017-12-20 12:05:36 +08:00
import (
"fmt"
"github.com/gogf/gf/internal/intlog"
"github.com/gogf/gf/net/ghttp"
2019-07-15 17:40:21 +08:00
"github.com/gogf/gf/os/gfile"
2019-07-29 21:01:19 +08:00
"github.com/gogf/gf/container/gmap"
"github.com/gogf/gf/database/gdb"
"github.com/gogf/gf/database/gredis"
2019-09-01 00:30:01 +08:00
"github.com/gogf/gf/i18n/gi18n"
2019-07-29 21:01:19 +08:00
"github.com/gogf/gf/os/gcfg"
"github.com/gogf/gf/os/gfsnotify"
"github.com/gogf/gf/os/glog"
2019-08-19 21:02:44 +08:00
"github.com/gogf/gf/os/gres"
2019-07-29 21:01:19 +08:00
"github.com/gogf/gf/os/gview"
"github.com/gogf/gf/text/gregex"
"github.com/gogf/gf/util/gconv"
2017-12-20 12:05:36 +08:00
)
const (
gFRAME_CORE_COMPONENT_NAME_VIEW = "gf.core.component.view"
2019-06-19 09:06:52 +08:00
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"
2019-06-19 09:06:52 +08:00
gFRAME_CORE_COMPONENT_NAME_DATABASE = "gf.core.component.database"
2017-12-20 12:05:36 +08:00
)
// instances is the instance map for common used components.
var instances = gmap.NewStrAnyMap(true)
// Get returns the instance by given name.
func Get(name string) interface{} {
return instances.Get(name)
}
// Set sets a instance object to the instance manager with given name.
func Set(name string, instance interface{}) {
instances.Set(name, instance)
}
// GetOrSet returns the instance by name,
// or set instance to the instance manager if it does not exist and returns this instance.
func GetOrSet(name string, instance interface{}) interface{} {
return instances.GetOrSet(name, instance)
}
// GetOrSetFunc returns the instance by name,
// or sets instance with returned value of callback function <f> if it does not exist
// and then returns this instance.
func GetOrSetFunc(name string, f func() interface{}) interface{} {
return instances.GetOrSetFunc(name, f)
}
// GetOrSetFuncLock returns the instance by name,
// or sets instance with returned value of callback function <f> if it does not exist
// and then returns this instance.
//
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
// with mutex.Lock of the hash map.
func GetOrSetFuncLock(name string, f func() interface{}) interface{} {
return instances.GetOrSetFuncLock(name, f)
}
// SetIfNotExist sets <instance> to the map if the <name> does not exist, then returns true.
// It returns false if <name> exists, and <instance> would be ignored.
func SetIfNotExist(name string, instance interface{}) bool {
return instances.SetIfNotExist(name, instance)
2017-12-20 12:05:36 +08:00
}
// View returns an instance of View with default settings.
2019-06-11 20:57:43 +08:00
// The parameter <name> is the name for the instance.
func View(name ...string) *gview.View {
instanceName := gview.DEFAULT_NAME
if len(name) > 0 && name[0] != "" {
instanceName = name[0]
}
instanceKey := fmt.Sprintf("%s.%s", gFRAME_CORE_COMPONENT_NAME_VIEW, instanceName)
return instances.GetOrSetFuncLock(instanceKey, func() interface{} {
view := gview.Instance(instanceName)
// To avoid file no found error while it's not necessary.
if Config().FilePath() != "" {
if m := Config().GetMap("view"); m != nil {
if err := view.SetConfigWithMap(m); err != nil {
glog.Panic(err)
}
}
}
return view
}).(*gview.View)
2017-12-28 15:21:25 +08:00
}
// Config returns an instance of View with default settings.
2019-06-11 20:57:43 +08:00
// The parameter <name> is the name for the instance.
func Config(name ...string) *gcfg.Config {
2019-06-19 09:06:52 +08:00
return gcfg.Instance(name...)
}
2019-08-19 21:02:44 +08:00
// Resource returns an instance of Resource.
// The parameter <name> is the name for the instance.
func Resource(name ...string) *gres.Resource {
return gres.Instance(name...)
}
2019-09-01 00:30:01 +08:00
// I18n returns an instance of gi18n.Manager.
2019-08-31 18:04:12 +08:00
// The parameter <name> is the name for the instance.
2019-09-01 00:30:01 +08:00
func I18n(name ...string) *gi18n.Manager {
2019-08-31 18:04:12 +08:00
return gi18n.Instance(name...)
}
// Log returns an instance of glog.Logger.
// The parameter <name> is the name for the instance.
func Log(name ...string) *glog.Logger {
instanceName := glog.DEFAULT_NAME
if len(name) > 0 && name[0] != "" {
instanceName = name[0]
}
instanceKey := fmt.Sprintf("%s.%s", gFRAME_CORE_COMPONENT_NAME_LOGGER, instanceName)
return instances.GetOrSetFuncLock(instanceKey, func() interface{} {
logger := glog.Instance(instanceName)
// 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
}).(*glog.Logger)
}
// Database returns an instance of database ORM object
// with specified configuration group name.
func Database(name ...string) gdb.DB {
2019-06-19 09:06:52 +08:00
config := Config()
group := gdb.DEFAULT_GROUP_NAME
2019-07-28 17:37:13 +08:00
if len(name) > 0 && name[0] != "" {
2019-06-19 09:06:52 +08:00
group = name[0]
}
instanceKey := fmt.Sprintf("%s.%s", gFRAME_CORE_COMPONENT_NAME_DATABASE, group)
db := instances.GetOrSetFuncLock(instanceKey, func() interface{} {
if gdb.GetConfig(group) != nil {
db, err := gdb.Instance(group)
if err != nil {
glog.Panic(err)
2019-06-19 09:06:52 +08:00
}
return db
}
m := config.GetMap("database")
if m == nil {
glog.Panic(`database init failed: "database" node not found, is config file or configuration missing?`)
}
// Parse <m> as map-slice.
for group, groupConfig := range m {
cg := gdb.ConfigGroup{}
switch value := groupConfig.(type) {
case []interface{}:
for _, v := range value {
if node := parseDBConfigNode(v); node != nil {
2019-07-09 14:50:56 +08:00
cg = append(cg, *node)
2019-06-19 09:06:52 +08:00
}
}
case map[string]interface{}:
if node := parseDBConfigNode(value); node != nil {
2019-07-09 14:50:56 +08:00
cg = append(cg, *node)
}
2019-06-19 09:06:52 +08:00
}
if len(cg) > 0 {
gdb.SetConfigGroup(group, cg)
}
2019-06-19 09:06:52 +08:00
}
// Parse <m> as a single node configuration.
if node := parseDBConfigNode(m); node != nil {
cg := gdb.ConfigGroup{}
if node.LinkInfo != "" || node.Host != "" {
cg = append(cg, *node)
}
if len(cg) > 0 {
gdb.SetConfigGroup(group, cg)
}
}
addConfigMonitor(instanceKey, config)
2019-06-19 09:06:52 +08:00
if db, err := gdb.New(name...); err == nil {
return db
} else {
glog.Panic(err)
2019-06-19 09:06:52 +08:00
}
return nil
})
if db != nil {
return db.(gdb.DB)
}
return nil
2017-12-20 12:05:36 +08:00
}
2018-08-23 21:55:27 +08:00
2019-07-09 15:08:26 +08:00
func parseDBConfigNode(value interface{}) *gdb.ConfigNode {
2019-07-09 14:50:56 +08:00
nodeMap, ok := value.(map[string]interface{})
if !ok {
return nil
}
node := &gdb.ConfigNode{}
err := gconv.Struct(nodeMap, node)
if err != nil {
glog.Panic(err)
2019-07-09 14:50:56 +08:00
}
if value, ok := nodeMap["link"]; ok {
node.LinkInfo = gconv.String(value)
}
// Parse link syntax.
if node.LinkInfo != "" && node.Type == "" {
match, _ := gregex.MatchString(`([a-z]+):(.+)`, node.LinkInfo)
if len(match) == 3 {
// Special handle for mssql for common usage purpose.
if match[1] == "sqlserver" {
node.Type = "mssql"
node.LinkInfo = node.LinkInfo
} else {
node.Type = match[1]
node.LinkInfo = match[2]
}
2019-07-09 14:50:56 +08:00
}
}
return node
}
// Redis returns an instance of redis client with specified configuration group name.
2019-06-19 09:06:52 +08:00
func Redis(name ...string) *gredis.Redis {
config := Config()
group := gredis.DEFAULT_GROUP_NAME
2019-07-28 17:37:13 +08:00
if len(name) > 0 && name[0] != "" {
2019-06-19 09:06:52 +08:00
group = name[0]
}
instanceKey := fmt.Sprintf("%s.%s", gFRAME_CORE_COMPONENT_NAME_REDIS, group)
result := instances.GetOrSetFuncLock(instanceKey, func() interface{} {
// If already configured, it returns the redis instance.
if _, ok := gredis.GetConfig(group); ok {
return gredis.Instance(group)
}
// Or else, it parses the default configuration file and returns a new redis instance.
2019-06-19 09:06:52 +08:00
if m := config.GetMap("redis"); m != nil {
if v, ok := m[group]; ok {
redisConfig, err := gredis.ConfigFromStr(gconv.String(v))
if err != nil {
glog.Panic(err)
2019-06-19 09:06:52 +08:00
}
addConfigMonitor(instanceKey, config)
return gredis.New(redisConfig)
2019-06-19 09:06:52 +08:00
} else {
glog.Panicf(`configuration for redis not found for group "%s"`, group)
2019-06-19 09:06:52 +08:00
}
} else {
glog.Panicf(`incomplete configuration for redis: "redis" node not found in config file "%s"`, config.FilePath())
2019-06-19 09:06:52 +08:00
}
return nil
})
if result != nil {
return result.(*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) {
_, err := gfsnotify.Add(path, func(event *gfsnotify.Event) {
2019-06-19 09:06:52 +08:00
instances.Remove(key)
})
if err != nil {
intlog.Error(err)
}
2019-06-19 09:06:52 +08:00
}
}