|
@@ -0,0 +1,289 @@
|
|
|
|
+package service
|
|
|
|
+
|
|
|
|
+import (
|
|
|
|
+ "context"
|
|
|
|
+ "errors"
|
|
|
|
+ "fmt"
|
|
|
|
+ "log"
|
|
|
|
+ "regexp"
|
|
|
|
+ "strings"
|
|
|
|
+ "time"
|
|
|
|
+
|
|
|
|
+ "github.com/gin-gonic/gin"
|
|
|
|
+ "github.com/mhaya/game/game_cluster/internal/constant"
|
|
|
|
+ "github.com/mhaya/game/game_cluster/internal/mdb"
|
|
|
|
+ "github.com/mhaya/game/game_cluster/internal/mdb/models"
|
|
|
|
+ "github.com/mhaya/game/game_cluster/nodes/webadmin/entity"
|
|
|
|
+ "github.com/mhaya/game/game_cluster/nodes/webadmin/model"
|
|
|
|
+ "go.mongodb.org/mongo-driver/bson"
|
|
|
|
+ "go.mongodb.org/mongo-driver/mongo"
|
|
|
|
+ "go.mongodb.org/mongo-driver/mongo/options"
|
|
|
|
+ "golang.org/x/crypto/bcrypt"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+type Admin struct {
|
|
|
|
+ db *mongo.Database
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func NewAdmin() *Admin {
|
|
|
|
+ return &Admin{
|
|
|
|
+ db: mdb.MDB,
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (a *Admin) GetDB() *mongo.Database {
|
|
|
|
+ return a.db
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (a *Admin) GetDBName() string {
|
|
|
|
+ return "admin"
|
|
|
|
+}
|
|
|
|
+func CheckPasswordHash(password, hash string) bool {
|
|
|
|
+ err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
|
|
|
+ return err == nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// HashPassword 加密密码
|
|
|
|
+func HashPassword(password string) (string, error) {
|
|
|
|
+ bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
|
|
|
|
+ return string(bytes), err
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Login 登录
|
|
|
|
+func (a *Admin) Login(ctx *gin.Context, username string, password string) (*entity.AdminResp, error) {
|
|
|
|
+ log.Printf("Attempting login for user: %s", username)
|
|
|
|
+ user, err := a.QueryUserByUsername(ctx, username)
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Printf("Failed to query user: %s", err)
|
|
|
|
+ return nil, fmt.Errorf("failed to query user: %s", err)
|
|
|
|
+ }
|
|
|
|
+ // 判断用户状态
|
|
|
|
+ if user.Status == 0 {
|
|
|
|
+ log.Println("User is disabled")
|
|
|
|
+ return nil, errors.New("user is disabled")
|
|
|
|
+ }
|
|
|
|
+ // 判断密码
|
|
|
|
+ if !CheckPasswordHash(password, user.Password) {
|
|
|
|
+ log.Println("Invalid username or password")
|
|
|
|
+ return nil, errors.New("invalid username or password")
|
|
|
|
+ }
|
|
|
|
+ // 创建token
|
|
|
|
+ generateToken, err := user.GenerateToken()
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ // 保存token 到 redis 中 过期时间为1天
|
|
|
|
+ err = mdb.RDB.Set(ctx, generateToken, user.Username, 24*time.Hour).Err()
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ // 更新用户登录时间
|
|
|
|
+ _, err = mdb.MDB.Collection(a.GetDBName()).UpdateOne(ctx, bson.M{"username": username}, bson.M{"$set": bson.M{"last_login_time": time.Now().Unix()}})
|
|
|
|
+ log.Printf("Login successful for user: %s", username)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ // 更新用户IP
|
|
|
|
+ ip := ctx.ClientIP()
|
|
|
|
+ _, err = mdb.MDB.Collection(a.GetDBName()).UpdateOne(ctx, bson.M{"username": username}, bson.M{"$set": bson.M{"last_login_ip": ip}})
|
|
|
|
+
|
|
|
|
+ // 返回用户信息
|
|
|
|
+ log.Printf("Returning user: %s", username)
|
|
|
|
+ return &entity.AdminResp{
|
|
|
|
+ ToKen: generateToken,
|
|
|
|
+ }, nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// QueryUserByUsername 根据用户名查询用户
|
|
|
|
+func (a *Admin) QueryUserByUsername(ctx context.Context, username string) (*model.Admin, error) {
|
|
|
|
+ admin := model.Admin{}
|
|
|
|
+ err := mdb.MDB.Collection(a.GetDBName()).FindOne(ctx, bson.M{"username": username}).Decode(&admin)
|
|
|
|
+ if errors.Is(err, mongo.ErrNoDocuments) && username == "admin" {
|
|
|
|
+ // 如果是admin 登录的话 创建一个初始的admin并且存入数据库
|
|
|
|
+ if username == "admin" {
|
|
|
|
+ pwd, err := HashPassword("123456")
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ adminn := &model.Admin{
|
|
|
|
+ Username: "admin",
|
|
|
|
+ Password: pwd,
|
|
|
|
+ RealName: "admin",
|
|
|
|
+ Pid: 0,
|
|
|
|
+ RoleId: 0,
|
|
|
|
+ ManagerAuth: 0,
|
|
|
|
+ Status: 1,
|
|
|
|
+ CreatedAt: 0,
|
|
|
|
+ UpdatedAt: 0,
|
|
|
|
+ DeletedAt: 0,
|
|
|
|
+ LastLoginIp: "",
|
|
|
|
+ LastLoginTime: 0,
|
|
|
|
+ Id: 0,
|
|
|
|
+ }
|
|
|
|
+ _, err = mdb.MDB.Collection(a.GetDBName()).InsertOne(ctx, adminn)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ return adminn, nil
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return &admin, nil
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ChangePassword 修改管理员密码
|
|
|
|
+func (a *Admin) ChangePassword(ctx context.Context, username string, password string) error {
|
|
|
|
+ // 更新密码
|
|
|
|
+ password, _ = HashPassword(password)
|
|
|
|
+ _, err := mdb.MDB.Collection(a.GetDBName()).UpdateOne(ctx, bson.M{"username": username}, bson.M{"$set": bson.M{"password": password}})
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ return nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Add 添加管理员
|
|
|
|
+func (a *Admin) Add(ctx context.Context, username string, password string, realName string, pid int64, roleId int64, status int) error {
|
|
|
|
+ // 判断账号是否重复
|
|
|
|
+ admin := model.Admin{}
|
|
|
|
+ err := mdb.MDB.Collection(a.GetDBName()).FindOne(ctx, bson.M{"username": username}).Decode(&admin)
|
|
|
|
+ if errors.Is(err, mongo.ErrNoDocuments) {
|
|
|
|
+ password, _ = HashPassword(password)
|
|
|
|
+ _, err := mdb.MDB.Collection(a.GetDBName()).InsertOne(ctx, &model.Admin{
|
|
|
|
+ Username: username,
|
|
|
|
+ Password: password,
|
|
|
|
+ RealName: realName,
|
|
|
|
+ Pid: pid,
|
|
|
|
+ RoleId: roleId,
|
|
|
|
+ Status: status,
|
|
|
|
+ CreatedAt: time.Now().Unix(),
|
|
|
|
+ UpdatedAt: time.Now().Unix(),
|
|
|
|
+ DeletedAt: 0,
|
|
|
|
+ LastLoginIp: "",
|
|
|
|
+ LastLoginTime: 0,
|
|
|
|
+ })
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ return nil
|
|
|
|
+ }
|
|
|
|
+ return fmt.Errorf("账号已存在")
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Delete 删除管理员
|
|
|
|
+func (a *Admin) Delete(ctx context.Context, username string) error {
|
|
|
|
+ _, err := mdb.MDB.Collection(a.GetDBName()).DeleteOne(ctx, bson.M{"username": username})
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ return nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// updateStatus
|
|
|
|
+func (a *Admin) UpdateStatus(ctx context.Context, username string, status int) error {
|
|
|
|
+ _, err := mdb.MDB.Collection(a.GetDBName()).UpdateOne(ctx, bson.M{"username": username}, bson.M{"$set": bson.M{"status": status}})
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ return nil
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// FindAll 查找所有管理员信息
|
|
|
|
+func (a *Admin) FindAll(ctx context.Context, page int, pageSize int, username string) ([]*model.Admin, error) {
|
|
|
|
+ // 日志记录
|
|
|
|
+ log.Printf("Finding admins with page %d and page size %d, username: %s", page, pageSize, maskUsername(username))
|
|
|
|
+
|
|
|
|
+ // 验证参数
|
|
|
|
+ if page <= 0 {
|
|
|
|
+ page = 1
|
|
|
|
+ }
|
|
|
|
+ if pageSize <= 0 {
|
|
|
|
+ pageSize = 10
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 构建查询条件
|
|
|
|
+ filter := bson.M{}
|
|
|
|
+ if username != "" {
|
|
|
|
+ filter["username"] = bson.M{"$regex": escapeRegex(username), "$options": "i"}
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 设置分页选项
|
|
|
|
+ skip := (page - 1) * pageSize
|
|
|
|
+ limit := pageSize
|
|
|
|
+ findOptions := options.Find().SetSkip(int64(skip)).SetLimit(int64(limit))
|
|
|
|
+
|
|
|
|
+ // 执行查询
|
|
|
|
+ cursor, err := mdb.MDB.Collection("admin").Find(ctx, filter, findOptions)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ defer func() {
|
|
|
|
+ if closeErr := cursor.Close(ctx); closeErr != nil {
|
|
|
|
+ log.Printf("Error closing cursor: %v", closeErr)
|
|
|
|
+ }
|
|
|
|
+ }()
|
|
|
|
+
|
|
|
|
+ // 解析结果
|
|
|
|
+ admins := make([]*model.Admin, 0)
|
|
|
|
+ for cursor.Next(ctx) {
|
|
|
|
+ var admin model.Admin
|
|
|
|
+ err := cursor.Decode(&admin)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ admins = append(admins, &admin)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if err := cursor.Err(); err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return admins, nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// GetServerStatus 获取服务器状态
|
|
|
|
+func (a *Admin) GetServerStatus(ctx context.Context) ([]*models.PlayerServerLoadStat, error) {
|
|
|
|
+ // 执行查询
|
|
|
|
+ cursor, err := mdb.MDB.Collection(constant.CNameServerLoadStat).Find(ctx, bson.M{})
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ defer func() {
|
|
|
|
+ if closeErr := cursor.Close(ctx); closeErr != nil {
|
|
|
|
+ log.Printf("Error closing cursor: %v", closeErr)
|
|
|
|
+ }
|
|
|
|
+ }()
|
|
|
|
+ // 解析结果
|
|
|
|
+ admins := make([]*models.PlayerServerLoadStat, 0)
|
|
|
|
+ for cursor.Next(ctx) {
|
|
|
|
+ var admin models.PlayerServerLoadStat
|
|
|
|
+ err := cursor.Decode(&admin)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ admins = append(admins, &admin)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if err := cursor.Err(); err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ return admins, nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 辅助函数:对 username 进行脱敏处理
|
|
|
|
+func maskUsername(username string) string {
|
|
|
|
+ if username == "" {
|
|
|
|
+ return ""
|
|
|
|
+ }
|
|
|
|
+ return strings.Repeat("*", len(username))
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 辅助函数:对正则表达式进行转义
|
|
|
|
+func escapeRegex(s string) string {
|
|
|
|
+ return regexp.QuoteMeta(s)
|
|
|
|
+}
|