topfans/backend/services/socialService/provider/social_provider.go
2026-04-07 22:29:48 +08:00

450 lines
14 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"
"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
}