topfans/backend/services/starbookService/provider/starbook_provider.go
2026-04-20 16:00:10 +08:00

222 lines
6.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package provider
import (
"context"
"fmt"
"strconv"
"time"
"dubbo.apache.org/dubbo-go/v3/common/constant"
"github.com/topfans/backend/pkg/logger"
pb "github.com/topfans/backend/pkg/proto/starbook"
pbCommon "github.com/topfans/backend/pkg/proto/common"
"github.com/topfans/backend/services/starbookService/service"
"go.uber.org/zap"
)
// StarbookProvider 星册服务Provider实现
// 实现 Triple 协议生成的 StarbookServiceHandler 接口
type StarbookProvider struct {
starbookService service.StarbookService
}
// 确保 StarbookProvider 实现了 StarbookServiceHandler 接口
var _ pb.StarbookServiceHandler = (*StarbookProvider)(nil)
// NewStarbookProvider 创建星册服务Provider实例
func NewStarbookProvider(starbookService service.StarbookService) *StarbookProvider {
return &StarbookProvider{
starbookService: starbookService,
}
}
// GetStarbookHome 获取星册首页
func (p *StarbookProvider) GetStarbookHome(ctx context.Context, req *pb.GetStarbookHomeRequest) (*pb.GetStarbookHomeResponse, error) {
userID, starID, err := extractUserInfoFromDubboAttachments(ctx)
if err != nil {
return &pb.GetStarbookHomeResponse{
Base: &pbCommon.BaseResponse{
Code: pbCommon.StatusCode_STATUS_UNAUTHORIZED,
Message: "user authentication required",
Timestamp: 0,
},
}, err
}
resp, err := p.starbookService.GetStarbookHome(userID, starID)
if err != nil {
logger.Logger.Error("GetStarbookHome failed",
zap.Error(err),
)
return &pb.GetStarbookHomeResponse{
Base: &pbCommon.BaseResponse{
Code: toStatusCode(err),
Message: err.Error(),
Timestamp: time.Now().UnixMilli(),
},
}, err
}
return resp, nil
}
// GetStarbookItems 获取星册藏品列表
func (p *StarbookProvider) GetStarbookItems(ctx context.Context, req *pb.GetStarbookItemsRequest) (*pb.GetStarbookItemsResponse, error) {
userID, starID, err := extractUserInfoFromDubboAttachments(ctx)
if err != nil {
return &pb.GetStarbookItemsResponse{
Base: &pbCommon.BaseResponse{
Code: pbCommon.StatusCode_STATUS_UNAUTHORIZED,
Message: "user authentication required",
Timestamp: 0,
},
}, err
}
resp, err := p.starbookService.GetStarbookItems(req, userID, starID)
if err != nil {
logger.Logger.Error("GetStarbookItems failed",
zap.Error(err),
)
return &pb.GetStarbookItemsResponse{
Base: &pbCommon.BaseResponse{
Code: toStatusCode(err),
Message: err.Error(),
Timestamp: time.Now().UnixMilli(),
},
}, err
}
return resp, nil
}
// extractUserInfoFromDubboAttachments 从 Dubbo attachments 中提取用户信息
// 网关调用:网关已验证 Token 并将 user_id 和 star_id 通过 attachments 传递
func extractUserInfoFromDubboAttachments(ctx context.Context) (int64, int64, error) {
logger.Logger.Info("=== extractUserInfoFromDubboAttachments called ===")
// 使用 constant.AttachmentKey 获取 Dubbo attachments
attachments := ctx.Value(constant.AttachmentKey)
logger.Logger.Info("ctx.Value(constant.AttachmentKey) result",
zap.Any("attachments", attachments),
zap.String("type", fmt.Sprintf("%T", attachments)),
)
if attachments != nil {
logger.Logger.Info("Attachments found in context")
if attMap, ok := attachments.(map[string]interface{}); ok {
logger.Logger.Info("Attachments is map[string]interface{}",
zap.Int("map_size", len(attMap)))
userID, starID := extractUserInfoFromMap(attMap)
if userID > 0 && starID > 0 {
logger.Logger.Info("Successfully extracted user info",
zap.Int64("user_id", userID),
zap.Int64("star_id", starID),
)
return userID, starID, nil
}
logger.Logger.Warn("Extracted zero user_id or star_id",
zap.Int64("user_id", userID),
zap.Int64("star_id", starID),
)
} else {
logger.Logger.Warn("Attachments is not map[string]interface{}",
zap.String("actual_type", fmt.Sprintf("%T", attachments)),
zap.Any("value", attachments),
)
}
} else {
logger.Logger.Warn("No attachments found in context")
// 尝试打印所有 context 的值
logger.Logger.Warn("Context type", zap.String("type", fmt.Sprintf("%T", ctx)))
}
return 0, 0, fmt.Errorf("user info not found in Dubbo attachments (expected user_id and star_id from gateway)")
}
// getContextKeys 获取 context 中所有的 key
func getContextKeys(ctx context.Context) []string {
keys := make([]string, 0)
// 直接打印 ctx 类型
logger.Logger.Debug("Context type", zap.String("type", fmt.Sprintf("%T", ctx)))
return keys
}
// getContextValues 遍历 context 中的一些已知值
func getContextValues(ctx context.Context) map[string]interface{} {
result := make(map[string]interface{})
// 检查 constant.AttachmentKey
if v := ctx.Value(constant.AttachmentKey); v != nil {
result["AttachmentKey"] = v
}
return result
}
// extractUserInfoFromMap 从 map 中提取 user_id 和 star_id
// 支持多种类型int64, float64, string
func extractUserInfoFromMap(attMap map[string]interface{}) (int64, int64) {
var userID, starID int64
// 打印所有 key 和 value
for k, v := range attMap {
logger.Logger.Debug("Attachment map entry",
zap.String("key", k),
zap.Any("value", v),
zap.String("type", fmt.Sprintf("%T", v)),
)
}
// 提取 user_id
if v, ok := attMap["user_id"]; ok {
userID = parseIntValue(v)
}
// 提取 star_id
if v, ok := attMap["star_id"]; ok {
starID = parseIntValue(v)
}
return userID, starID
}
// parseIntValue 解析不同类型的整数值
func parseIntValue(v interface{}) int64 {
switch val := v.(type) {
case int64:
return val
case int:
return int64(val)
case float64:
return int64(val)
case string:
if i, err := strconv.ParseInt(val, 10, 64); err == nil {
return i
}
case []string:
if len(val) > 0 {
if i, err := strconv.ParseInt(val[0], 10, 64); err == nil {
return i
}
}
case []interface{}:
if len(val) > 0 {
if s, ok := val[0].(string); ok {
if i, err := strconv.ParseInt(s, 10, 64); err == nil {
return i
}
}
}
}
return 0
}
// toStatusCode 将错误转换为Proto状态码
func toStatusCode(err error) pbCommon.StatusCode {
if err == nil {
return pbCommon.StatusCode_STATUS_OK
}
// 简化处理,实际应该使用 appErrors.ToStatusCode
return pbCommon.StatusCode_STATUS_INTERNAL_ERROR
}