157 lines
4.0 KiB
Go
157 lines
4.0 KiB
Go
|
|
package service
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"carrotskin/internal/model"
|
|||
|
|
"carrotskin/internal/repository"
|
|||
|
|
"context"
|
|||
|
|
"encoding/base64"
|
|||
|
|
"time"
|
|||
|
|
|
|||
|
|
"go.uber.org/zap"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// SerializationService 序列化服务接口
|
|||
|
|
type SerializationService interface {
|
|||
|
|
// SerializeProfile 序列化档案为Yggdrasil格式
|
|||
|
|
SerializeProfile(ctx context.Context, profile model.Profile) map[string]interface{}
|
|||
|
|
// SerializeUser 序列化用户为Yggdrasil格式
|
|||
|
|
SerializeUser(ctx context.Context, user *model.User, uuid string) map[string]interface{}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Property Yggdrasil属性
|
|||
|
|
type Property struct {
|
|||
|
|
Name string `json:"name"`
|
|||
|
|
Value string `json:"value"`
|
|||
|
|
Signature string `json:"signature,omitempty"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// yggdrasilSerializationService 序列化服务实现
|
|||
|
|
type yggdrasilSerializationService struct {
|
|||
|
|
textureRepo repository.TextureRepository
|
|||
|
|
signatureService *signatureService
|
|||
|
|
logger *zap.Logger
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NewSerializationService 创建序列化服务实例
|
|||
|
|
func NewSerializationService(
|
|||
|
|
textureRepo repository.TextureRepository,
|
|||
|
|
signatureService *signatureService,
|
|||
|
|
logger *zap.Logger,
|
|||
|
|
) SerializationService {
|
|||
|
|
return &yggdrasilSerializationService{
|
|||
|
|
textureRepo: textureRepo,
|
|||
|
|
signatureService: signatureService,
|
|||
|
|
logger: logger,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// SerializeProfile 序列化档案为Yggdrasil格式
|
|||
|
|
func (s *yggdrasilSerializationService) SerializeProfile(ctx context.Context, profile model.Profile) map[string]interface{} {
|
|||
|
|
// 创建基本材质数据
|
|||
|
|
texturesMap := make(map[string]interface{})
|
|||
|
|
textures := map[string]interface{}{
|
|||
|
|
"timestamp": time.Now().UnixMilli(),
|
|||
|
|
"profileId": profile.UUID,
|
|||
|
|
"profileName": profile.Name,
|
|||
|
|
"textures": texturesMap,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 处理皮肤
|
|||
|
|
if profile.SkinID != nil {
|
|||
|
|
skin, err := s.textureRepo.FindByID(*profile.SkinID)
|
|||
|
|
if err != nil {
|
|||
|
|
s.logger.Error("获取皮肤失败",
|
|||
|
|
zap.Error(err),
|
|||
|
|
zap.Int64("skinID", *profile.SkinID),
|
|||
|
|
)
|
|||
|
|
} else if skin != nil {
|
|||
|
|
texturesMap["SKIN"] = map[string]interface{}{
|
|||
|
|
"url": skin.URL,
|
|||
|
|
"metadata": skin.Size,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 处理披风
|
|||
|
|
if profile.CapeID != nil {
|
|||
|
|
cape, err := s.textureRepo.FindByID(*profile.CapeID)
|
|||
|
|
if err != nil {
|
|||
|
|
s.logger.Error("获取披风失败",
|
|||
|
|
zap.Error(err),
|
|||
|
|
zap.Int64("capeID", *profile.CapeID),
|
|||
|
|
)
|
|||
|
|
} else if cape != nil {
|
|||
|
|
texturesMap["CAPE"] = map[string]interface{}{
|
|||
|
|
"url": cape.URL,
|
|||
|
|
"metadata": cape.Size,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 将textures编码为base64
|
|||
|
|
bytes, err := json.Marshal(textures)
|
|||
|
|
if err != nil {
|
|||
|
|
s.logger.Error("序列化textures失败",
|
|||
|
|
zap.Error(err),
|
|||
|
|
zap.String("profileUUID", profile.UUID),
|
|||
|
|
)
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
textureData := base64.StdEncoding.EncodeToString(bytes)
|
|||
|
|
signature, err := s.signatureService.SignStringWithSHA1withRSA(textureData)
|
|||
|
|
if err != nil {
|
|||
|
|
s.logger.Error("签名textures失败",
|
|||
|
|
zap.Error(err),
|
|||
|
|
zap.String("profileUUID", profile.UUID),
|
|||
|
|
)
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建结果
|
|||
|
|
data := map[string]interface{}{
|
|||
|
|
"id": profile.UUID,
|
|||
|
|
"name": profile.Name,
|
|||
|
|
"properties": []Property{
|
|||
|
|
{
|
|||
|
|
Name: "textures",
|
|||
|
|
Value: textureData,
|
|||
|
|
Signature: signature,
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
return data
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// SerializeUser 序列化用户为Yggdrasil格式
|
|||
|
|
func (s *yggdrasilSerializationService) SerializeUser(ctx context.Context, user *model.User, uuid string) map[string]interface{} {
|
|||
|
|
if user == nil {
|
|||
|
|
s.logger.Error("尝试序列化空用户")
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
data := map[string]interface{}{
|
|||
|
|
"id": uuid,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 正确处理 *datatypes.JSON 指针类型
|
|||
|
|
// 如果 Properties 为 nil,则设置为 nil;否则解引用并解析为 JSON 值
|
|||
|
|
if user.Properties == nil {
|
|||
|
|
data["properties"] = nil
|
|||
|
|
} else {
|
|||
|
|
// datatypes.JSON 是 []byte 类型,需要解析为实际的 JSON 值
|
|||
|
|
var propertiesValue interface{}
|
|||
|
|
if err := json.Unmarshal(*user.Properties, &propertiesValue); err != nil {
|
|||
|
|
s.logger.Warn("解析用户Properties失败,使用空值",
|
|||
|
|
zap.Error(err),
|
|||
|
|
zap.Int64("userID", user.ID),
|
|||
|
|
)
|
|||
|
|
data["properties"] = nil
|
|||
|
|
} else {
|
|||
|
|
data["properties"] = propertiesValue
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return data
|
|||
|
|
}
|