- Add YggdrasilErrorResponse struct and standard error codes for protocol compliance - Change UUID storage from varchar(36) to varchar(32) for unsigned format - Add utility functions: GenerateUUID, FormatUUIDToNoDash, RandomHex - Support unsigned query parameter in GetProfileByUUID endpoint - Improve refresh token response with available profiles list - Fix key pair retrieval to use correct database column (rsa_private_key) - Update UUID validator to accept both 32-char and 36-char formats - Add SignStringWithProfileRSA method for profile-specific signing - Fix profile assignment validation in refresh token flow
137 lines
4.8 KiB
Go
137 lines
4.8 KiB
Go
package service
|
||
|
||
import (
|
||
"carrotskin/internal/model"
|
||
"carrotskin/internal/repository"
|
||
"carrotskin/pkg/redis"
|
||
"carrotskin/pkg/utils"
|
||
"context"
|
||
"errors"
|
||
"fmt"
|
||
|
||
"go.uber.org/zap"
|
||
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// yggdrasilServiceComposite 组合服务,保持接口兼容性
|
||
// 将认证、会话、序列化、证书服务组合在一起
|
||
type yggdrasilServiceComposite struct {
|
||
authService *yggdrasilAuthService
|
||
sessionService SessionService
|
||
serializationService SerializationService
|
||
certificateService CertificateService
|
||
profileRepo repository.ProfileRepository
|
||
tokenService TokenService // 使用TokenService接口,不直接依赖TokenRepository
|
||
logger *zap.Logger
|
||
}
|
||
|
||
// NewYggdrasilServiceComposite 创建组合服务实例
|
||
func NewYggdrasilServiceComposite(
|
||
db *gorm.DB,
|
||
userRepo repository.UserRepository,
|
||
profileRepo repository.ProfileRepository,
|
||
yggdrasilRepo repository.YggdrasilRepository,
|
||
signatureService *SignatureService,
|
||
redisClient *redis.Client,
|
||
logger *zap.Logger,
|
||
tokenService TokenService, // 新增:TokenService接口
|
||
) YggdrasilService {
|
||
// 创建各个专门的服务
|
||
authService := NewYggdrasilAuthService(db, userRepo, yggdrasilRepo, logger)
|
||
sessionService := NewSessionService(redisClient, logger)
|
||
serializationService := NewSerializationService(
|
||
repository.NewTextureRepository(db),
|
||
signatureService,
|
||
logger,
|
||
)
|
||
certificateService := NewCertificateService(profileRepo, signatureService, logger)
|
||
|
||
return &yggdrasilServiceComposite{
|
||
authService: authService,
|
||
sessionService: sessionService,
|
||
serializationService: serializationService,
|
||
certificateService: certificateService,
|
||
profileRepo: profileRepo,
|
||
tokenService: tokenService,
|
||
logger: logger,
|
||
}
|
||
}
|
||
|
||
// GetUserIDByEmail 获取用户ID(通过邮箱)
|
||
func (s *yggdrasilServiceComposite) GetUserIDByEmail(ctx context.Context, email string) (int64, error) {
|
||
return s.authService.GetUserIDByEmail(ctx, email)
|
||
}
|
||
|
||
// VerifyPassword 验证密码
|
||
func (s *yggdrasilServiceComposite) VerifyPassword(ctx context.Context, password string, userID int64) error {
|
||
return s.authService.VerifyPassword(ctx, password, userID)
|
||
}
|
||
|
||
// ResetYggdrasilPassword 重置Yggdrasil密码
|
||
func (s *yggdrasilServiceComposite) ResetYggdrasilPassword(ctx context.Context, userID int64) (string, error) {
|
||
return s.authService.ResetYggdrasilPassword(ctx, userID)
|
||
}
|
||
|
||
// JoinServer 加入服务器
|
||
func (s *yggdrasilServiceComposite) JoinServer(ctx context.Context, serverID, accessToken, selectedProfile, ip string) error {
|
||
// 通过TokenService验证Token并获取UUID
|
||
uuid, err := s.tokenService.GetUUIDByAccessToken(ctx, accessToken)
|
||
if err != nil {
|
||
s.logger.Error("验证Token失败",
|
||
zap.Error(err),
|
||
zap.String("accessToken", accessToken),
|
||
)
|
||
return fmt.Errorf("验证Token失败: %w", err)
|
||
}
|
||
|
||
// 确保UUID是32位无符号格式(用于向后兼容)
|
||
formattedProfile := utils.FormatUUIDToNoDash(selectedProfile)
|
||
if uuid != formattedProfile {
|
||
return errors.New("selectedProfile与Token不匹配")
|
||
}
|
||
|
||
// 获取Profile以获取用户名
|
||
profile, err := s.profileRepo.FindByUUID(ctx, formattedProfile)
|
||
if err != nil {
|
||
s.logger.Error("获取Profile失败",
|
||
zap.Error(err),
|
||
zap.String("uuid", formattedProfile),
|
||
)
|
||
return fmt.Errorf("获取Profile失败: %w", err)
|
||
}
|
||
|
||
// 使用会话服务创建会话
|
||
return s.sessionService.CreateSession(ctx, serverID, accessToken, profile.Name, formattedProfile, ip)
|
||
}
|
||
|
||
// HasJoinedServer 验证玩家是否已加入服务器
|
||
func (s *yggdrasilServiceComposite) HasJoinedServer(ctx context.Context, serverID, username, ip string) error {
|
||
return s.sessionService.ValidateSession(ctx, serverID, username, ip)
|
||
}
|
||
|
||
// SerializeProfile 序列化档案
|
||
func (s *yggdrasilServiceComposite) SerializeProfile(ctx context.Context, profile model.Profile) map[string]interface{} {
|
||
return s.serializationService.SerializeProfile(ctx, profile)
|
||
}
|
||
|
||
// SerializeProfileWithUnsigned 序列化档案(支持unsigned参数)
|
||
func (s *yggdrasilServiceComposite) SerializeProfileWithUnsigned(ctx context.Context, profile model.Profile, unsigned bool) map[string]interface{} {
|
||
return s.serializationService.SerializeProfileWithUnsigned(ctx, profile, unsigned)
|
||
}
|
||
|
||
// SerializeUser 序列化用户
|
||
func (s *yggdrasilServiceComposite) SerializeUser(ctx context.Context, user *model.User, uuid string) map[string]interface{} {
|
||
return s.serializationService.SerializeUser(ctx, user, uuid)
|
||
}
|
||
|
||
// GeneratePlayerCertificate 生成玩家证书
|
||
func (s *yggdrasilServiceComposite) GeneratePlayerCertificate(ctx context.Context, uuid string) (map[string]interface{}, error) {
|
||
return s.certificateService.GeneratePlayerCertificate(ctx, uuid)
|
||
}
|
||
|
||
// GetPublicKey 获取公钥
|
||
func (s *yggdrasilServiceComposite) GetPublicKey(ctx context.Context) (string, error) {
|
||
return s.certificateService.GetPublicKey(ctx)
|
||
}
|