From 5c38610b55efeaebfe3a633fd36f88321962127f Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Fri, 11 Oct 2024 13:29:42 +0800 Subject: [PATCH] =?UTF-8?q?mongodb=E5=BA=93=E5=8D=87=E7=BA=A7=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mongo/export.go | 58 +++++++++++++ mongo/internal/mongo.go | 185 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 mongo/export.go create mode 100644 mongo/internal/mongo.go diff --git a/mongo/export.go b/mongo/export.go new file mode 100644 index 0000000..16d4e81 --- /dev/null +++ b/mongo/export.go @@ -0,0 +1,58 @@ +package mongo + +import ( + "errors" + "mongo.games.com/game/mongo/internal" + "mongo.games.com/goserver/core/logger" +) + +type Config = internal.Config +type DatabaseConfig = internal.DatabaseConfig +type Collection = internal.Collection + +var _manager *internal.Manager +var _conf *internal.Config + +// GetConfig 获取配置 +func GetConfig() *Config { + return _conf +} + +// Init 初始化 +func Init(conf *Config) error { + _conf = conf + _manager = internal.NewManager(_conf) + return nil +} + +// Restart 重启 +func Restart() { + if _manager == nil { + logger.Logger.Errorf("mongo manager is nil, please call Init() first") + return + } + _manager.Restart(_conf) +} + +// GetGlobalCollection 获取全局库 +// database: 数据库名称 +// collection: 集合名称 +func GetGlobalCollection(database, collection string) (*Collection, error) { + if _manager == nil { + return nil, errors.New("mongo manager is nil, please call Init() first") + } + + return _manager.GetCollection("global", database, collection) +} + +// GetCollection 获取平台库 +// platform: 平台id +// database: 数据库名称 +// collection: 集合名称 +func GetCollection(platform, database, collection string) (*Collection, error) { + if _manager == nil { + return nil, errors.New("mongo manager is nil, please call Init() first") + } + + return _manager.GetCollection(platform, database, collection) +} diff --git a/mongo/internal/mongo.go b/mongo/internal/mongo.go new file mode 100644 index 0000000..bb99a56 --- /dev/null +++ b/mongo/internal/mongo.go @@ -0,0 +1,185 @@ +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...") + global := m.global + platforms := m.platforms + time.AfterFunc(time.Minute, func() { + logger.Logger.Infof("mongo manager restart close...") + global.Range(func(key, value any) bool { + if v, ok := value.(*Database); ok { + v.Client.Disconnect(nil) + } + return true + }) + + 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 + }) + }) + + m.conf = conf + m.global = &sync.Map{} + m.platforms = &sync.Map{} +} + +func (m *Manager) GetConfig() *Config { + return m.conf +} + +func NewManager(conf *Config) *Manager { + return &Manager{ + conf: conf, + global: &sync.Map{}, + platforms: &sync.Map{}, + } +}