189 lines
4.0 KiB
Go
189 lines
4.0 KiB
Go
package internal
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"go.mongodb.org/mongo-driver/mongo"
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
|
"mongo.games.com/goserver/core/logger"
|
|
)
|
|
|
|
type Config struct {
|
|
Global map[string]*DatabaseConfig
|
|
Platforms map[string]map[string]*DatabaseConfig
|
|
}
|
|
|
|
type DatabaseConfig struct {
|
|
HostName string // 主机地址
|
|
HostPort int32 // 端口
|
|
Database string // 数据库名
|
|
Username string // 用户名
|
|
Password string // 密码
|
|
Options string // 配置
|
|
}
|
|
|
|
type Collection struct {
|
|
Database *Database
|
|
*mongo.Collection
|
|
}
|
|
|
|
type Database struct {
|
|
*DatabaseConfig
|
|
Client *mongo.Client
|
|
Database *mongo.Database
|
|
Collection sync.Map
|
|
}
|
|
|
|
func (d *Database) Connect() error {
|
|
if d.DatabaseConfig == nil {
|
|
err := fmt.Errorf("mongo Connect error, DatabaseConifg not found")
|
|
logger.Logger.Error(err)
|
|
return err
|
|
}
|
|
|
|
login := ""
|
|
if d.DatabaseConfig.Username != "" {
|
|
login = d.DatabaseConfig.Username + ":" + d.DatabaseConfig.Password + "@"
|
|
}
|
|
host := d.DatabaseConfig.HostName
|
|
if d.DatabaseConfig.HostName == "" {
|
|
host = "127.0.0.1"
|
|
}
|
|
port := d.DatabaseConfig.HostPort
|
|
if d.DatabaseConfig.HostPort == 0 {
|
|
port = 27017
|
|
}
|
|
myOptions := d.DatabaseConfig.Options
|
|
if myOptions != "" {
|
|
myOptions = "?" + myOptions
|
|
}
|
|
|
|
s := fmt.Sprintf("mongodb://%s%s:%d/admin%s", login, host, port, myOptions)
|
|
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(s))
|
|
if err != nil {
|
|
logger.Logger.Errorf("mongo Connect %v error: %v config:%+v", s, err, *d.DatabaseConfig)
|
|
return err
|
|
}
|
|
logger.Logger.Tracef("mongo connect success %+v", *d.DatabaseConfig)
|
|
d.Client = client
|
|
d.Database = client.Database(d.DatabaseConfig.Database)
|
|
return nil
|
|
}
|
|
|
|
func (d *Database) GetCollection(name string) (*Collection, error) {
|
|
if d.Database == nil {
|
|
err := fmt.Errorf("mongo GetCollection error, collection:%v, database is nil", name)
|
|
logger.Logger.Error(err)
|
|
return nil, err
|
|
}
|
|
v, ok := d.Collection.Load(name)
|
|
if !ok {
|
|
v = &Collection{
|
|
Database: d,
|
|
Collection: d.Database.Collection(name),
|
|
}
|
|
d.Collection.Store(name, v)
|
|
}
|
|
c, _ := v.(*Collection)
|
|
return c, nil
|
|
}
|
|
|
|
type Manager struct {
|
|
conf *Config
|
|
global *sync.Map // 内部库名称:Database
|
|
platforms *sync.Map // 平台id:内部库名称:Database
|
|
}
|
|
|
|
func (m *Manager) GetCollection(key, database, collection string) (*Collection, error) {
|
|
switch key {
|
|
case "global":
|
|
v, ok := m.global.Load(database)
|
|
if !ok {
|
|
db := &Database{
|
|
DatabaseConfig: m.conf.Global[database],
|
|
Collection: sync.Map{},
|
|
}
|
|
if err := db.Connect(); err != nil {
|
|
return nil, err
|
|
}
|
|
v = db
|
|
m.global.Store(database, v)
|
|
}
|
|
d, _ := v.(*Database)
|
|
return d.GetCollection(collection)
|
|
|
|
default:
|
|
var mp *sync.Map
|
|
v, ok := m.platforms.Load(key) // 平台id
|
|
if !ok {
|
|
mp = new(sync.Map)
|
|
m.platforms.Store(key, mp)
|
|
} else {
|
|
mp = v.(*sync.Map)
|
|
}
|
|
v, ok = mp.Load(database)
|
|
if !ok {
|
|
db := &Database{
|
|
DatabaseConfig: m.conf.Platforms[key][database],
|
|
Collection: sync.Map{},
|
|
}
|
|
if err := db.Connect(); err != nil {
|
|
return nil, err
|
|
}
|
|
v = db
|
|
mp.Store(database, v)
|
|
}
|
|
d, _ := v.(*Database)
|
|
return d.GetCollection(collection)
|
|
}
|
|
}
|
|
|
|
func (m *Manager) Restart(conf *Config) {
|
|
logger.Logger.Infof("mongo manager restart...")
|
|
old := *m
|
|
time.AfterFunc(time.Minute, func() {
|
|
Close(&old)
|
|
})
|
|
|
|
m.conf = conf
|
|
m.global = &sync.Map{}
|
|
m.platforms = &sync.Map{}
|
|
}
|
|
|
|
func Close(m *Manager) {
|
|
logger.Logger.Infof("mongo manager close")
|
|
m.global.Range(func(key, value any) bool {
|
|
if v, ok := value.(*Database); ok {
|
|
v.Client.Disconnect(nil)
|
|
}
|
|
return true
|
|
})
|
|
|
|
m.platforms.Range(func(key, value any) bool {
|
|
if v, ok := value.(*sync.Map); ok {
|
|
v.Range(func(key, value any) bool {
|
|
if v, ok := value.(*Database); ok {
|
|
v.Client.Disconnect(nil)
|
|
}
|
|
return true
|
|
})
|
|
}
|
|
return true
|
|
})
|
|
}
|
|
|
|
func (m *Manager) GetConfig() *Config {
|
|
return m.conf
|
|
}
|
|
|
|
func NewManager(conf *Config) *Manager {
|
|
return &Manager{
|
|
conf: conf,
|
|
global: &sync.Map{},
|
|
platforms: &sync.Map{},
|
|
}
|
|
}
|