2019-02-02 16:18:25 +08:00
|
|
|
// 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,
|
2019-02-02 16:18:25 +08:00
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2017-12-29 16:03:30 +08:00
|
|
|
|
2019-04-02 14:37:46 +08:00
|
|
|
// Package gins provides instances management and core components management.
|
2017-12-30 23:49:55 +08:00
|
|
|
package gins
|
2017-12-14 17:32:51 +08:00
|
|
|
|
2017-12-20 12:05:36 +08:00
|
|
|
import (
|
2019-04-03 23:39:31 +08:00
|
|
|
"fmt"
|
2019-11-07 11:32:25 +08:00
|
|
|
"github.com/gogf/gf/internal/intlog"
|
|
|
|
"github.com/gogf/gf/net/ghttp"
|
2019-07-15 17:40:21 +08:00
|
|
|
|
2019-08-22 21:04:30 +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 (
|
2019-11-28 11:18:09 +08:00
|
|
|
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"
|
2019-11-06 20:22:20 +08:00
|
|
|
gFRAME_CORE_COMPONENT_NAME_LOGGER = "gf.core.component.logger"
|
2019-11-07 11:32:25 +08:00
|
|
|
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
|
|
|
)
|
2017-12-14 17:32:51 +08:00
|
|
|
|
2019-11-06 20:22:20 +08:00
|
|
|
// instances is the instance map for common used components.
|
2019-07-23 23:20:27 +08:00
|
|
|
var instances = gmap.NewStrAnyMap(true)
|
2017-12-14 17:32:51 +08:00
|
|
|
|
2019-11-06 20:22:20 +08:00
|
|
|
// Get returns the instance by given name.
|
|
|
|
func Get(name string) interface{} {
|
|
|
|
return instances.Get(name)
|
2017-12-14 17:32:51 +08:00
|
|
|
}
|
|
|
|
|
2019-11-06 20:22:20 +08:00
|
|
|
// Set sets a instance object to the instance manager with given name.
|
|
|
|
func Set(name string, instance interface{}) {
|
|
|
|
instances.Set(name, instance)
|
2018-10-13 20:29:27 +08:00
|
|
|
}
|
|
|
|
|
2019-11-06 20:22:20 +08:00
|
|
|
// 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)
|
2018-10-13 20:29:27 +08:00
|
|
|
}
|
|
|
|
|
2019-11-06 20:22:20 +08:00
|
|
|
// 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)
|
2018-10-13 20:29:27 +08:00
|
|
|
}
|
|
|
|
|
2019-11-06 20:22:20 +08:00
|
|
|
// 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)
|
2018-10-13 20:29:27 +08:00
|
|
|
}
|
|
|
|
|
2019-11-06 20:22:20 +08:00
|
|
|
// 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
|
|
|
}
|
|
|
|
|
2019-04-03 23:39:31 +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.
|
2019-04-03 23:39:31 +08:00
|
|
|
func View(name ...string) *gview.View {
|
2019-11-28 11:18:09 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2019-04-03 23:39:31 +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.
|
2019-04-03 23:39:31 +08:00
|
|
|
func Config(name ...string) *gcfg.Config {
|
2019-06-19 09:06:52 +08:00
|
|
|
return gcfg.Instance(name...)
|
2018-10-13 20:29:27 +08:00
|
|
|
}
|
|
|
|
|
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...)
|
|
|
|
}
|
|
|
|
|
2019-11-06 20:22:20 +08:00
|
|
|
// 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)
|
2019-11-07 11:32:25 +08:00
|
|
|
// 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)
|
|
|
|
}
|
2019-11-06 20:22:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return logger
|
|
|
|
}).(*glog.Logger)
|
|
|
|
}
|
|
|
|
|
2019-08-22 21:04:30 +08:00
|
|
|
// Database returns an instance of database ORM object
|
|
|
|
// with specified configuration group name.
|
2019-04-03 23:39:31 +08:00
|
|
|
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]
|
|
|
|
}
|
2019-08-22 21:04:30 +08:00
|
|
|
instanceKey := fmt.Sprintf("%s.%s", gFRAME_CORE_COMPONENT_NAME_DATABASE, group)
|
|
|
|
db := instances.GetOrSetFuncLock(instanceKey, func() interface{} {
|
2019-09-10 20:38:23 +08:00
|
|
|
if gdb.GetConfig(group) != nil {
|
|
|
|
db, err := gdb.Instance(group)
|
|
|
|
if err != nil {
|
2019-11-07 11:32:25 +08:00
|
|
|
glog.Panic(err)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2019-09-10 20:38:23 +08:00
|
|
|
return db
|
|
|
|
}
|
|
|
|
m := config.GetMap("database")
|
|
|
|
if m == nil {
|
2019-11-07 11:32:25 +08:00
|
|
|
glog.Panic(`database init failed: "database" node not found, is config file or configuration missing?`)
|
2019-09-10 20:38:23 +08:00
|
|
|
}
|
|
|
|
// 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
|
|
|
}
|
|
|
|
}
|
2019-09-10 20:38:23 +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
|
|
|
}
|
2019-09-10 20:38:23 +08:00
|
|
|
if len(cg) > 0 {
|
|
|
|
gdb.SetConfigGroup(group, cg)
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2019-09-10 20:38:23 +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 {
|
2019-11-07 11:32:25 +08:00
|
|
|
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{}
|
2019-10-15 21:20:38 +08:00
|
|
|
err := gconv.Struct(nodeMap, node)
|
|
|
|
if err != nil {
|
2019-11-07 11:32:25 +08:00
|
|
|
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 {
|
2019-11-22 19:45:42 +08:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2019-08-22 21:04:30 +08:00
|
|
|
// 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()
|
2019-11-07 11:32:25 +08:00
|
|
|
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]
|
|
|
|
}
|
2019-08-22 21:04:30 +08:00
|
|
|
instanceKey := fmt.Sprintf("%s.%s", gFRAME_CORE_COMPONENT_NAME_REDIS, group)
|
|
|
|
result := instances.GetOrSetFuncLock(instanceKey, func() interface{} {
|
2019-09-10 20:38:23 +08:00
|
|
|
// 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 {
|
2019-09-10 20:38:23 +08:00
|
|
|
redisConfig, err := gredis.ConfigFromStr(gconv.String(v))
|
|
|
|
if err != nil {
|
2019-11-07 11:32:25 +08:00
|
|
|
glog.Panic(err)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2019-09-10 20:38:23 +08:00
|
|
|
addConfigMonitor(instanceKey, config)
|
|
|
|
return gredis.New(redisConfig)
|
2019-06-19 09:06:52 +08:00
|
|
|
} else {
|
2019-11-07 11:32:25 +08:00
|
|
|
glog.Panicf(`configuration for redis not found for group "%s"`, group)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
} else {
|
2019-11-07 11:32:25 +08:00
|
|
|
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
|
2018-10-13 21:13:18 +08:00
|
|
|
}
|
|
|
|
|
2019-11-07 11:32:25 +08:00
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
|
2019-04-02 16:08:46 +08:00
|
|
|
func addConfigMonitor(key string, config *gcfg.Config) {
|
2019-08-22 21:04:30 +08:00
|
|
|
if path := config.FilePath(); path != "" && gfile.Exists(path) {
|
2019-11-07 11:32:25 +08:00
|
|
|
_, err := gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
2019-06-19 09:06:52 +08:00
|
|
|
instances.Remove(key)
|
|
|
|
})
|
2019-11-07 11:32:25 +08:00
|
|
|
if err != nil {
|
|
|
|
intlog.Error(err)
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2019-04-02 14:37:46 +08:00
|
|
|
}
|