package logic import ( "fmt" "github.com/oylshe1314/framework/client/db" "github.com/oylshe1314/framework/config" "github.com/oylshe1314/framework/errors" "github.com/oylshe1314/framework/server" "github.com/oylshe1314/framework/util" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "time" ) const TableServer string = "server" func TableServerKey(name string, appId uint32) string { return fmt.Sprint(name, "_", appId) } type ServerInfo struct { Key string `bson:"_id"` Name string `bson:"name"` AppId uint32 `bson:"app_id"` CreateTime int64 `bson:"create_time"` Creations uint32 `bson:"creations"` MaxOnline uint32 `bson:"max_online"` MaxOnlineTime int64 `bson:"max_online_time"` } type AreaConfig struct { Id uint32 `json:"id"` //服务器ID Platform uint32 `json:"platform"` //平台 Channel uint32 `json:"channel"` //渠道 Area string `json:"area"` //大区 Name string `json:"name"` //名称 } type ServerConfig struct { err error dataDir string maxRoles int openTime int64 areaConfig *AreaConfig } func (this *ServerConfig) DataDir() string { return this.dataDir } func (this *ServerConfig) MaxRoles() int { return this.maxRoles } func (this *ServerConfig) OpenTime() int64 { return this.openTime } func (this *ServerConfig) AreaConfig() *AreaConfig { return this.areaConfig } func (this *ServerConfig) WithDataDir(dataDir string) { this.dataDir = dataDir } func (this *ServerConfig) WithMaxRoles(maxRoles int) { this.maxRoles = maxRoles } func (this *ServerConfig) WithOpenTime(openTime string) { if openTime != "" { this.openTime, this.err = util.ParseUnix(openTime, time.DateTime) } } func (this *ServerConfig) WithAreaConfig(areaConfig *AreaConfig) { this.areaConfig = areaConfig } func (this *ServerConfig) Init() (err error) { if this.err != nil { return this.err } if len(this.dataDir) == 0 { return errors.Error("'serverConfig.dataDir' can not be empty") } if this.areaConfig == nil { return errors.Error("'serverConfig.areaConfig' can not be nil") } if this.areaConfig.Id == 0 { return errors.Error("'serverConfig.areaConfig.id' can not be 0") } if this.areaConfig.Area == "" { return errors.Error("'serverConfig.areaConfig.Area' can not be empty") } if this.areaConfig.Name == "" { return errors.Error("'serverConfig.areaConfig.Name' can not be empty") } if this.maxRoles < 1 { this.maxRoles = 1 } return nil } type ServerManager struct { manager closed bool mongoClient *db.MongoClient //eventManager *EventManager info *ServerInfo config *ServerConfig dirty bool //数据是否有更新 creations uint32 //服务器总创建人数 online uint32 //当前在线人数 maxOnline uint32 //历史最大在线人数 maxOnlineTime int64 //历史最大在线时间人数 } func NewServerManager(svr server.Server, config *ServerConfig, mongoClient *db.MongoClient /*, eventManager *EventManager*/) *ServerManager { return &ServerManager{manager: manager{logger: svr.Logger(), server: svr}, config: config, mongoClient: mongoClient /*, eventManager: eventManager*/} } func (this *ServerManager) SetEventManager( /*eventManager *EventManager*/ ) { //this.eventManager = eventManager } func (this *ServerManager) Init() error { //if this.eventManager == nil { // return errors.Error("'eventManager' is nil") //} var err = this.initData() if err != nil { return err } this.run() return nil } func (this *ServerManager) initData() error { var info = &ServerInfo{Key: TableServerKey(this.server.Name(), this.server.AppId())} var err = this.mongoClient.Collection(TableServer).FindOne(this.mongoClient.Context(), bson.M{"_id": info.Key}).Decode(info) if err != nil { if !errors.Is(err, mongo.ErrNoDocuments) { return err } info.Name = this.server.Name() info.AppId = this.server.AppId() info.CreateTime = util.Unix() info.Creations = 0 info.MaxOnline = 0 info.MaxOnlineTime = 0 _, err = this.mongoClient.Collection(TableServer).InsertOne(this.mongoClient.Context(), info) if err != nil { return err } //TODO 其他数据库初始化操作 // 创建玩家昵称索引 //_, err = this.mongoClient.Collection(TablePlayer).Indexes().CreateOne(this.mongoClient.Context(), mongo.IndexModel{Keys: bson.M{"role.name": 1}}) //if err != nil { // return err //} } this.info = info return nil } func (this *ServerManager) Close() error { this.closed = true return nil } func (this *ServerManager) saveData() { var set = bson.M{} if this.creations != this.info.Creations { this.info.Creations = this.creations set["creations"] = this.info.Creations } if this.maxOnline != this.info.MaxOnline { this.info.MaxOnline = this.maxOnline set["max_online"] = this.info.MaxOnline } if this.maxOnlineTime != this.info.MaxOnlineTime { this.info.MaxOnlineTime = this.maxOnlineTime set["max_online_time"] = this.info.MaxOnlineTime } if len(set) > 0 { go func(set bson.M) { _, err := this.mongoClient.Collection(TableServer).UpdateByID(this.mongoClient.Context(), this.info.Key, bson.M{"$set": set}) if err != nil { this.logger.Error("Save server data error, ", err) } }(set) } } func (this *ServerManager) run() { go func() { var rt = 60 - util.Unix()%60 if rt > 0 { time.Sleep(time.Second * time.Duration(rt)) } var ticker = time.NewTicker(time.Minute) defer ticker.Stop() for { if this.closed { return } if this.dirty { this.dirty = false this.saveData() //this.eventManager.ServerOnline(LogTypeServerOnline, this.server.AppId(), this.creations, this.online, this.offline, this.maxOnline, this.maxOnlineTime) } _, ok := <-ticker.C if !ok { return } } }() } func (this *ServerManager) Info() *ServerInfo { return this.info } func (this *ServerManager) Config() *ServerConfig { return this.config } func (this *ServerManager) Creations() uint32 { return this.creations } func (this *ServerManager) MaxOnline() uint32 { return this.maxOnline } func (this *ServerManager) MaxOnlineTime() int64 { return this.maxOnlineTime } func (this *ServerManager) AddCreations(value uint32) { this.creations += value this.dirty = true } func (this *ServerManager) AddOnline(value uint32) { this.online += value if this.online > this.maxOnline { this.maxOnline = this.online this.maxOnlineTime = util.Unix() } this.dirty = true } func (this *ServerManager) ReduceOnline(value uint32) { if this.online > 0 { this.online -= value this.dirty = true } } func (this *ServerManager) Online() uint32 { return this.online } func (this *ServerManager) Reload() error { configServer, ok := this.server.(config.Server) if !ok { return errors.Error("Unsupported data reload") } return configServer.Load(this.config.DataDir()) }