450 lines
14 KiB
Go
450 lines
14 KiB
Go
package provider
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"strconv"
|
||
"time"
|
||
|
||
"dubbo.apache.org/dubbo-go/v3/common/constant"
|
||
"github.com/topfans/backend/pkg/logger"
|
||
"github.com/topfans/backend/pkg/proto/common"
|
||
pb "github.com/topfans/backend/pkg/proto/social"
|
||
"github.com/topfans/backend/services/socialService/service"
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
// SocialProvider 社交服务Provider实现
|
||
// 实现 Triple 协议生成的 SocialServiceHandler 接口
|
||
type SocialProvider struct {
|
||
friendService service.FriendService
|
||
assetLikeService *service.AssetLikeService
|
||
}
|
||
|
||
// 确保 SocialProvider 实现了 SocialServiceHandler 接口
|
||
var _ pb.SocialServiceHandler = (*SocialProvider)(nil)
|
||
|
||
// NewSocialProvider 创建社交服务Provider实例
|
||
func NewSocialProvider(friendService service.FriendService, assetLikeService *service.AssetLikeService) *SocialProvider {
|
||
return &SocialProvider{
|
||
friendService: friendService,
|
||
assetLikeService: assetLikeService,
|
||
}
|
||
}
|
||
|
||
// ========== 好友请求相关 ==========
|
||
|
||
// SendFriendRequest 发送好友请求
|
||
func (p *SocialProvider) SendFriendRequest(ctx context.Context, req *pb.SendFriendRequestRequest) (*pb.SendFriendRequestResponse, error) {
|
||
// 从上下文获取用户信息(由middleware注入)
|
||
userID, starID, err := extractUserInfo(ctx)
|
||
if err != nil {
|
||
logger.Logger.Warn("Failed to extract user info from context", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
logger.Logger.Debug("SendFriendRequest called",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Int64("friend_user_id", req.FriendUserId),
|
||
)
|
||
|
||
return p.friendService.SendFriendRequest(ctx, req, userID, starID)
|
||
}
|
||
|
||
// GetFriendRequests 获取好友请求列表
|
||
func (p *SocialProvider) GetFriendRequests(ctx context.Context, req *pb.GetFriendRequestsRequest) (*pb.GetFriendRequestsResponse, error) {
|
||
// 从上下文获取用户信息
|
||
userID, starID, err := extractUserInfo(ctx)
|
||
if err != nil {
|
||
logger.Logger.Warn("Failed to extract user info from context", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
logger.Logger.Debug("GetFriendRequests called",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.String("type", req.Type),
|
||
zap.String("status", req.Status),
|
||
)
|
||
|
||
return p.friendService.GetFriendRequests(ctx, req, userID, starID)
|
||
}
|
||
|
||
// HandleFriendRequest 处理好友请求(接受/拒绝)
|
||
func (p *SocialProvider) HandleFriendRequest(ctx context.Context, req *pb.HandleFriendRequestRequest) (*pb.HandleFriendRequestResponse, error) {
|
||
// 从上下文获取用户信息
|
||
userID, starID, err := extractUserInfo(ctx)
|
||
if err != nil {
|
||
logger.Logger.Warn("Failed to extract user info from context", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
logger.Logger.Debug("HandleFriendRequest called",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Int64("request_id", req.RequestId),
|
||
zap.String("action", req.Action),
|
||
)
|
||
|
||
return p.friendService.HandleFriendRequest(ctx, req, userID, starID)
|
||
}
|
||
|
||
// ========== 好友关系相关 ==========
|
||
|
||
// GetFriendList 获取好友列表
|
||
func (p *SocialProvider) GetFriendList(ctx context.Context, req *pb.GetFriendListRequest) (*pb.GetFriendListResponse, error) {
|
||
// 从上下文获取用户信息
|
||
userID, starID, err := extractUserInfo(ctx)
|
||
if err != nil {
|
||
logger.Logger.Warn("Failed to extract user info from context", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
logger.Logger.Debug("GetFriendList called",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.String("keyword", req.Keyword),
|
||
)
|
||
|
||
return p.friendService.GetFriendList(ctx, req, userID, starID)
|
||
}
|
||
|
||
// DeleteFriend 删除好友
|
||
func (p *SocialProvider) DeleteFriend(ctx context.Context, req *pb.DeleteFriendRequest) (*pb.DeleteFriendResponse, error) {
|
||
// 从上下文获取用户信息
|
||
userID, starID, err := extractUserInfo(ctx)
|
||
if err != nil {
|
||
logger.Logger.Warn("Failed to extract user info from context", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
logger.Logger.Debug("DeleteFriend called",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Int64("friend_user_id", req.FriendUserId),
|
||
)
|
||
|
||
return p.friendService.DeleteFriend(ctx, req, userID, starID)
|
||
}
|
||
|
||
// SetFriendRemark 设置好友备注
|
||
func (p *SocialProvider) SetFriendRemark(ctx context.Context, req *pb.SetFriendRemarkRequest) (*pb.SetFriendRemarkResponse, error) {
|
||
// 从上下文获取用户信息
|
||
userID, starID, err := extractUserInfo(ctx)
|
||
if err != nil {
|
||
logger.Logger.Warn("Failed to extract user info from context", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
logger.Logger.Debug("SetFriendRemark called",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Int64("friend_user_id", req.FriendUserId),
|
||
)
|
||
|
||
return p.friendService.SetFriendRemark(ctx, req, userID, starID)
|
||
}
|
||
|
||
// CheckFriendship 检查好友关系
|
||
func (p *SocialProvider) CheckFriendship(ctx context.Context, req *pb.CheckFriendshipRequest) (*pb.CheckFriendshipResponse, error) {
|
||
logger.Logger.Debug("CheckFriendship called",
|
||
zap.Int64("user_id", req.UserId),
|
||
zap.Int64("friend_user_id", req.FriendUserId),
|
||
)
|
||
|
||
return p.friendService.CheckFriendship(ctx, req)
|
||
}
|
||
|
||
// GetFriendCount 获取好友数量
|
||
func (p *SocialProvider) GetFriendCount(ctx context.Context, req *pb.GetFriendCountRequest) (*pb.GetFriendCountResponse, error) {
|
||
// 从上下文获取用户信息
|
||
userID, starID, err := extractUserInfo(ctx)
|
||
if err != nil {
|
||
logger.Logger.Warn("Failed to extract user info from context", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
logger.Logger.Debug("GetFriendCount called",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
)
|
||
|
||
return p.friendService.GetFriendCount(ctx, req, userID, starID)
|
||
}
|
||
|
||
// ========== 辅助方法 ==========
|
||
|
||
// SearchUserForFriend 查找用户信息(用于加好友)
|
||
func (p *SocialProvider) SearchUserForFriend(ctx context.Context, req *pb.SearchUserForFriendRequest) (*pb.SearchUserForFriendResponse, error) {
|
||
// 从上下文获取用户信息
|
||
userID, starID, err := extractUserInfo(ctx)
|
||
if err != nil {
|
||
logger.Logger.Warn("Failed to extract user info from context", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
logger.Logger.Debug("SearchUserForFriend called",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Int64("friend_fan_profile_id", req.GetFriendFanProfileId()),
|
||
)
|
||
|
||
return p.friendService.SearchUserForFriend(ctx, req, userID, starID)
|
||
}
|
||
|
||
// GetUsersPaged 获取分页用户列表(同一明星身份下)
|
||
func (p *SocialProvider) GetUsersPaged(ctx context.Context, req *pb.GetUsersPagedRequest) (*pb.GetUsersPagedResponse, error) {
|
||
userID, starID, err := extractUserInfo(ctx)
|
||
if err != nil {
|
||
logger.Logger.Warn("Failed to extract user info from context", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
logger.Logger.Debug("GetUsersPaged called",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Int32("page", req.Page),
|
||
zap.Int32("page_size", req.PageSize),
|
||
)
|
||
|
||
return p.friendService.GetUsersPaged(ctx, req, userID, starID)
|
||
}
|
||
|
||
// GetRandomUsers 获取随机用户(同一明星下)
|
||
func (p *SocialProvider) GetRandomUsers(ctx context.Context, req *pb.GetRandomUsersRequest) (*pb.GetRandomUsersResponse, error) {
|
||
// 从上下文获取用户信息
|
||
userID, starID, err := extractUserInfo(ctx)
|
||
if err != nil {
|
||
logger.Logger.Warn("Failed to extract user info from context", zap.Error(err))
|
||
return nil, err
|
||
}
|
||
|
||
logger.Logger.Debug("GetRandomUsers called",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Int32("count", req.Count),
|
||
)
|
||
|
||
return p.friendService.GetRandomUsers(ctx, req, userID, starID)
|
||
}
|
||
|
||
// ========== 资产点赞相关 ==========
|
||
|
||
// LikeAsset 点赞资产
|
||
func (p *SocialProvider) LikeAsset(ctx context.Context, req *pb.LikeAssetRequest) (*pb.LikeAssetResponse, error) {
|
||
// 从上下文获取用户信息
|
||
userID, starID, err := extractUserInfo(ctx)
|
||
if err != nil {
|
||
logger.Logger.Warn("Failed to extract user info from context", zap.Error(err))
|
||
return &pb.LikeAssetResponse{
|
||
Base: &common.BaseResponse{
|
||
Code: common.StatusCode_STATUS_UNAUTHORIZED,
|
||
Message: "Unauthorized: " + err.Error(),
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
logger.Logger.Debug("LikeAsset called",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Int64("asset_id", req.AssetId),
|
||
)
|
||
|
||
// 调用业务逻辑层
|
||
if err := p.assetLikeService.LikeAsset(ctx, req.AssetId, userID, starID); err != nil {
|
||
logger.Logger.Error("Failed to like asset",
|
||
zap.Error(err),
|
||
zap.Int64("asset_id", req.AssetId),
|
||
zap.Int64("user_id", userID),
|
||
)
|
||
return &pb.LikeAssetResponse{
|
||
Base: &common.BaseResponse{
|
||
Code: common.StatusCode_STATUS_INTERNAL_ERROR,
|
||
Message: "Failed to like asset: " + err.Error(),
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
return &pb.LikeAssetResponse{
|
||
Base: &common.BaseResponse{
|
||
Code: common.StatusCode_STATUS_OK,
|
||
Message: "Successfully liked asset",
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// UnlikeAsset 取消点赞资产
|
||
func (p *SocialProvider) UnlikeAsset(ctx context.Context, req *pb.UnlikeAssetRequest) (*pb.UnlikeAssetResponse, error) {
|
||
// 从上下文获取用户信息
|
||
userID, starID, err := extractUserInfo(ctx)
|
||
if err != nil {
|
||
logger.Logger.Warn("Failed to extract user info from context", zap.Error(err))
|
||
return &pb.UnlikeAssetResponse{
|
||
Base: &common.BaseResponse{
|
||
Code: common.StatusCode_STATUS_UNAUTHORIZED,
|
||
Message: "Unauthorized: " + err.Error(),
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
logger.Logger.Debug("UnlikeAsset called",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Int64("asset_id", req.AssetId),
|
||
)
|
||
|
||
// 调用业务逻辑层
|
||
if err := p.assetLikeService.UnlikeAsset(ctx, req.AssetId, userID, starID); err != nil {
|
||
logger.Logger.Error("Failed to unlike asset",
|
||
zap.Error(err),
|
||
zap.Int64("asset_id", req.AssetId),
|
||
zap.Int64("user_id", userID),
|
||
)
|
||
return &pb.UnlikeAssetResponse{
|
||
Base: &common.BaseResponse{
|
||
Code: common.StatusCode_STATUS_INTERNAL_ERROR,
|
||
Message: "Failed to unlike asset: " + err.Error(),
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
return &pb.UnlikeAssetResponse{
|
||
Base: &common.BaseResponse{
|
||
Code: common.StatusCode_STATUS_OK,
|
||
Message: "Successfully unliked asset",
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// CheckAssetLike 检查是否已点赞资产
|
||
func (p *SocialProvider) CheckAssetLike(ctx context.Context, req *pb.CheckAssetLikeRequest) (*pb.CheckAssetLikeResponse, error) {
|
||
// 从上下文获取用户信息
|
||
userID, starID, err := extractUserInfo(ctx)
|
||
if err != nil {
|
||
logger.Logger.Warn("Failed to extract user info from context", zap.Error(err))
|
||
return &pb.CheckAssetLikeResponse{
|
||
Base: &common.BaseResponse{
|
||
Code: common.StatusCode_STATUS_UNAUTHORIZED,
|
||
Message: "Unauthorized: " + err.Error(),
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
IsLiked: false,
|
||
}, nil
|
||
}
|
||
|
||
logger.Logger.Debug("CheckAssetLike called",
|
||
zap.Int64("user_id", userID),
|
||
zap.Int64("star_id", starID),
|
||
zap.Int64("asset_id", req.AssetId),
|
||
)
|
||
|
||
// 调用业务逻辑层
|
||
isLiked, err := p.assetLikeService.CheckAssetLike(ctx, req.AssetId, userID, starID)
|
||
if err != nil {
|
||
logger.Logger.Error("Failed to check asset like",
|
||
zap.Error(err),
|
||
zap.Int64("asset_id", req.AssetId),
|
||
zap.Int64("user_id", userID),
|
||
)
|
||
return &pb.CheckAssetLikeResponse{
|
||
Base: &common.BaseResponse{
|
||
Code: common.StatusCode_STATUS_INTERNAL_ERROR,
|
||
Message: "Failed to check asset like: " + err.Error(),
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
IsLiked: false,
|
||
}, nil
|
||
}
|
||
|
||
return &pb.CheckAssetLikeResponse{
|
||
Base: &common.BaseResponse{
|
||
Code: common.StatusCode_STATUS_OK,
|
||
Message: "Successfully checked asset like status",
|
||
Timestamp: time.Now().UnixMilli(),
|
||
},
|
||
IsLiked: isLiked,
|
||
}, nil
|
||
}
|
||
|
||
// extractUserInfo 从 Dubbo attachments 中提取用户信息
|
||
// 网关调用:网关已验证 Token 并将 user_id 和 star_id 通过 attachments 传递
|
||
func extractUserInfo(ctx context.Context) (int64, int64, error) {
|
||
logger.Logger.Debug("Extracting user info from Dubbo attachments")
|
||
|
||
// 使用正确的 constant.AttachmentKey 获取 Dubbo attachments
|
||
if attachments := ctx.Value(constant.AttachmentKey); attachments != nil {
|
||
logger.Logger.Debug("Found attachments in context", zap.Any("attachments", attachments))
|
||
|
||
if attMap, ok := attachments.(map[string]interface{}); ok {
|
||
userID, starID := extractUserInfoFromMap(attMap)
|
||
if userID > 0 && starID > 0 {
|
||
logger.Logger.Debug("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 a map[string]interface{}",
|
||
zap.String("type", fmt.Sprintf("%T", attachments)),
|
||
)
|
||
}
|
||
} else {
|
||
logger.Logger.Warn("No attachments found in context")
|
||
}
|
||
|
||
return 0, 0, fmt.Errorf("user info not found in Dubbo attachments (expected user_id and star_id from gateway)")
|
||
}
|
||
|
||
// extractUserInfoFromMap 从 map 中提取 user_id 和 star_id
|
||
// 支持多种类型:int64, float64, string
|
||
func extractUserInfoFromMap(attMap map[string]interface{}) (int64, int64) {
|
||
var userID, starID int64
|
||
|
||
// 提取 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
|
||
}
|
||
}
|
||
}
|
||
return 0
|
||
}
|