diff --git a/README.md b/README.md index 9cbd1f9..86e649a 100755 --- a/README.md +++ b/README.md @@ -28,3 +28,8 @@ go get github.com/ClubWeGo/videomicro@latest go get github.com/ClubWeGo/usermicro@latest go get github.com/ClubWeGo/relationmicro@latest + + + +# 说明 +1. 当前注册用户时,前端并未提供个人参数配置的能力,也没有提供更新用户信息的能力,所以在core.register_server处写死了初始化的用户背景图像和头像。在配置本项目时,请将对应文件名换成minio中存储的文件名。 diff --git a/biz/handler/core/feed_server.go b/biz/handler/core/feed_server.go index 7333a70..d573193 100755 --- a/biz/handler/core/feed_server.go +++ b/biz/handler/core/feed_server.go @@ -4,11 +4,12 @@ package core import ( "context" + "log" "time" core "github.com/ClubWeGo/douyin/biz/model/core" "github.com/ClubWeGo/douyin/kitex_server" - "github.com/ClubWeGo/videomicro/kitex_gen/videomicro" + "github.com/ClubWeGo/douyin/tools" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/protocol/consts" ) @@ -24,67 +25,45 @@ func FeedMethod(ctx context.Context, c *app.RequestContext) { return } + // TODO : 记录ip地址和注册api调用次数,限制统一设备短时间太多的请求,预防爬虫。 + msgsucceed := "获取视频流成功" msgFailed := "获取视频流失败" resp := new(core.FeedResp) + // 字段处理 // 目前该api无需token,后续增加登录定制化内容则需根据token获取其他参数 - // var token string - // if req.Token != nil { // 可选字段,需要验证是否存在,判断对应指针是否存在 - // token = *req.Token - // } + var currentUserId int64 + if req.Token != nil { // 可选字段,需要验证是否存在,判断对应指针是否存在 + _, currentUserId, err = tools.ValidateToken(*req.Token) // + if err != nil { + currentUserId = 0 + // "无效Token或Token已失效, 此处不做约束,继续执行代码" + } + } var latestTime = time.Now().UnixNano() if req.LatestTime != nil { latestTime = (*req.LatestTime) * 1e6 // app传入的是13位毫秒级时间戳,usermicro需传入纳秒级时间戳 } - r, err := kitex_server.Videoclient.GetVideosFeedMethod(context.Background(), &videomicro.GetVideosFeedReq{LatestTime: latestTime, Limit: 30}) + + // TODO : 缓存命中逻辑 + + // 缓存未命中,去后端调api + resultList, nextTime, err := kitex_server.GetFeed(latestTime, currentUserId, 30) if err != nil { + log.Println(err) resp.StatusCode = 1 resp.StatusMsg = &msgFailed c.JSON(consts.StatusOK, resp) return } - // author 相关的查询 - // 批量查询author: Userclient.GetUserSetByIdSetMethod() - - // 批量查询author作品数,Work_count 从video服务 - kitex_server.Videoclient.GetVideoCountSetByIdUserSetMethod(context.Background(), &videomicro.GetVideoCountSetByIdUserSetReq{}) - - // 批量查询 favorite_count, total_favourited 从favorite服务: kitex_server.FavoriteClient.UserFavoriteCountMethod() - - // 批量查询 is_follow, 从relation服务 - - // 批量查询 follow_count, follower_cout 从relation服务 - - // video 相关的查询 - // 批量查询video favorite_count: FavoriteClient.VideoFavoriteCountMethod() ,出入视频id - - // 查询video comment_count : 该接口目前没有 - - // 查询isFavorite: FavoriteClient.FavoriteRelation(),传入当前 查询用户的token对应id 与 视频id - - resp.VideoList = make([]*core.Video, 0) - for _, video := range r.VideoList { - author, _ := kitex_server.GetUser(video.AuthorId) - // 暂时不做处理,错误返回空对象即可 - resp.VideoList = append(resp.VideoList, &core.Video{ - ID: video.Id, - Author: author, - PlayURL: video.PlayUrl, - CoverURL: video.CoverUrl, - FavoriteCount: video.FavoriteCount, - CommentCount: video.CommentCount, - IsFavorite: false, // 需要增加喜欢配置 // TODO:增加 - Title: video.Title, - }) - } + resp.VideoList = resultList resp.StatusMsg = &msgsucceed - nextTimeMs := (*r.NextTime) / 1e6 // 转为毫秒 - resp.NextTime = nextTimeMs + resp.NextTime = nextTime / 1e6 c.JSON(consts.StatusOK, resp) } diff --git a/biz/handler/core/register_server.go b/biz/handler/core/register_server.go index b90017e..df9c107 100755 --- a/biz/handler/core/register_server.go +++ b/biz/handler/core/register_server.go @@ -7,6 +7,7 @@ import ( core "github.com/ClubWeGo/douyin/biz/model/core" "github.com/ClubWeGo/douyin/kitex_server" + "github.com/ClubWeGo/douyin/minio_server" "github.com/ClubWeGo/douyin/tools" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/protocol/consts" @@ -23,12 +24,20 @@ func RegisterMethod(ctx context.Context, c *app.RequestContext) { return } + // TODO : 缓存记录ip地址和注册api调用次数,限制统一设备短时间太多的注册,预防黑灰产。 + // TODO : 注册字段过滤 : 注入,敏感词, + msgsucceed := "注册成功" msgFailed := "注册失败" resp := new(core.RegisterResp) - userid, err := kitex_server.RegisterUser(req.Username, *req.Password) + // 题目要求的基础注册功能 + // userid, err := kitex_server.RegisterUser(req.Username, *req.Password) + // 附带个人设置的注册功能 + var testBackgroundImage = "http://" + minio_server.GlobalConfig.Endpoint + "/douyin/" + "backgroud.jpg" + var testAvatar = "http://" + minio_server.GlobalConfig.Endpoint + "/douyin/" + "0019534761_20.jpg" + userid, err := kitex_server.RegisterUserALL(req.Username, *req.Password, nil, nil, &testBackgroundImage, &testAvatar) if err != nil { resp.StatusCode = 1 resp.StatusMsg = &msgFailed diff --git a/biz/handler/core/user_info_server.go b/biz/handler/core/user_info_server.go index e88770d..c0cc31d 100755 --- a/biz/handler/core/user_info_server.go +++ b/biz/handler/core/user_info_server.go @@ -4,9 +4,11 @@ package core import ( "context" + "sync" core "github.com/ClubWeGo/douyin/biz/model/core" "github.com/ClubWeGo/douyin/kitex_server" + "github.com/ClubWeGo/douyin/tools" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/protocol/consts" ) @@ -27,28 +29,50 @@ func UserInfoMethod(ctx context.Context, c *app.RequestContext) { resp := new(core.UserInfoResp) - // 从User服务拿User信息 - user, err := kitex_server.GetUser(req.UserID) - - // 从video服务拿最新的用户作品数量 - // WorkCountSet, err := kitex_server.GetVideoCountSetByUserIdSet([]int64{req.UserID}) - - // 批量查询 favorite_count, total_favourited 从favorite服务: kitex_server.FavoriteClient.UserFavoriteCountMethod() - // favoriteSet, favoritedSet, err := kitex_server.GetFavoriteCountByUserIdSet([]int64{req.UserID}) - - // 批量查询 is_follow, 从relation服务 - // isFollowSet, err := kitex_server.GetIsFollowSetByUserIdSet([]int64{req.UserID}) - - // 批量查询 follow_count, follower_cout 从relation服务 - + ifValid, currentUserId, err := tools.ValidateToken(req.Token) if err != nil { + msgFailed := "无效Token或Token已失效" resp.StatusCode = 1 resp.StatusMsg = &msgFailed c.JSON(consts.StatusOK, resp) return } + if !ifValid { + msgFailed := "没有权限查看信息" + resp.StatusCode = 1 + resp.StatusMsg = &msgFailed + c.JSON(consts.StatusOK, resp) + return + } + + // 从User服务拿User信息 + wg := &sync.WaitGroup{} + + // 获取最新的用户信息 + respLatestAuthorMap := make(chan map[int64]core.User, 1) + defer close(respLatestAuthorMap) + respLatestAuthorMapError := make(chan []error, 1) + defer close(respLatestAuthorMapError) + wg.Add(1) + go kitex_server.GetUserLatestMap([]int64{req.UserID}, currentUserId, respLatestAuthorMap, wg, respLatestAuthorMapError) + + // 等待数据 + wg.Wait() + // 处理协程错误 + AuthorMap := <-respLatestAuthorMap + + errSlice := <-respLatestAuthorMapError + for _, errItem := range errSlice { + if errItem != nil { + resp.StatusCode = 1 + resp.StatusMsg = &msgFailed + c.JSON(consts.StatusOK, resp) + return + } + } + user := AuthorMap[req.UserID] resp.StatusMsg = &msgsucceed - resp.User = user + resp.User = &user c.JSON(consts.StatusOK, resp) } diff --git a/go.mod b/go.mod index 99a0858..5367164 100755 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/ClubWeGo/favoritemicro v0.0.0-20230218084417-fd4c3433fb21 github.com/ClubWeGo/relationmicro v0.0.0-20230218072559-b17f0bf612ed github.com/ClubWeGo/usermicro v0.0.0-20230218161017-d68d94d1dac8 - github.com/ClubWeGo/videomicro v0.0.0-20230219034144-566fb1b6207a + github.com/ClubWeGo/videomicro v0.0.0-20230219154644-a1694e2abf99 github.com/apache/thrift v0.13.0 github.com/cloudwego/hertz v0.5.2 github.com/cloudwego/kitex v0.4.4 diff --git a/go.sum b/go.sum index 1558ba2..725a11a 100755 --- a/go.sum +++ b/go.sum @@ -28,6 +28,8 @@ github.com/ClubWeGo/videomicro v0.0.0-20230218142838-4e63ecd438ca h1:sp1kKw7f/45 github.com/ClubWeGo/videomicro v0.0.0-20230218142838-4e63ecd438ca/go.mod h1:SJiohnvP4Dk+iAO/cili779usv4VDj8eIX9RUEN4Cms= github.com/ClubWeGo/videomicro v0.0.0-20230219034144-566fb1b6207a h1:+5leZMgy9Nj+aOkPfVKQhIt51XAVHCEW6h6JFbf/+ak= github.com/ClubWeGo/videomicro v0.0.0-20230219034144-566fb1b6207a/go.mod h1:SJiohnvP4Dk+iAO/cili779usv4VDj8eIX9RUEN4Cms= +github.com/ClubWeGo/videomicro v0.0.0-20230219154644-a1694e2abf99 h1:oY0N5NZxvcnaerEKlFiGRp7Nj4xgeREjgl0DMHCR/n8= +github.com/ClubWeGo/videomicro v0.0.0-20230219154644-a1694e2abf99/go.mod h1:SJiohnvP4Dk+iAO/cili779usv4VDj8eIX9RUEN4Cms= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= diff --git a/kitex_server/relationservice.go b/kitex_server/relationservice.go index 4eb71f7..f1210c9 100755 --- a/kitex_server/relationservice.go +++ b/kitex_server/relationservice.go @@ -176,3 +176,8 @@ func VerifyFollowParam(myUid int64, targetUid int64, actionType int32) *string { } return nil } + +// TODO : .GetIsFollowSetByUserIdSet +func GetIsFollowSetByUserIdSet(idSet []int64) (isFollowSet []int64, err error) { + return []int64{}, nil +} diff --git a/kitex_server/userservice.go b/kitex_server/userservice.go index 16f63a0..fbe4700 100755 --- a/kitex_server/userservice.go +++ b/kitex_server/userservice.go @@ -4,35 +4,135 @@ import ( "context" "errors" "strconv" + "sync" "github.com/ClubWeGo/douyin/biz/model/core" "github.com/ClubWeGo/usermicro/kitex_gen/usermicro" + "github.com/ClubWeGo/videomicro/kitex_gen/videomicro" ) -func GetUser(userid int64) (*core.User, error) { - r, err := Userclient.GetUserMethod(context.Background(), &usermicro.GetUserReq{Id: &userid}) +// 工具函数 + +func ConvertUserInfoSetToMap(setData []*usermicro.UserInfo) map[int64]usermicro.UserInfo { + dataMap := make(map[int64]usermicro.UserInfo, len(setData)) + for _, data := range setData { + dataMap[data.Id] = *data + } + return dataMap +} + +func ConvertUserInfoMapToCoreUserMap(mapData map[int64]usermicro.UserInfo) map[int64]core.User { + newMap := make(map[int64]core.User, len(mapData)) + for key, value := range mapData { + newMap[key] = core.User{ + ID: value.Id, + Name: value.Name, + FollowCount: value.FollowCount, + FollowerCount: value.FollowerCount, + IsFollow: false, + Avatar: value.Avatar, + BackgroundImage: value.BackgroundImage, + Signature: value.Signature, + TotalFavourited: strconv.FormatInt(value.TotalFavorited, 10), + WorkCount: value.WorkCount, + FavoriteCount: value.FavoriteCount, + } + } + return newMap +} + +// 协程接口 + +// 通过GetUserSetByIdSet获取用户集合,然后转为Map, 此处获取的是usermicro中的user,交互和社交字段是不准确的 +func GetUserMap(idSet []int64, respUserMap chan map[int64]core.User, wg *sync.WaitGroup, errChan chan error) { + defer wg.Done() + + r, err := Userclient.GetUserSetByIdSetMethod(context.Background(), &usermicro.GetUserSetByIdSetReq{ + IdSet: idSet, + }) if err != nil { - return &core.User{}, err + respUserMap <- map[int64]core.User{} // 出错返回一个空的,否则会阻塞<-chan + errChan <- err + return } if r.Status { - return &core.User{ - ID: r.User.Id, - Name: r.User.Name, - FollowCount: r.User.FollowCount, - FollowerCount: r.User.FollowerCount, - IsFollow: false, // 需要后续增加社交接口,才可以实现follow - Avatar: r.User.Avatar, - BackgroundImage: r.User.BackgroundImage, - Signature: r.User.Signature, - TotalFavourited: strconv.FormatInt(r.User.TotalFavorited, 10), - WorkCount: r.User.WorkCount, - }, nil + rUserMap := ConvertUserInfoSetToMap(r.UserSet) + respUserMap <- ConvertUserInfoMapToCoreUserMap(rUserMap) + errChan <- nil + return // 成功 + } + respUserMap <- map[int64]core.User{} + errChan <- errors.New("userservice GetUserSetByIDSet error: 微服务调用成功,但是返回状态显示失败") +} + +// 用于获取用户的最新数据;写成协程,是为了feed那块可以和视频查询协程并发查询 +// 根据idSet查core.User的map +func GetUserLatestMap(idSet []int64, currentUser int64, respUserMap chan map[int64]core.User, wg *sync.WaitGroup, errChan chan []error) { + defer wg.Done() // 外部的wg + + wgUser := &sync.WaitGroup{} // 本函数子协程的wg + + // 批量查询author: Userclient.GetUserSetByIdSetMethod(),获取不准确的user信息 + // 传切片,切片扩容会导致地址改变,故还是chan通信可靠 + respAuthorMap := make(chan map[int64]core.User, 1) + defer close(respAuthorMap) + respAuthorMapError := make(chan error, 1) + defer close(respAuthorMapError) + wgUser.Add(1) + go GetUserMap(idSet, respAuthorMap, wgUser, respAuthorMapError) + + // 批量查询author作品数,Work_count 从video服务 + // Videoclient.GetVideoCountSetByIdUserSetMethod(context.Background(), &videomicro.GetVideoCountSetByIdUserSetReq{}) + respVideoCountMap := make(chan map[int64]videomicro.VideoCount, 1) + defer close(respVideoCountMap) + respVideoCountMapError := make(chan error, 1) + defer close(respVideoCountMapError) + wgUser.Add(1) + go GetVideoCountMap(idSet, respVideoCountMap, wgUser, respVideoCountMapError) + + // 等待数据 + wgUser.Wait() + + // 处理协程错误 + AuthorMap := <-respAuthorMap + var errSlice = []error{} // 防止外部设置的chan缓存不够造成阻塞,干脆要求外部设置长度为1的error切片类型 + err := <-respAuthorMapError + if err != nil { + errSlice = append(errSlice, err) + } + + VideoCountMap := <-respVideoCountMap + err = <-respVideoCountMapError + if err != nil { + errSlice = append(errSlice, err) + } + // TODO: 其他协程的错误处理 + + errChan <- errSlice // 错误切片 + + // 更新数据 + for id, user := range AuthorMap { + AuthorMap[id] = core.User{ + ID: user.ID, + Name: user.Name, + FollowCount: 0, // TODO: 从获取的数据中拿 + FollowerCount: 0, // TODO: 从获取的数据中拿 + IsFollow: false, // TODO: 从获取的数据中拿 + Avatar: user.Avatar, + BackgroundImage: user.BackgroundImage, + Signature: user.Signature, + TotalFavourited: "", // TODO: 从获取的数据中拿 + WorkCount: VideoCountMap[id].Count, // 最新的count数据 + FavoriteCount: 0, // TODO: 从获取的数据中拿 + } + } - return &core.User{}, errors.New("kitex-usermicroserver : error to get user") // return a null user + respUserMap <- AuthorMap // 返回数据 } -func GetUserFavoriteCount() +// 业务接口 +// 基础注册:用户名和密码 func RegisterUser(username, password string) (userid int64, err error) { newUser := usermicro.CreateUserInfo{ Name: username, @@ -51,6 +151,30 @@ func RegisterUser(username, password string) (userid int64, err error) { return 0, errors.New("kitex-usermicroserver : error to create new user") } +// 完善用户信息的注册 +func RegisterUserALL(username, password string, email, signature, backgroundImage, avatar *string) (userid int64, err error) { + newUser := usermicro.CreateUserInfo{ + Name: username, + Email: email, + Signature: signature, + BackgroundImage: backgroundImage, + Avatar: avatar, + } + r, err := Userclient.CreateUserMethod(context.Background(), &usermicro.CreateUserReq{ + Newuser_: &newUser, + Password: password, // 此处传输明文,加密由user微服务进行 + }) + if err != nil { + return 0, err + } + + if r.Status { + return *r.UserId, nil + } + return 0, errors.New("kitex-usermicroserver : error to create new user") +} + +// 登录校验,目前只支持用户名密码 func LoginUser(username, password string) (userid int64, err error) { r, err := Userclient.LoginUserMethod(context.Background(), &usermicro.LoginUserReq{ Name: username, diff --git a/kitex_server/videoservice.go b/kitex_server/videoservice.go index 4a3abde..c3aa653 100755 --- a/kitex_server/videoservice.go +++ b/kitex_server/videoservice.go @@ -3,40 +3,247 @@ package kitex_server import ( "context" "errors" + "sync" "github.com/ClubWeGo/douyin/biz/model/core" "github.com/ClubWeGo/videomicro/kitex_gen/videomicro" ) -func GetVideosByAuthorId(id int64) ([]*core.Video, error) { +// utils +// 将VideoCount集合转为map +func ConvertVideoCountSetToMap(setData []*videomicro.VideoCount) map[int64]videomicro.VideoCount { + dataMap := make(map[int64]videomicro.VideoCount, len(setData)) + for _, data := range setData { + dataMap[data.Id] = *data + } + return dataMap +} + +// 协程接口 + +// 通过GetVideoCountSetByIdUserSetMethod获取WorkCount的集合,然后转为Map +func GetVideoCountMap(idSet []int64, respVideoCountMap chan map[int64]videomicro.VideoCount, wg *sync.WaitGroup, errChan chan error) { + defer wg.Done() + + r, err := Videoclient.GetVideoCountSetByIdUserSetMethod(context.Background(), &videomicro.GetVideoCountSetByIdUserSetReq{ + AuthorIdSet: idSet, + }) + if err != nil { + respVideoCountMap <- map[int64]videomicro.VideoCount{} + errChan <- err + return + } + if r.Status { + + rVideoCountMap := ConvertVideoCountSetToMap(r.CountSet) + respVideoCountMap <- rVideoCountMap + errChan <- nil + return // 成功 + } + respVideoCountMap <- map[int64]videomicro.VideoCount{} + errChan <- errors.New("userservice GetVideoCountSetByIDUserSet error: 微服务调用成功,但是返回状态显示失败") +} + +// 用于获取视频切片中 被喜欢数,评论数,用户是否喜欢 的最新数据;写成协程,是为了feed那块可以并发查询 +// 本函数根据查到的信息,构建Video切片,其中只有Video.Id和本函数查询的数据为真,其余数据以视频流查到的为准 +func GetVideoLatestMap(idSet []int64, currentUser int64, respVideoMap chan map[int64]core.Video, wg *sync.WaitGroup, errChan chan []error) { + defer wg.Done() // 外部的wg + + wgVideo := &sync.WaitGroup{} // 本函数子协程的wg + + // 批量查询视频的 被喜欢数 ,Favorite 从Favorite服务 + // 批量查询 favorite_count, total_favourited 从favorite服务: kitex_server.FavoriteClient.UserFavoriteCountMethod() + // TODO: 结果要 videoId与对应的数据 map + + // 批量查询 is_follow, 从relation服务; 传入目标userID和currentUser + + // 批量查询 follow_count, follower_cout 从relation服务 + + // 等待数据 + wgVideo.Wait() + + // // 处理协程错误 + var errSlice = []error{} // 防止外部设置的chan缓存不够造成阻塞,要求外部设置长度为1的error切片类型 + // err := <-respAuthorMapError + // if err != nil { + // errSlice = append(errSlice, err) + // } + + // // TODO: 其他协程的错误处理 + + errChan <- errSlice // 记录错误的切片,至少应该返回一个空切片,否则chan会阻塞 + + // 更新数据 + videoLatestMap := make(map[int64]core.Video, len(idSet)) // 视频切片的id是没有重复的 + for _, id := range idSet { + videoLatestMap[id] = core.Video{ // 视频id对应的Video存储查到的关键字段 + FavoriteCount: 0, // TODO:从拿到的MAP数据更新 + CommentCount: 0, // TODO:从拿到的MAP数据更新 + IsFavorite: false, // TODO:从拿到的MAP数据更新 + } + } + respVideoMap <- videoLatestMap // 返回数据 +} + +// 业务接口 + +// 异步调用各种微服务获取feed流以及最新的信息 +func GetFeed(latestTime int64, currentUserId int64, limit int32) (resultList []*core.Video, nextTime int64, err error) { + // currentUserId 用于登录用户刷视频的时候,看是否关注过视频作者 + + r, err := Videoclient.GetVideosFeedMethod(context.Background(), &videomicro.GetVideosFeedReq{LatestTime: latestTime, Limit: limit}) + if err != nil { + return []*core.Video{}, 0, err + } + + if r.Status { + authorIdSet := make([]int64, len(r.VideoList)) + for index, video := range r.VideoList { + authorIdSet[index] = video.AuthorId + } + + wg := &sync.WaitGroup{} + + // 各种chan千万别写错,否则会引起各种读或者写的阻塞(发生阻塞一般都是这种情况) + + // 获取最新的用户信息 + respLatestAuthorMap := make(chan map[int64]core.User, 1) + defer close(respLatestAuthorMap) + respLatestAuthorMapError := make(chan []error, 1) + defer close(respLatestAuthorMapError) + wg.Add(1) + go GetUserLatestMap(authorIdSet, currentUserId, respLatestAuthorMap, wg, respLatestAuthorMapError) + + // 获取视频的最新信息 + respLatestVideoMap := make(chan map[int64]core.Video, 1) + defer close(respLatestVideoMap) + respLatestVideoMapError := make(chan []error, 1) + defer close(respLatestVideoMapError) + wg.Add(1) + go GetVideoLatestMap(authorIdSet, currentUserId, respLatestVideoMap, wg, respLatestVideoMapError) + + // 等待数据 + wg.Wait() + + // 处理协程错误 + AuthorMap := <-respLatestAuthorMap + errSlice := <-respLatestAuthorMapError + + for _, errItem := range errSlice { + if errItem != nil { + return []*core.Video{}, 0, errItem + } + } + + videoMap := <-respLatestVideoMap + errSlice = <-respLatestVideoMapError + for _, errItem := range errSlice { + if errItem != nil { + return []*core.Video{}, 0, errItem + } + } + + // 拼接结果 + resultList = make([]*core.Video, len(r.VideoList)) + for index, video := range r.VideoList { + // TODO:没有查询到的错误处理 + author := AuthorMap[video.AuthorId] + + // TODO:设置机制,慢速同步其他服务的最新数据到user服务的主表,video的主表 + + resultList[index] = &core.Video{ + ID: video.Id, + Author: &author, + PlayURL: video.PlayUrl, + CoverURL: video.CoverUrl, + FavoriteCount: videoMap[video.Id].FavoriteCount, + CommentCount: videoMap[video.Id].CommentCount, + IsFavorite: videoMap[video.Id].IsFavorite, + Title: video.Title, + } + } + return resultList, *r.NextTime, nil + } + return []*core.Video{}, 0, errors.New("向kitex请求feed失败") +} + +// 通过userid获取用户的发布列表 +func GetVideosByAuthorId(id int64) (resultList []*core.Video, err error) { r, err := Videoclient.GetVideosByAuthorIdMethod(context.Background(), &videomicro.GetVideosByAuthorIdReq{ AuthorId: id, }) - // 如果出错,拿到的是空切片,所以videoList也是空的 - videoList := make([]*core.Video, len(r.VideoList)) if err != nil { - return videoList, err + return []*core.Video{}, err } + if r.Status { - author, _ := GetUser(id) // 避免不必要的检索 + authorIdSet := []int64{id} // 只有作者本人 + + wg := &sync.WaitGroup{} + + // 获取最新的用户信息 + respLatestAuthorMap := make(chan map[int64]core.User, 1) + defer close(respLatestAuthorMap) + respLatestAuthorMapError := make(chan []error, 1) + defer close(respLatestAuthorMapError) + wg.Add(1) + go GetUserLatestMap(authorIdSet, id, respLatestAuthorMap, wg, respLatestAuthorMapError) + + // 获取视频的最新信息 + respLatestVideoMap := make(chan map[int64]core.Video, 1) + defer close(respLatestVideoMap) + respLatestVideoMapError := make(chan []error, 1) + defer close(respLatestVideoMapError) + wg.Add(1) + go GetVideoLatestMap(authorIdSet, id, respLatestVideoMap, wg, respLatestVideoMapError) + + // 等待数据 + wg.Wait() + + // 处理协程错误 + AuthorMap := <-respLatestAuthorMap + // log.Println(AuthorMap) + errSlice := <-respLatestAuthorMapError + for _, errItem := range errSlice { + if errItem != nil { + return []*core.Video{}, errItem + } + } + + videoMap := <-respLatestVideoMap + // log.Println(VideoMap) + errSlice = <-respLatestVideoMapError + for _, errItem := range errSlice { + if errItem != nil { + return []*core.Video{}, errItem + } + } + + // 拼接结果 + resultList = make([]*core.Video, len(r.VideoList)) for index, video := range r.VideoList { - // 暂时不做处理,错误返回空对象即可 - videoList[index] = &core.Video{ + // TODO:没有查询到的错误处理 + author := AuthorMap[video.AuthorId] + // TODO:设置机制,慢速同步其他服务的最新数据到user服务的主表,video的主表 + + resultList[index] = &core.Video{ ID: video.Id, - Author: author, + Author: &author, PlayURL: video.PlayUrl, CoverURL: video.CoverUrl, - FavoriteCount: video.FavoriteCount, - CommentCount: video.CommentCount, - IsFavorite: false, // 需要增加喜欢配置 + FavoriteCount: videoMap[video.Id].FavoriteCount, + CommentCount: videoMap[video.Id].CommentCount, + IsFavorite: videoMap[video.Id].IsFavorite, Title: video.Title, } } - return videoList, nil + + return resultList, nil } - return videoList, errors.New("kitex-videomicroserver : error to get video by authorod") // return a null video list + return []*core.Video{}, errors.New("向kitex请求作者的发布信息失败") } +// 发布视频接口 func CreateVideo(title, playUrl, coverUrl string, authorId int64) error { r, err := Videoclient.CreateVideoMethod(context.Background(), &videomicro.CreateVideoReq{ Title: title, @@ -54,13 +261,3 @@ func CreateVideo(title, playUrl, coverUrl string, authorId int64) error { } return errors.New("kitex-videomicroserver : create video failed") } - -func GetVideoCountSetByUserIdSet(idSet []int64) ([]int64, error) { - resp, err := Videoclient.GetVideoCountSetByIdUserSetMethod(context.Background(), &videomicro.GetVideoCountSetByIdUserSetReq{ - AuthorIdSet: idSet, - }) - if err != nil { - return nil, err - } - return resp.CountSet, nil -} diff --git a/main.go b/main.go index fa71988..bdc38eb 100755 --- a/main.go +++ b/main.go @@ -30,7 +30,7 @@ func main() { // init minio minio_server.Init(minioConfig) - h := server.Default(server.WithMaxRequestBodySize(20 << 20)) + h := server.Default(server.WithMaxRequestBodySize(100 * 1024 * 1024)) register(h) h.Spin()