ecs/servers/user/logic/manager.go
2025-07-16 10:05:22 +08:00

325 lines
8.1 KiB
Go

package logic
import (
"ecs/proto"
"ecs/proto/pb"
"errors"
"github.com/oylshe1314/framework/client/db"
"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"
"golang.org/x/crypto/bcrypt"
"sync"
)
type manager struct {
server server.Server
}
func (this *manager) Logger() log.Logger {
return this.server.Logger()
}
type UserManager struct {
manager
mongoClient db.MongoClient
locker sync.RWMutex
users map[string]*User
tokens map[uint64]string
}
func NewUserManager(svr server.Server, mongoClient db.MongoClient) *UserManager {
return &UserManager{
manager: manager{
server: svr,
},
mongoClient: mongoClient,
users: map[string]*User{},
tokens: map[uint64]string{},
}
}
func (this *UserManager) Init() error {
return nil
}
func (this *UserManager) Close() error {
return nil
}
func (this *UserManager) saveUser(user *User) error {
_, err := this.mongoClient.Collection(TableUser).InsertOne(this.mongoClient.Context(), user)
return err
}
func (this *UserManager) queryUser(filter bson.M) (*User, error) {
var user = new(User)
var err = this.mongoClient.Collection(TableUser).FindOne(this.mongoClient.Context(), filter).Decode(user)
if err != nil {
if errors.Is(err, mongo.ErrNoDocuments) {
return nil, nil
}
return nil, err
}
return user, nil
}
func (this *UserManager) updateUser(id string, set bson.M) error {
var _, err = this.mongoClient.Collection(TableUser).UpdateByID(this.mongoClient.Context(), id, bson.M{"$set": set})
return err
}
func (this *UserManager) signUp(origin *proto.UserOrigin, auth *proto.UserAuth, thirdInfo map[string]interface{}) (*User, error) {
counter, err := this.mongoClient.Counter("user_id", 1)
if err != nil {
return nil, err
}
var uid = util.EncryptUid(counter)
if len(auth.Password) > 0 {
password, err := bcrypt.GenerateFromPassword([]byte(auth.Password), bcrypt.DefaultCost)
if err != nil {
this.Logger().Error(err)
return nil, err
}
auth.Password = string(password)
}
var user = &User{
Id: UserKey(origin.Channel, auth.Username),
UserId: uid,
Platform: origin.Platform,
Channel: origin.Channel,
Username: auth.Username,
Password: auth.Password,
CreateTime: util.NowUnix(),
ThirdInfo: thirdInfo,
}
err = this.saveUser(user)
if err != nil {
return nil, err
}
return user, nil
}
func (this *UserManager) SignUp(origin *proto.UserOrigin, auth *proto.UserAuth) (*User, error) {
if origin == nil {
this.Logger().Error("Parameter error, UserOrigin == nil")
return nil, proto.ErrParameterError
}
if auth == nil {
this.Logger().Error("Parameter error, UserAuth == nil")
return nil, proto.ErrParameterError
}
user, err := this.queryUser(bson.M{"_id": UserKey(origin.Channel, auth.Username)})
if err != nil {
this.Logger().Error(err)
return nil, proto.ErrInternalError
}
if user != nil {
return nil, proto.ErrUsernameExists
}
user, err = this.signUp(origin, auth, nil)
if err != nil {
this.Logger().Error(err)
return nil, proto.ErrInternalError
}
return user, nil
}
func (this *UserManager) Login(origin *proto.UserOrigin, auth *proto.UserAuth, third *proto.UserThird) (*User, string, error) {
if origin == nil {
this.Logger().Error("Parameter error, UserOrigin == nil")
return nil, "", proto.ErrParameterError
}
//var thirdInfo map[string]any
switch pb.Channel(origin.Channel) {
case pb.Channel_Internal:
if auth == nil {
this.Logger().Error("Parameter error, UserAuth == nil")
return nil, "", proto.ErrParameterError
}
//case pb.Channel_WechatMiniGame:
// if third == nil {
// this.logger.Error("Parameter error, UserThird == nil")
// return nil, "", proto.ErrParameterError
// }
//
// ack, err := wechat.Code2Session(third.Token)
// if err != nil {
// this.logger.Error("Code to session failed, ", err)
// return nil, "", proto.ErrUserLoginFailed
// }
//
// if ack.ErrCode != 0 {
// this.logger.Error("Third user login failed, msg: ", ack.ErrMsg)
// return nil, "", proto.ErrUserLoginFailed
// }
//
// auth = &proto.UserAuth{Username: ack.OpenId}
// thirdInfo = map[string]any{"openid": ack.OpenId, "unionid": ack.UnionId, "sessionKey": ack.SessionKey}
//case proto.ChannelTapTap:
// if third == nil {
// this.logger.Error("Parameter error, UserThird == nil")
// return nil, "", proto.ErrParameterError
// }
//
// if third.Args == nil || third.Args.TapTap == nil || third.Args.TapTap.MacKey == "" {
// return nil, "", proto.ErrParameterError
// }
//
// ack, err := taptap.AccountProfile(third.Token, third.Args.TapTap.MacKey)
// if err != nil {
// this.logger.Error(err)
// return nil, "", proto.ErrUserLoginFailed
// }
//
// if !ack.Success {
// return nil, "", proto.ErrUserLoginFailed
// }
//
// auth = &proto.UserAuth{Username: ack.Data.Openid}
// thirdInfo = map[string]interface{}{"name": ack.Data.Name, "avatar": ack.Data.Avatar}
default:
return nil, "", proto.ErrChannelError
}
user, err := this.queryUser(bson.M{"_id": UserKey(origin.Channel, auth.Username)})
if err != nil {
this.Logger().Error(err)
return nil, "", proto.ErrInternalError
}
if user == nil {
user, err = this.signUp(origin, auth, nil)
if err != nil {
this.Logger().Error(err)
return nil, "", proto.ErrInternalError
}
} else {
if user.BanLogin && user.BanLoginTime > util.NowUnix() {
return nil, "", proto.ErrUserBanLogin
}
if len(auth.Password) > 0 {
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(auth.Password))
if err != nil {
this.Logger().Error(err)
return nil, "", proto.ErrPasswordError
}
}
//if thirdInfo != nil {
// if !reflect.DeepEqual(user.ThirdInfo, thirdInfo) {
// user.ThirdInfo = thirdInfo
// err = this.updateUser(user.Id, bson.M{"third_info": user.ThirdInfo})
// if err != nil {
// this.Logger().Error(err)
// return nil, "", proto.ErrInternalError
// }
// }
//}
}
var token = util.RandomToken()
this.locker.Lock()
defer this.locker.Unlock()
if expired, ok := this.tokens[user.UserId]; ok {
delete(this.users, expired)
}
this.users[token] = user
this.tokens[user.UserId] = token
return user, token, nil
}
func (this *UserManager) TokenVerify(token string, serverId uint32) (*User, error) {
this.locker.RLock()
var user = this.users[token]
this.locker.RUnlock()
if user == nil {
return nil, nil
}
if user.RecentServer != serverId {
user.RecentServer = serverId
var err = this.updateUser(user.Id, bson.M{"recent_server": user.RecentServer})
if err != nil {
this.Logger().Error(err)
return nil, proto.ErrInternalError
}
}
return user, nil
}
//func (this *UserManager) Ban(userId string, banDays uint32) error {
// user, err := this.queryUser(bson.M{"_id": userId})
// if err != nil {
// this.logger.Error("Query user error, ", err)
// return proto.RawErrInternalError
// }
//
// if user == nil {
// return proto.RawErrUserNotExists
// }
//
// if banDays == 0 {
// user.BanLogin = false
// user.BanLoginTime = int64(0)
// } else {
// user.BanLogin = true
// user.BanLoginTime = util.TodayBeginTime() + 86400*int64(banDays)
// }
//
// _, err = this.mongoClient.Collection(TableUser).UpdateByID(this.mongoClient.Context(), user.Id, bson.M{"$set": bson.M{"ban_login": user.BanLogin, "ban_login_time": user.BanLoginTime}})
// if err != nil {
// this.logger.Error(err)
// return proto.RawErrInternalError
// }
//
// if banDays == 0 {
// return nil
// }
//
// return nil
//}
//
//func (this *UserManager) ResetPassword(userId string, password string) error {
// user, err := this.queryUser(bson.M{"_id": userId})
// if err != nil {
// this.logger.Error("Query user error, ", err)
// return proto.RawErrInternalError
// }
//
// if user == nil {
// return proto.RawErrUserNotExists
// }
//
// user.Password = password
//
// _, err = this.mongoClient.Collection(TableUser).UpdateByID(this.mongoClient.Context(), user.Id, bson.M{"$set": bson.M{"password": user.Password}})
// if err != nil {
// this.logger.Error(err)
// return proto.RawErrInternalError
// }
//
// return nil
//}