222 lines
6.2 KiB
Go
222 lines
6.2 KiB
Go
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
|
||
}
|