game_sync/mongo/internal/mongo.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{},
}
}