331 lines
8.0 KiB
Go
331 lines
8.0 KiB
Go
|
package service
|
|||
|
|
|||
|
import (
|
|||
|
"context"
|
|||
|
"encoding/json"
|
|||
|
"go-common/app/interface/bbq/app-bbq/api/http/v1"
|
|||
|
"go-common/app/interface/bbq/app-bbq/model"
|
|||
|
"go-common/app/service/bbq/common"
|
|||
|
"go-common/library/ecode"
|
|||
|
"go-common/library/log"
|
|||
|
|
|||
|
"github.com/json-iterator/go"
|
|||
|
)
|
|||
|
|
|||
|
const (
|
|||
|
searchTypeVideo = "bbq_video"
|
|||
|
searchTypeUser = "bbq_user"
|
|||
|
suggestType = "bbq"
|
|||
|
suggestVer = "v4"
|
|||
|
searchLen = 20
|
|||
|
)
|
|||
|
|
|||
|
// SearchCursor .
|
|||
|
type SearchCursor struct {
|
|||
|
Offset int64 `json:"offset"` // 默认为0,数据从1开始
|
|||
|
}
|
|||
|
|
|||
|
func parseSearchCursor(c context.Context, cursorPrev, cursorNext string) (cursor *SearchCursor, directionNext bool, err error) {
|
|||
|
cursor = new(SearchCursor)
|
|||
|
// 判断是向前还是向后查询
|
|||
|
directionNext = true
|
|||
|
cursorStr := cursorNext
|
|||
|
if len(cursorNext) == 0 && len(cursorPrev) > 0 {
|
|||
|
directionNext = false
|
|||
|
cursorStr = cursorPrev
|
|||
|
}
|
|||
|
// 解析
|
|||
|
if len(cursorStr) != 0 {
|
|||
|
var cursorData = []byte(cursorStr)
|
|||
|
err = json.Unmarshal(cursorData, &cursor)
|
|||
|
if err != nil {
|
|||
|
err = ecode.ReqParamErr
|
|||
|
return
|
|||
|
}
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
//HotWord .
|
|||
|
func (s *Service) HotWord(c context.Context, req *v1.HotWordRequest) (res *v1.HotWordResponse, err error) {
|
|||
|
res = new(v1.HotWordResponse)
|
|||
|
res.List = append(res.List, "小姐姐")
|
|||
|
res.List = append(res.List, "舞蹈")
|
|||
|
res.List = append(res.List, "MMD")
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// VideoSearch 视频搜索
|
|||
|
func (s *Service) VideoSearch(c context.Context, arg *v1.BaseSearchReq) (res *v1.VideoSearchRes, err error) {
|
|||
|
res = new(v1.VideoSearchRes)
|
|||
|
var (
|
|||
|
sres []*model.VideoSearchResult
|
|||
|
searchRes *model.RawSearchRes
|
|||
|
relids []int32
|
|||
|
svids []int64
|
|||
|
svidMap map[int64]int64
|
|||
|
)
|
|||
|
|
|||
|
// 0. check
|
|||
|
|
|||
|
// 1. 生成请求,会根据请求参数
|
|||
|
// v2接口
|
|||
|
reqPage := int64(1)
|
|||
|
firstItemOffset := int64(0)
|
|||
|
var cursor *SearchCursor
|
|||
|
var directionNext bool
|
|||
|
if arg.Page == 0 {
|
|||
|
cursor, directionNext, err = parseSearchCursor(c, arg.CursorPrev, arg.CursorNext)
|
|||
|
if err != nil {
|
|||
|
log.Warnw(c, "log", "parse search cursor fail", "prev", arg.CursorPrev, "next", arg.CursorNext)
|
|||
|
return
|
|||
|
}
|
|||
|
firstItemOffset = cursor.Offset - 1
|
|||
|
if directionNext {
|
|||
|
firstItemOffset = cursor.Offset + 1
|
|||
|
}
|
|||
|
reqPage = (firstItemOffset-1)/searchLen + 1
|
|||
|
log.V(1).Infow(c, "log", "v2 request", "next", arg.CursorNext, "prev", arg.CursorPrev)
|
|||
|
} else {
|
|||
|
reqPage = arg.Page
|
|||
|
}
|
|||
|
|
|||
|
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
|||
|
sp := &model.SearchBaseReq{
|
|||
|
KeyWord: arg.Key,
|
|||
|
Type: searchTypeVideo,
|
|||
|
Page: reqPage,
|
|||
|
PageSize: searchLen,
|
|||
|
Highlight: int64(arg.Highlight),
|
|||
|
}
|
|||
|
// 相信搜索结果返回的就是searchLen
|
|||
|
searchRes, err = s.dao.SearchBBQ(c, sp)
|
|||
|
if searchRes.Res == nil {
|
|||
|
return
|
|||
|
}
|
|||
|
if err = json.Unmarshal(searchRes.Res, &sres); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
for _, v := range sres {
|
|||
|
relids = append(relids, v.ID)
|
|||
|
}
|
|||
|
if len(relids) == 0 {
|
|||
|
log.Infov(c, log.KV("log", "search ret empty"))
|
|||
|
return
|
|||
|
}
|
|||
|
ids := s.dao.ParseRel2ID(relids)
|
|||
|
svidMap, err = s.dao.ConvID2SVID(c, ids)
|
|||
|
if err != nil {
|
|||
|
log.Error("ConvID2SVID err [%v]", err)
|
|||
|
err = nil
|
|||
|
return
|
|||
|
}
|
|||
|
for _, svid := range svidMap {
|
|||
|
svids = append(svids, svid)
|
|||
|
}
|
|||
|
svMap, _ := s.svInfos(c, svids, 0, false)
|
|||
|
|
|||
|
for index, sinfo := range sres {
|
|||
|
id := s.dao.ParseRel2ID([]int32{sinfo.ID})
|
|||
|
if id[0] == 0 {
|
|||
|
continue
|
|||
|
}
|
|||
|
if svid, ok := svidMap[id[0]]; ok {
|
|||
|
if sv, ok := svMap[svid]; ok {
|
|||
|
if common.IsSearchSvStateAvailable(int64(sv.State)) {
|
|||
|
r := new(v1.VideoSearchList)
|
|||
|
r.VideoResponse = *sv
|
|||
|
r.SVID = svid
|
|||
|
r.HitColumns = sinfo.HitColumns
|
|||
|
r.TitleHighlight = sinfo.Title
|
|||
|
r.Offset = (reqPage-1)*int64(searchLen) + int64(index) + 1
|
|||
|
res.List = append(res.List, r)
|
|||
|
} else {
|
|||
|
log.Warnw(c, "log", "get error svid in search list", "svid", svid, "sv", sv)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
res.NumPage = searchRes.PageNum
|
|||
|
res.Page = searchRes.Page
|
|||
|
|
|||
|
res.HasMore = false
|
|||
|
if arg.Page == 0 {
|
|||
|
if (directionNext && searchRes.PageNum > searchRes.Page) || (!directionNext && searchRes.Page > 1) {
|
|||
|
res.HasMore = true
|
|||
|
}
|
|||
|
|
|||
|
var list []*v1.VideoSearchList
|
|||
|
if directionNext {
|
|||
|
for _, item := range res.List {
|
|||
|
if item.Offset < firstItemOffset {
|
|||
|
continue
|
|||
|
}
|
|||
|
list = append(list, item)
|
|||
|
}
|
|||
|
} else {
|
|||
|
if firstItemOffset >= int64(len(res.List)) {
|
|||
|
firstItemOffset = int64(len(res.List)) - 1
|
|||
|
}
|
|||
|
for i := firstItemOffset - 1; i >= 0; i-- {
|
|||
|
list = append(list, res.List[i])
|
|||
|
}
|
|||
|
}
|
|||
|
res.List = list
|
|||
|
}
|
|||
|
|
|||
|
var cursorValue SearchCursor
|
|||
|
for _, item := range res.List {
|
|||
|
cursorValue.Offset = item.Offset
|
|||
|
data, _ := json.Marshal(cursorValue)
|
|||
|
item.CursorValue = string(data)
|
|||
|
}
|
|||
|
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// UserSearch 用户搜索
|
|||
|
func (s *Service) UserSearch(c context.Context, mid int64, arg *v1.BaseSearchReq) (res *v1.UserSearchRes, err error) {
|
|||
|
res = new(v1.UserSearchRes)
|
|||
|
var (
|
|||
|
sres []*model.UserSearchResult
|
|||
|
searchRes *model.RawSearchRes
|
|||
|
mids []int64
|
|||
|
)
|
|||
|
|
|||
|
// 1. 生成请求,会根据请求参数
|
|||
|
// v2接口
|
|||
|
reqPage := int64(1)
|
|||
|
firstItemOffset := int64(0)
|
|||
|
var cursor *SearchCursor
|
|||
|
var directionNext bool
|
|||
|
if arg.Page == 0 {
|
|||
|
cursor, directionNext, err = parseSearchCursor(c, arg.CursorPrev, arg.CursorNext)
|
|||
|
if err != nil {
|
|||
|
log.Warnw(c, "log", "parse search cursor fail", "prev", arg.CursorPrev, "next", arg.CursorNext)
|
|||
|
return
|
|||
|
}
|
|||
|
firstItemOffset = cursor.Offset - 1
|
|||
|
if directionNext {
|
|||
|
firstItemOffset = cursor.Offset + 1
|
|||
|
}
|
|||
|
reqPage = (firstItemOffset-1)/searchLen + 1
|
|||
|
log.V(1).Infow(c, "log", "v2 request", "next", arg.CursorNext, "prev", arg.CursorPrev)
|
|||
|
} else {
|
|||
|
reqPage = arg.Page
|
|||
|
}
|
|||
|
|
|||
|
sp := &model.SearchBaseReq{
|
|||
|
KeyWord: arg.Key,
|
|||
|
Type: searchTypeUser,
|
|||
|
Page: reqPage,
|
|||
|
PageSize: searchLen,
|
|||
|
Highlight: int64(arg.Highlight),
|
|||
|
}
|
|||
|
searchRes, err = s.dao.SearchBBQ(c, sp)
|
|||
|
if searchRes.Res == nil {
|
|||
|
return
|
|||
|
}
|
|||
|
if err = json.Unmarshal(searchRes.Res, &sres); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
for _, v := range sres {
|
|||
|
mids = append(mids, v.ID)
|
|||
|
}
|
|||
|
if len(mids) == 0 {
|
|||
|
log.Infov(c, log.KV("log", "search ret empty"))
|
|||
|
return
|
|||
|
}
|
|||
|
uMap, _ := s.dao.BatchUserInfo(c, mid, mids, false, true, true)
|
|||
|
for index, sinfo := range sres {
|
|||
|
if u, ok := uMap[sinfo.ID]; ok {
|
|||
|
r := &v1.UserSearchList{
|
|||
|
UserInfo: *u,
|
|||
|
}
|
|||
|
st := new(v1.UserStatic)
|
|||
|
st.Fan = u.Fan
|
|||
|
st.Follow = u.Follow
|
|||
|
st.Like = u.Like
|
|||
|
st.Liked = u.Liked
|
|||
|
st.FollowState = u.FollowState
|
|||
|
r.UserStatic = st
|
|||
|
r.HitColumns = sinfo.HitColumns
|
|||
|
r.UnameHighlight = sinfo.Uname
|
|||
|
r.Offset = (reqPage-1)*int64(searchLen) + int64(index) + 1
|
|||
|
res.List = append(res.List, r)
|
|||
|
}
|
|||
|
}
|
|||
|
res.NumPage = searchRes.PageNum
|
|||
|
res.Page = searchRes.Page
|
|||
|
|
|||
|
res.HasMore = false
|
|||
|
if arg.Page == 0 {
|
|||
|
if (directionNext && searchRes.PageNum > searchRes.Page) || (!directionNext && searchRes.Page > 1) {
|
|||
|
res.HasMore = true
|
|||
|
}
|
|||
|
|
|||
|
var list []*v1.UserSearchList
|
|||
|
if directionNext {
|
|||
|
for _, item := range res.List {
|
|||
|
if item.Offset < firstItemOffset {
|
|||
|
continue
|
|||
|
}
|
|||
|
list = append(list, item)
|
|||
|
}
|
|||
|
} else {
|
|||
|
if firstItemOffset >= int64(len(res.List)) {
|
|||
|
firstItemOffset = int64(len(res.List)) - 1
|
|||
|
}
|
|||
|
for i := firstItemOffset - 1; i >= 0; i-- {
|
|||
|
list = append(list, res.List[i])
|
|||
|
}
|
|||
|
}
|
|||
|
res.List = list
|
|||
|
}
|
|||
|
|
|||
|
var cursorValue SearchCursor
|
|||
|
for _, item := range res.List {
|
|||
|
cursorValue.Offset = item.Offset
|
|||
|
data, _ := json.Marshal(cursorValue)
|
|||
|
item.CursorValue = string(data)
|
|||
|
}
|
|||
|
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// BBQSug BBQSUG服务
|
|||
|
func (s *Service) BBQSug(c context.Context, arg *v1.SugReq) (res []*v1.SugTag, err error) {
|
|||
|
var (
|
|||
|
sres []*model.RawSugTag
|
|||
|
data json.RawMessage
|
|||
|
)
|
|||
|
sp := &model.SugBaseReq{
|
|||
|
Term: arg.KeyWord,
|
|||
|
SuggestType: suggestType,
|
|||
|
MainVer: suggestVer,
|
|||
|
SugNum: arg.PageSize,
|
|||
|
Highlight: int64(arg.Highlight),
|
|||
|
}
|
|||
|
data, err = s.dao.SugBBQ(c, sp)
|
|||
|
if err != nil {
|
|||
|
log.Error("s.dao.SugBBQ err[%v] data [%s]", err, string(data))
|
|||
|
return
|
|||
|
}
|
|||
|
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
|||
|
if err = json.Unmarshal(data, &sres); err != nil {
|
|||
|
log.Error("json.Unmarshal err[%v] data [%s]", err, string(data))
|
|||
|
return
|
|||
|
}
|
|||
|
for _, sinfo := range sres {
|
|||
|
r := new(v1.SugTag)
|
|||
|
name := sinfo.Name
|
|||
|
r.Name = name
|
|||
|
r.Value = sinfo.Value
|
|||
|
r.Type = sinfo.Type
|
|||
|
r.Ref = sinfo.Ref
|
|||
|
res = append(res, r)
|
|||
|
}
|
|||
|
return
|
|||
|
}
|