package logic import ( "ecs/proto" "github.com/oylshe1314/framework/client/db" "github.com/oylshe1314/framework/client/rpc" "github.com/oylshe1314/framework/errors" "github.com/oylshe1314/framework/log" "github.com/oylshe1314/framework/server" "github.com/oylshe1314/framework/util" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "sort" "sync" "time" ) type manager struct { server server.Server } func (this *manager) Logger() log.Logger { return this.server.Logger() } const tableSetting = "setting" type Setting struct { Id uint32 `bson:"_id"` Version string `bson:"version"` LoginClosed bool `bson:"login_closed"` TimedClose bool `bson:"timed_closed"` CloseTime int64 `bson:"close_time"` ClosedList []uint32 `bson:"closed_list"` WhiteList []uint64 `bson:"white_list"` } const tableNotice = "notice" type Notice struct { Id uint64 `bson:"_id"` Type string `json:"type"` Title string `bson:"title"` Content string `bson:"content"` BeginTime int64 `bson:"begin_time"` EndTime int64 `bson:"end_time"` } type GateManager struct { manager setting *Setting closeTime int64 closeMutex sync.Mutex closeTimer *time.Timer mongoClient db.MongoClient httpRpcClient rpc.HttpRpcClient } func NewGateManager(svr server.Server, mongoClient db.MongoClient, httpRpcClient rpc.HttpRpcClient) *GateManager { return &GateManager{ manager: manager{ server: svr, }, mongoClient: mongoClient, httpRpcClient: httpRpcClient, } } func (this *GateManager) Init() error { setting, err := this.querySetting() if err != nil { return err } if setting != nil { this.setSetting(setting) } return nil } func (this *GateManager) Close() error { return nil } func (this *GateManager) querySetting() (*Setting, error) { var setting = &Setting{Id: this.server.AppId()} var err = this.mongoClient.Collection(tableSetting).FindOne(this.mongoClient.Context(), bson.M{"_id": setting.Id}).Decode(setting) if err != nil { if errors.Is(err, mongo.ErrNoDocuments) { return nil, nil } return nil, err } return setting, nil } func (this *GateManager) GetSetting() *Setting { return this.setting } func (this *GateManager) SetSetting(setting *Setting) error { var err = this.saveSetting(setting) if err != nil { this.Logger().Error(err) return proto.ErrInternalError } this.setSetting(setting) return nil } func (this *GateManager) saveSetting(setting *Setting) error { var updateOption = options.Update().SetUpsert(true) _, err := this.mongoClient.Collection(tableSetting).UpdateByID(this.mongoClient.Context(), setting.Id, bson.M{"$set": setting}, updateOption) return err } func (this *GateManager) setSetting(setting *Setting) { this.setting = setting if setting.LoginClosed { var now = util.NowUnix() this.closeMutex.Lock() if this.closeTimer != nil { if this.closeTime == setting.CloseTime || now >= setting.CloseTime { this.closeMutex.Unlock() return } this.closeTimer.Stop() this.closeTime = 0 this.closeTimer = nil } this.closeMutex.Unlock() var f = func() { this.closeMutex.Lock() this.closeTime = 0 this.closeTimer = nil this.closeMutex.Unlock() ar, err := this.httpRpcClient.AllPost("game", "/server/close", nil, nil, nil) if err != nil { this.Logger().Errorf("Http get error, error: %v", err) } else { for appId, result := range ar { if result.Err != nil { this.Logger().Errorf("[game_1:%d] <- Server offline error, %v", appId, result.Err) continue } if result.Res.Status != errors.StatusSuccessful { this.Logger().Errorf("[game_1:%d] <- Server offline failed, %s", appId, result.Res.Message) continue } } } } if !setting.TimedClose || util.NowUnix() >= setting.CloseTime { f() } else { this.closeMutex.Lock() this.closeTime = setting.CloseTime this.closeTimer = time.AfterFunc(time.Second*time.Duration(setting.CloseTime-now), f) this.closeMutex.Unlock() } } else { this.closeMutex.Lock() if this.closeTimer != nil { this.closeTimer.Stop() this.closeTime = 0 this.closeTimer = nil } this.closeMutex.Unlock() } } type gameServerInfo struct { appId uint32 address string online uint32 } type gameServerList struct { id uint32 platform uint32 channel uint32 area string name string online uint32 roleLv uint32 serverList []*gameServerInfo } func (this *GateManager) GetServerList(platform uint32, channel uint32, userId uint64, recentServer uint32) ([]*proto.GameServer, error) { var setting = this.GetSetting() var whiteList = map[uint64]struct{}{} var closedList = map[uint32]struct{}{} if setting != nil && setting.LoginClosed { if !setting.TimedClose || util.NowUnix() >= setting.CloseTime { for _, whiteId := range setting.WhiteList { whiteList[whiteId] = struct{}{} } if len(setting.ClosedList) == 0 { if _, ok := whiteList[userId]; !ok { return nil, proto.ErrServerMaintain } } for _, closedId := range setting.ClosedList { closedList[closedId] = struct{}{} } } } ar, err := this.httpRpcClient.AllPost("game", "/server/info", nil, &proto.MsgServerInfoReq{UserId: userId}, &proto.MsgServerInfoAck{}) if err != nil { return nil, proto.ErrServerMaintain } var listMap = map[uint32]*gameServerList{} for appId, reply := range ar { if reply.Err != nil { this.Logger().Error("Get server online failed, ", reply.Err) continue } if reply.Res.Error() != nil { this.Logger().Errorf("Get server online failed, status: %d, message: %s", reply.Res.Status, reply.Res.Message) continue } var node = this.httpRpcClient.Node("game", appId) if node == nil { continue } var infoAck = reply.Res.Data.(*proto.MsgServerInfoAck) if platform != 0 { if infoAck.Platform != platform { continue } } if channel != 0 { if infoAck.Channel != channel { continue } } if _, closed := closedList[infoAck.Id]; closed { if _, white := whiteList[userId]; !white { continue } } var gsl = listMap[infoAck.Id] if gsl == nil { gsl = &gameServerList{ id: infoAck.Id, platform: infoAck.Platform, channel: infoAck.Channel, area: infoAck.Area, name: infoAck.Name, roleLv: infoAck.RoleLv, } listMap[infoAck.Id] = gsl } gsl.online += infoAck.Online gsl.serverList = append(gsl.serverList, &gameServerInfo{appId: appId, address: node.Exter.Address, online: infoAck.Online}) } var serverList []*proto.GameServer for _, gsl := range listMap { if len(gsl.serverList) == 0 { continue } sort.Slice(gsl.serverList, func(i, j int) bool { if gsl.serverList[i].online == gsl.serverList[j].online { return gsl.serverList[i].appId < gsl.serverList[j].appId } else { return gsl.serverList[i].online < gsl.serverList[j].online } }) serverList = append(serverList, &proto.GameServer{ Id: gsl.id, Area: gsl.area, Name: gsl.name, Address: gsl.serverList[0].address, Online: gsl.online, Recent: gsl.id == recentServer, RoleLv: gsl.roleLv, }) } sort.Slice(serverList, func(i, j int) bool { return serverList[i].Id < serverList[j].Id }) return serverList, nil } func (this *GateManager) GetNotice() ([]*Notice, error) { var now = util.NowUnix() cur, err := this.mongoClient.Collection(tableNotice).Find(this.mongoClient.Context(), bson.M{"begin_time": bson.M{"$lt": now}, "end_time": bson.M{"$gt": now}}) if err != nil { if errors.Is(err, mongo.ErrNoDocuments) { return nil, nil } return nil, err } defer cur.Close(this.mongoClient.Context()) var notices []*Notice for cur.Next(this.mongoClient.Context()) { var notice = new(Notice) err = cur.Decode(notice) if err != nil { return nil, err } notices = append(notices, notice) } return notices, nil } func (this *GateManager) AddNotice(notice *Notice) error { _, err := this.mongoClient.Collection(tableNotice).InsertOne(this.mongoClient.Context(), notice) return err } func (this *GateManager) DeleteNotice(id uint64) error { _, err := this.mongoClient.Collection(tableNotice).DeleteOne(this.mongoClient.Context(), bson.M{"_id": id}) return err }