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 }