From e0e44380b77ee604fd195dc4ae89933a3aae6bcf Mon Sep 17 00:00:00 2001 From: liuxiaobo <1224730913@qq.com> Date: Mon, 2 Jun 2025 01:07:35 +0800 Subject: [PATCH] =?UTF-8?q?db=E6=9C=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/tableOperation.go | 33 ++-- common/model/user/user.go | 19 +++ common/model/user/userAccount.go | 46 ++++++ common/model/user/userResources.go | 19 +++ common/pb/msgId.proto | 3 +- common/utils/password.go | 14 ++ server/db/model/user.go | 23 --- server/db/model/userAccount.go | 152 ------------------ server/db/{model => operation}/db.go | 19 ++- server/db/operation/operation.go | 16 ++ server/db/operation/userAccount.go | 114 +++++++++++++ server/db/server/processor.go | 55 +------ server/db/server/service.go | 45 ++---- server/db/server/user.go | 51 ++++++ server/gate/server/service.go | 5 +- 工作.txt | 20 +++ 16 files changed, 357 insertions(+), 277 deletions(-) rename server/db/model/tableOption.go => common/model/tableOperation.go (78%) create mode 100644 common/model/user/user.go create mode 100644 common/model/user/userAccount.go create mode 100644 common/model/user/userResources.go create mode 100644 common/utils/password.go delete mode 100644 server/db/model/user.go delete mode 100644 server/db/model/userAccount.go rename server/db/{model => operation}/db.go (75%) create mode 100644 server/db/operation/operation.go create mode 100644 server/db/operation/userAccount.go create mode 100644 server/db/server/user.go create mode 100644 工作.txt diff --git a/server/db/model/tableOption.go b/common/model/tableOperation.go similarity index 78% rename from server/db/model/tableOption.go rename to common/model/tableOperation.go index 06a8383..ab652c4 100644 --- a/server/db/model/tableOption.go +++ b/common/model/tableOperation.go @@ -6,6 +6,7 @@ import ( "fmt" "game/common/proto/pb" "game/common/serialization" + "game/common/utils" "github.com/fox/fox/log" "github.com/go-redis/redis/v8" "gorm.io/gorm" @@ -13,7 +14,7 @@ import ( ) const ( - tableExpire = 7 * 24 * time.Hour // 七天后过期 + TableExpire = 7 * 24 * time.Hour // 七天后过期 ) type resultT[T any] struct { @@ -33,7 +34,7 @@ type TableOp[T iTable] struct { rds *redis.Client } -func newTableOp[T iTable](db *gorm.DB, rds *redis.Client) *TableOp[T] { +func NewTableOp[T iTable](db *gorm.DB, rds *redis.Client) *TableOp[T] { return &TableOp[T]{db: db, rds: rds} } @@ -82,7 +83,7 @@ func (s *TableOp[T]) updateRedis(id uint, maps map[string]any) { if err := s.rds.HMSet(context.Background(), s.redisKey(id), maps).Err(); err != nil { log.ErrorF("redis-key:%v HMSet err: %v", s.redisKey(id), err) } - _ = s.rds.Expire(context.Background(), s.redisKey(id), tableExpire).Err() + _ = s.rds.Expire(context.Background(), s.redisKey(id), TableExpire).Err() } func (s *TableOp[T]) deleteRedis(id uint) { @@ -97,6 +98,7 @@ func (s *TableOp[T]) Create(t *T) (*T, pb.ErrCode) { log.ErrorF("create table:%v err:%v", s.tableName(), err) return nil, pb.ErrCode_SystemErr } + s.writeRedis((*t).GetId(), t) return t, pb.ErrCode_OK } @@ -114,16 +116,21 @@ func (s *TableOp[T]) Find(id uint) (*T, pb.ErrCode) { return &result.ret, pb.ErrCode_OK } -//// 根据条件查询,只在mysql中查询,无法在redis中查询 -//func (s *TableOp[T]) FindCondition(condition map[string]any) (*T, error) { -// var result resultT[T] -// err := s.db.Where(condition).First(&result.ret).Error -// if err != nil { -// log.ErrorF("find table:%v condition:%v err:%v", s.tableName(), utils.JsonMarshal(condition), err) -// return nil, err -// } -// return &result.ret, nil -//} +// 根据条件查询,只在mysql中查询,无法在redis中查询 +func (s *TableOp[T]) FindCondition(condition map[string]any) (*T, error) { + var result resultT[T] + err := s.db.Where(condition).First(&result.ret).Error + if err != nil { + log.ErrorF("find table:%v condition:%v err:%v", s.tableName(), utils.JsonMarshal(condition), err) + return nil, err + } + // 查看redis中是否存在该键,不存在则写入数据 + exist, _ := s.rds.Exists(context.Background(), s.redisKey(result.ret.GetId())).Result() + if exist != 1 { + s.writeRedis(result.ret.GetId(), &result.ret) + } + return &result.ret, nil +} func (s *TableOp[T]) Update(id uint, updates map[string]any) (*T, pb.ErrCode) { var result resultT[T] diff --git a/common/model/user/user.go b/common/model/user/user.go new file mode 100644 index 0000000..f513c32 --- /dev/null +++ b/common/model/user/user.go @@ -0,0 +1,19 @@ +package user + +import ( + "gorm.io/gorm" +) + +// 玩家账户表 +type User struct { + gorm.Model + accountId uint `gorm:"type:bigint;uniqueIndex;not null"` // 帐号id + Nickname string `gorm:"type:varchar(32);uniqueIndex;not null"` // 昵称 + AvatarUrl string `gorm:"type:varchar(255)"` // 头像 + AvatarFrame string `gorm:"type:varchar(255)"` // 头像框 + VipExp int32 `gorm:"type:int"` // vip经验值 +} + +func (u User) GetId() uint { + return u.ID +} diff --git a/common/model/user/userAccount.go b/common/model/user/userAccount.go new file mode 100644 index 0000000..942e26a --- /dev/null +++ b/common/model/user/userAccount.go @@ -0,0 +1,46 @@ +package user + +import ( + "gorm.io/gorm" + "time" +) + +const ( + AccountNormal = 1 // 正常 + AccountFrozen = 2 // 冻结 + AccountBanned = 3 // 封禁 +) + +// 玩家账户表 +type UserAccount struct { + gorm.Model + Username string `gorm:"type:varchar(32);uniqueIndex;not null"` // 用户名 + Password string `gorm:"type:varchar(255);not null"` // 密码哈希 + Email string `gorm:"type:varchar(100)"` // 邮箱(可选) + Phone string `gorm:"type:varchar(20)"` // 手机号(可选) + DeviceID string `gorm:"type:varchar(64);index"` // 设备ID + LastLoginIP string `gorm:"type:varchar(45)"` // 最后登录IP(支持IPv6) + LastLoginTime time.Time // 最后登录时间 + Status int `gorm:"type:tinyint;default:1"` // 账号状态 1-正常 2-冻结 3-封禁 + RegisterIP string `gorm:"type:varchar(45)"` // 注册IP + RegisterTime time.Time `gorm:"type:TIMESTAMP;default:CURRENT_TIMESTAMP"` // 注册时间 +} + +func (u UserAccount) GetId() uint { + return u.ID +} + +// 玩家登录记录表 +type UserLoginLog struct { + gorm.Model + PlayerID uint `gorm:"index"` // 关联玩家ID + LoginIP string `gorm:"type:varchar(45);not null"` // 登录IP + LoginTime time.Time `gorm:"type:TIMESTAMP;default:CURRENT_TIMESTAMP"` // 登录时间 + DeviceInfo string `gorm:"type:varchar(255)"` // 设备信息(JSON格式) + LoginResult bool // 登录结果 true-成功 false-失败 + FailReason string `gorm:"type:varchar(100)"` // 失败原因 +} + +func (u UserLoginLog) GetId() uint { + return u.ID +} diff --git a/common/model/user/userResources.go b/common/model/user/userResources.go new file mode 100644 index 0000000..0dbd2c8 --- /dev/null +++ b/common/model/user/userResources.go @@ -0,0 +1,19 @@ +package user + +import ( + "gorm.io/gorm" +) + +// 玩家账户表 +type UserResources struct { + gorm.Model + accountId uint `gorm:"type:bigint;uniqueIndex;not null"` // 帐号id + Nickname string `gorm:"type:varchar(32);uniqueIndex;not null"` // 昵称 + AvatarUrl string `gorm:"type:varchar(255)"` // 头像 + AvatarFrame string `gorm:"type:varchar(255)"` // 头像框 + VipExp int32 `gorm:"type:int"` // vip经验值 +} + +func (u UserResources) GetId() uint { + return u.ID +} diff --git a/common/pb/msgId.proto b/common/pb/msgId.proto index f63f0cc..9089418 100644 --- a/common/pb/msgId.proto +++ b/common/pb/msgId.proto @@ -4,13 +4,14 @@ option go_package = "common/proto/pb"; /* 命名规则: -1. 所有游戏id都在msgId.proto的MsgId中定义,前缀需有C2S,S2C,Ntf三种之一,后缀统一为Id +1. 所有消息id都在msgId.proto的MsgId中定义,前缀需有C2S,S2C,Ntf三种之一,后缀统一为Id 2. 所有错误码都在code.proto的ErrCode中定义 3. 所有消息名为对应消息id去掉后缀Id组成 */ enum MsgId { MI_Unknown = 0; + // 聊天服 2000-2100 C2SChatId = 2000; // 玩家聊天消息 S2CChatId = 2001; // 复用C2SChatMsg diff --git a/common/utils/password.go b/common/utils/password.go new file mode 100644 index 0000000..f780eb3 --- /dev/null +++ b/common/utils/password.go @@ -0,0 +1,14 @@ +package utils + +import ( + "golang.org/x/crypto/bcrypt" +) + +func Password(password string) (string, error) { + // 密码加密 + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + return "", err + } + return string(hashedPassword), nil +} diff --git a/server/db/model/user.go b/server/db/model/user.go deleted file mode 100644 index e7ac52b..0000000 --- a/server/db/model/user.go +++ /dev/null @@ -1,23 +0,0 @@ -package model - -import ( - "gorm.io/gorm" -) - -// 玩家账户表 -type User struct { - gorm.Model - Nickname string `gorm:"type:varchar(32);uniqueIndex;not null"` // 用户名 - AvatarUrl string `gorm:"type:varchar(255)"` // 头像 - AvatarBorder string `gorm:"type:varchar(255)"` // 头像框 - Gold int64 `gorm:"type:bigint;default:0"` // 金币 - VipExp int32 `gorm:"type:int"` // vip经验值 -} - -func (u User) GetId() uint { - return u.ID -} - -func NewUserOp() *TableOp[User] { - return newTableOp[User](UserDB, UserRedis) -} diff --git a/server/db/model/userAccount.go b/server/db/model/userAccount.go deleted file mode 100644 index cc25888..0000000 --- a/server/db/model/userAccount.go +++ /dev/null @@ -1,152 +0,0 @@ -package model - -import ( - "errors" - "github.com/fox/fox/log" - "golang.org/x/crypto/bcrypt" - "gorm.io/gorm" - "time" -) - -const ( - AccountNormal = 1 // 正常 - AccountFrozen = 2 // 冻结 - AccountBanned = 3 // 封禁 -) - -// 玩家账户表 -type UserAccount struct { - gorm.Model - Username string `gorm:"type:varchar(32);uniqueIndex;not null"` // 用户名 - Password string `gorm:"type:varchar(255);not null"` // 密码哈希 - Email string `gorm:"type:varchar(100)"` // 邮箱(可选) - Phone string `gorm:"type:varchar(20)"` // 手机号(可选) - DeviceID string `gorm:"type:varchar(64);index"` // 设备ID - LastLoginIP string `gorm:"type:varchar(45)"` // 最后登录IP(支持IPv6) - LastLoginTime time.Time // 最后登录时间 - Status int `gorm:"type:tinyint;default:1"` // 账号状态 1-正常 2-冻结 3-封禁 - RegisterIP string `gorm:"type:varchar(45)"` // 注册IP - RegisterTime time.Time `gorm:"type:TIMESTAMP;default:CURRENT_TIMESTAMP"` // 注册时间 -} - -// 玩家登录记录表 -type UserLoginLog struct { - gorm.Model - PlayerID uint `gorm:"index"` // 关联玩家ID - LoginIP string `gorm:"type:varchar(45);not null"` // 登录IP - LoginTime time.Time `gorm:"type:TIMESTAMP;default:CURRENT_TIMESTAMP"` // 登录时间 - DeviceInfo string `gorm:"type:varchar(255)"` // 设备信息(JSON格式) - LoginResult bool // 登录结果 true-成功 false-失败 - FailReason string `gorm:"type:varchar(100)"` // 失败原因 -} - -type UserLoginOp struct { - db *gorm.DB - logDb *gorm.DB -} - -func NewUserLoginOp() *UserLoginOp { - return &UserLoginOp{db: UserDB, logDb: LogDB} -} - -var ( - ErrUserOrPassword = errors.New("user or password was error") - ErrAccountFrozen = errors.New("account frozen") - ErrAccountBanned = errors.New("account banned") -) - -func (s *UserLoginOp) Login(username, password, ip, deviceID string) (*UserAccount, error) { - var user UserAccount - err := s.db.Where("username = ?", username).First(&user).Error - if err != nil { - return nil, err - } - // 验证密码 - if err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil { - s.recordLoginLog(user.ID, ip, deviceID, false, ErrUserOrPassword.Error()) - return nil, ErrUserOrPassword - } - // 检查账号状态 - switch user.Status { - case AccountNormal: - - case AccountFrozen: - s.recordLoginLog(user.ID, ip, deviceID, false, ErrAccountFrozen.Error()) - return nil, ErrAccountFrozen - case AccountBanned: - s.recordLoginLog(user.ID, ip, deviceID, false, ErrAccountBanned.Error()) - return nil, ErrAccountBanned - } - // 更新最后登录信息 - user.LastLoginIP = ip - user.LastLoginTime = time.Now() - _ = s.db.Save(&user).Error - - // 记录成功登录日志 - s.recordLoginLog(user.ID, ip, deviceID, true, "") - - // 6. 生成访问令牌 - token, err := generateToken(user.ID, user.Username) - if err != nil { - return nil, err - } - user.Password = token - return &user, err -} - -// 注册新用户 -func (s *UserLoginOp) RegisterNewUser(username, password, ip, deviceID string) (*UserAccount, error) { - // 密码加密 - hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) - if err != nil { - return nil, err - } - user := UserAccount{ - Username: username, - Password: string(hashedPassword), - DeviceID: deviceID, - RegisterIP: ip, - Status: 1, - LastLoginIP: ip, - LastLoginTime: time.Now(), - } - - if err := s.db.Create(&user).Error; err != nil { - return nil, err - } - - s.recordLoginLog(user.ID, ip, deviceID, true, "") - - // 生成访问令牌 - token, err := generateToken(user.ID, user.Username) - if err != nil { - return nil, err - } - user.Password = token - - return &user, nil -} - -// 记录登录日志 -func (s *UserLoginOp) recordLoginLog(userID uint, ip, deviceID string, success bool, failReason string) { - logEntry := UserLoginLog{ - PlayerID: userID, - LoginIP: ip, - DeviceInfo: deviceID, - LoginResult: success, - FailReason: failReason, - } - - if err := s.logDb.Create(&logEntry).Error; err != nil { - log.ErrorF("记录登录日志失败: %v", err) - } -} - -// 生成JWT令牌(简化版) -func generateToken(userID uint, username string) (string, error) { - _ = userID - _ = username - // 这里应该使用JWT库生成实际令牌 - // 简化实现,实际项目中请使用安全的JWT实现 - return "generated-token-placeholder", nil -} diff --git a/server/db/model/db.go b/server/db/operation/db.go similarity index 75% rename from server/db/model/db.go rename to server/db/operation/db.go index d8a76e1..68410b7 100644 --- a/server/db/model/db.go +++ b/server/db/operation/db.go @@ -1,6 +1,7 @@ -package model +package operation import ( + "game/common/model/user" "game/server/db/config" "github.com/fox/fox/db" "github.com/fox/fox/log" @@ -9,9 +10,10 @@ import ( ) var ( - UserRedis *redis.Client - UserDB *gorm.DB - LogDB *gorm.DB + UserRedis *redis.Client + AccountRedis *redis.Client + UserDB *gorm.DB + LogDB *gorm.DB ) func InitRedis() { @@ -23,6 +25,11 @@ func InitRedis() { log.Fatal(err.Error()) return } + AccountRedis, err = db.InitRedis(cfg.Password, cfg.Host, cfg.Port, 1) + if err != nil { + log.Fatal(err.Error()) + return + } } func InitDb() { @@ -42,7 +49,7 @@ func InitDb() { } // 自动迁移game库表结构 err = UserDB.AutoMigrate( - &UserAccount{}, + &user.UserAccount{}, ) if err != nil { log.Fatal(err.Error()) @@ -50,7 +57,7 @@ func InitDb() { } // 自动迁移game_log库表结构 err = LogDB.AutoMigrate( - &UserLoginLog{}, + &user.UserLoginLog{}, ) if err != nil { log.Fatal(err.Error()) diff --git a/server/db/operation/operation.go b/server/db/operation/operation.go new file mode 100644 index 0000000..9aa9638 --- /dev/null +++ b/server/db/operation/operation.go @@ -0,0 +1,16 @@ +package operation + +import ( + "game/common/model" + "game/common/model/user" +) + +// 玩家表 +func NewUserOp() *model.TableOp[user.User] { + return model.NewTableOp[user.User](UserDB, UserRedis) +} + +// 玩家资源表 +func NewUserResourcesOp() *model.TableOp[user.UserResources] { + return model.NewTableOp[user.UserResources](UserDB, UserRedis) +} diff --git a/server/db/operation/userAccount.go b/server/db/operation/userAccount.go new file mode 100644 index 0000000..26a894f --- /dev/null +++ b/server/db/operation/userAccount.go @@ -0,0 +1,114 @@ +package operation + +import ( + "context" + "errors" + "fmt" + "game/common/model" + "game/common/model/user" + "game/common/proto/pb" + "game/common/utils" + "github.com/fox/fox/log" + "github.com/go-redis/redis/v8" + "gorm.io/gorm" + "strconv" +) + +type UserAccountOp struct { + db *gorm.DB + accountRedis *redis.Client + accountOp *model.TableOp[user.UserAccount] +} + +func NewUserAccountOp() *UserAccountOp { + return &UserAccountOp{ + db: UserDB, + accountRedis: AccountRedis, + accountOp: model.NewTableOp[user.UserAccount](UserDB, AccountRedis), + } +} + +func (s *UserAccountOp) redisKey(username string) string { + return fmt.Sprintf("username:%s", username) +} + +func (s *UserAccountOp) GetUserAccount(username string) (*user.UserAccount, pb.ErrCode) { + sUid, err := s.accountRedis.Get(context.Background(), s.redisKey(username)).Result() + if err != nil { + if errors.Is(err, redis.Nil) { + var us user.UserAccount + err = s.db.Where("username = ?", username).First(&us).Error + if err != nil { + log.ErrorF("find user:%v err:%v", username, err) + return nil, pb.ErrCode_SystemErr + } + } else { + log.ErrorF("find user:%v err:%v", username, err) + return nil, pb.ErrCode_SystemErr + } + } + uid, _ := strconv.ParseInt(sUid, 10, 64) + if uid < 0 { + log.ErrorF("get user account:%v failed, uid is: %d", username, uid) + return nil, pb.ErrCode_SystemErr + } + return s.accountOp.Find(uint(uid)) +} + +// 创建用户 +func (s *UserAccountOp) CreateUserAccount(us *user.UserAccount) (*user.UserAccount, pb.ErrCode) { + // 密码加密 + hashedPassword, err := utils.Password(us.Password) + if err != nil { + log.ErrorF("username :%v generate password err:%v", us.Username, err) + return nil, pb.ErrCode_SystemErr + } + us.Password = hashedPassword + var code pb.ErrCode + us, code = s.accountOp.Create(us) + if code != pb.ErrCode_OK { + return nil, code + } + s.accountRedis.Set(context.Background(), s.redisKey(us.Username), us.ID, model.TableExpire) + return us, pb.ErrCode_OK +} + +// 更新密码 +func (s *UserAccountOp) UpdateUserPassword(us *user.UserAccount) (*user.UserAccount, pb.ErrCode) { + // 密码加密 + hashedPassword, err := utils.Password(us.Password) + if err != nil { + log.ErrorF("username :%v generate password err:%v", us.Username, err) + return nil, pb.ErrCode_SystemErr + } + var code pb.ErrCode + us, code = s.accountOp.Update(us.ID, map[string]any{"password": hashedPassword}) + if code != pb.ErrCode_OK { + s.accountRedis.Expire(context.Background(), s.redisKey(us.Username), model.TableExpire) + } + return us, code +} + +//// 记录登录日志 +//func (s *UserAccountOp) recordLoginLog(userID uint, ip, deviceID string, success bool, failReason string) { +// logEntry := user.UserLoginLog{ +// PlayerID: userID, +// LoginIP: ip, +// DeviceInfo: deviceID, +// LoginResult: success, +// FailReason: failReason, +// } +// +// if err := s.logDb.Create(&logEntry).Error; err != nil { +// log.ErrorF("记录登录日志失败: %v", err) +// } +//} +// +//// 生成JWT令牌(简化版) +//func generateToken(userID uint, username string) (string, error) { +// _ = userID +// _ = username +// // 这里应该使用JWT库生成实际令牌 +// // 简化实现,实际项目中请使用安全的JWT实现 +// return "generated-token-placeholder", nil +//} diff --git a/server/db/server/processor.go b/server/db/server/processor.go index 3b46e96..d8c9ad0 100644 --- a/server/db/server/processor.go +++ b/server/db/server/processor.go @@ -1,57 +1,14 @@ package server import ( - "errors" - "game/common/proto/pb" - "game/server/db/model" - "github.com/fox/fox/ipb" + "game/common/rpcName" "github.com/fox/fox/processor" - "github.com/fox/fox/service" - "gorm.io/gorm" ) -func (s *DbService) initProcessor() { - s.processor.RegisterMessages(processor.RegisterMetas{ - pb.MsgId_C2SUserLoginId: {pb.C2SUserLogin{}, s.onLoginOrRegister}, +func (s *DbService) initRpcProcessor() { + s.RpcProcessor.RegisterMessages(map[string]processor.RpcHandler{ + rpcName.CreateUserAccount: s.onCreateUserAccount, + rpcName.GetUserAccount: s.onGetUserAccount, + rpcName.UpdateUserPassword: s.onUpdateUserAccount, }) } - -func (s *DbService) checkLoginOrRegister(req *pb.C2SUserLogin) (user *model.UserAccount, code pb.ErrCode) { - op := model.NewUserLoginOp() - var err error - user, err = op.Login(req.Username, req.Password, req.Ip, req.DeviceId) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - user, err = op.RegisterNewUser(req.Username, req.Password, req.Ip, req.DeviceId) - if err != nil { - code = pb.ErrCode_RegisterUserExist - return - } - } else if errors.Is(err, model.ErrUserOrPassword) { - code = pb.ErrCode_LoginUserOrPwdErr - return - } else if errors.Is(err, model.ErrAccountFrozen) { - code = pb.ErrCode_AccountFrozen - return - } else if errors.Is(err, model.ErrAccountBanned) { - code = pb.ErrCode_AccountBanned - return - } else { - code = pb.ErrCode_SystemErr - } - } - return user, code -} - -// 登录或注册 -func (s *DbService) onLoginOrRegister(iMsg *ipb.InternalMsg, req *pb.C2SUserLogin) { - user, code := s.checkLoginOrRegister(req) - userId := int64(0) - rsp := &pb.S2CUserLogin{Code: code} - if user != nil && code == pb.ErrCode_OK { - rsp.UserId = int64(user.ID) - rsp.Token = user.Password - userId = rsp.UserId - } - s.SendServiceMsg(service.TopicEx(iMsg.ServiceName), iMsg.ConnId, userId, int32(pb.MsgId_S2CUserLoginId), rsp) -} diff --git a/server/db/server/service.go b/server/db/server/service.go index 6f54c24..1a4be5e 100644 --- a/server/db/server/service.go +++ b/server/db/server/service.go @@ -4,22 +4,15 @@ import ( "fmt" "game/common/proto/pb" "game/common/serviceName" - "game/common/userBindService" "game/server/db/config" - "game/server/db/model" - "github.com/fox/fox/ipb" "github.com/fox/fox/log" - "github.com/fox/fox/processor" "github.com/fox/fox/service" - "github.com/golang/protobuf/proto" ) var DbSrv []*DbService type DbService struct { *service.NatsService - processor *processor.Processor - bindService *userBindService.UserBindService } func Init() { @@ -62,9 +55,7 @@ func newLoginService(serviceId int) *DbService { return nil } - s.bindService = userBindService.NewUserBindService(model.UserRedis, s.ServiceEtcd()) - s.processor = processor.NewProcessor() - s.initProcessor() + s.initRpcProcessor() s.OnInit() return s } @@ -88,29 +79,19 @@ func (s *DbService) OnStop() { // 处理其它服发送过来的消息 func (s *DbService) OnMessage(data []byte) error { - var iMsg = &ipb.InternalMsg{} - var err error - if err = proto.Unmarshal(data, iMsg); err != nil { - log.Error(err.Error()) - return err - } - if req, err := s.processor.Unmarshal(iMsg.MsgId, iMsg.Msg); err == nil { - err = s.processor.Dispatch(iMsg.MsgId, iMsg, req) - } else { - log.Error(err.Error()) - } + _ = data //log.Debug(s.Log("received message:%v", iMsg.MsgId)) return nil } -// 向内部服务发送消息 -func (s *DbService) SendServiceData(topic string, connId uint32, userId int64, msgId int32, data []byte) { - iMsg := ipb.MakeMsg(s.Name(), connId, userId, msgId, data) - _ = s.Send(topic, iMsg) -} - -// 向内部服务发送消息 -func (s *DbService) SendServiceMsg(topic string, connId uint32, userId int64, msgId int32, msg proto.Message) { - data, _ := proto.Marshal(msg) - s.SendServiceData(topic, connId, userId, msgId, data) -} +//// 向内部服务发送消息 +//func (s *DbService) SendServiceData(topic string, connId uint32, userId int64, msgId int32, data []byte) { +// iMsg := ipb.MakeMsg(s.Name(), connId, userId, msgId, data) +// _ = s.Send(topic, iMsg) +//} +// +//// 向内部服务发送消息 +//func (s *DbService) SendServiceMsg(topic string, connId uint32, userId int64, msgId int32, msg proto.Message) { +// data, _ := proto.Marshal(msg) +// s.SendServiceData(topic, connId, userId, msgId, data) +//} diff --git a/server/db/server/user.go b/server/db/server/user.go new file mode 100644 index 0000000..7931b44 --- /dev/null +++ b/server/db/server/user.go @@ -0,0 +1,51 @@ +package server + +import ( + "encoding/json" + "game/common/model/user" + "game/common/proto/pb" + "game/server/db/operation" + "github.com/fox/fox/ipb" + "github.com/fox/fox/log" +) + +// 获取帐号 +func (s *DbService) onGetUserAccount(iMsg *ipb.InternalMsg) *ipb.InternalMsg { + s.operation(iMsg, func(us *user.UserAccount) (*user.UserAccount, pb.ErrCode) { + return operation.NewUserAccountOp().GetUserAccount(us.Username) + }) + return iMsg +} + +// 创建帐号 +func (s *DbService) onCreateUserAccount(iMsg *ipb.InternalMsg) *ipb.InternalMsg { + s.operation(iMsg, operation.NewUserAccountOp().CreateUserAccount) + return iMsg +} + +// 修改密码 +func (s *DbService) operation(iMsg *ipb.InternalMsg, operation func(us *user.UserAccount) (*user.UserAccount, pb.ErrCode)) { + us := &user.UserAccount{} + err := json.Unmarshal(iMsg.Msg, us) + if err != nil { + log.ErrorF("error unmarshalling user account %v", err) + return + } + var code pb.ErrCode + us, code = operation(us) + if code != pb.ErrCode_OK { + return + } + iMsg.Msg, err = json.Marshal(us) + if err != nil { + log.ErrorF("error marshalling user account %v", err) + return + } + return +} + +// 修改密码 +func (s *DbService) onUpdateUserAccount(iMsg *ipb.InternalMsg) *ipb.InternalMsg { + s.operation(iMsg, operation.NewUserAccountOp().UpdateUserPassword) + return iMsg +} diff --git a/server/gate/server/service.go b/server/gate/server/service.go index 49fb625..2e11e94 100644 --- a/server/gate/server/service.go +++ b/server/gate/server/service.go @@ -172,6 +172,9 @@ func (s *GateService) WsOnMessage(conn ws.IConn, data []byte) { log.Error(err.Error()) return } + if msg.MsgId < 0 { + return + } var topic string if msg.ServiceName != "" { topic = service.TopicEx(msg.ServiceName) @@ -189,7 +192,7 @@ func (s *GateService) WsOnMessage(conn ws.IConn, data []byte) { } else { log.Error(s.Log("topic:%v not exist.user:%v", topic, conn.UserId())) } - log.Debug(s.Log("received client message:%v", msg.MsgId)) + log.Debug(s.Log("received client:%d user:%v message:%v", conn.Id(), conn.UserId(), msg.MsgId)) } // 向内部服务发送消息 diff --git a/工作.txt b/工作.txt new file mode 100644 index 0000000..106f526 --- /dev/null +++ b/工作.txt @@ -0,0 +1,20 @@ +1.测试gate + 1.1 每10分钟新起1000个连接,发送登陆,然后关闭。检查是否有内存及协程泄漏。 + 1.2 启动1000个链接,每小时固定发送登陆消息,一天后查看连接是否还在。检查心跳机制。 + +2.编写db服 + 2.1 login服向db服请求数据及向log db服写入日志。测试rpc机制。 + +3.编写color game玩法 + 3.1 服务端玩法 + 3.2 客户端用控制台编写逻辑,不涉及ui + +4. 编写管理后台 + 4.1 玩法配置 + 4.2 金流查询 + 4.3 牌局日志 + +5. 客户端编写 u3d + 5.1 网络连接 + 5.2 ui,动画等 + 5.3 玩法逻辑 \ No newline at end of file