relation.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. package v1
  2. import (
  3. "context"
  4. "math"
  5. "strconv"
  6. "time"
  7. "go-common/library/sync/errgroup"
  8. "github.com/pkg/errors"
  9. v1pb "go-common/app/interface/live/app-interface/api/http/v1"
  10. "go-common/app/interface/live/app-interface/conf"
  11. "go-common/app/interface/live/app-interface/dao"
  12. relationT "go-common/app/interface/live/app-interface/service/v1/relation"
  13. avV1 "go-common/app/service/live/av/api/liverpc/v1"
  14. relationV1 "go-common/app/service/live/relation/api/liverpc/v1"
  15. roomV1 "go-common/app/service/live/room/api/liverpc/v1"
  16. roomExV1 "go-common/app/service/live/room_ex/api/liverpc/v1"
  17. playurlbvc "go-common/app/service/live/third_api/bvc"
  18. userExV1 "go-common/app/service/live/userext/api/liverpc/v1"
  19. accountM "go-common/app/service/main/account/model"
  20. actmdl "go-common/app/service/main/account/model"
  21. account "go-common/app/service/main/account/rpc/client"
  22. "go-common/library/ecode"
  23. "go-common/library/log"
  24. "go-common/library/net/rpc/liverpc"
  25. liveConText "go-common/library/net/rpc/liverpc/context"
  26. rpcCtx "go-common/library/net/rpc/liverpc/context"
  27. )
  28. // RelationService struct
  29. type RelationService struct {
  30. conf *conf.Config
  31. accountRPC *account.Service3
  32. // optionally add other properties here, such as dao
  33. // dao *dao.Dao
  34. }
  35. // NewRelationService init
  36. func NewRelationService(c *conf.Config) (s *RelationService) {
  37. s = &RelationService{
  38. conf: c,
  39. accountRPC: account.New3(nil),
  40. }
  41. return s
  42. }
  43. const (
  44. // RoomStatusLive ...
  45. RoomStatusLive = 1
  46. // MobileIndexBadgeColorDefault ...
  47. MobileIndexBadgeColorDefault = "#FB9E60"
  48. )
  49. // UnliveAnchor ... implementation
  50. // 直播二级页暂未开播接口
  51. func (s *RelationService) UnliveAnchor(ctx context.Context, req *v1pb.UnLiveAnchorReq) (resp *v1pb.UnLiveAnchorResp, err error) {
  52. resp = &v1pb.UnLiveAnchorResp{}
  53. config := conf.GetDummyUidConf()
  54. if config == relationT.DummyUIDEnable {
  55. dummyHeader := &liverpc.Header{Uid: relationT.RParseInt(req.Buyaofangqizhiliao, relationT.SelfUID)}
  56. ctx = liveConText.WithHeader(ctx, dummyHeader)
  57. }
  58. MakeUnLiveDefaultResult(resp)
  59. uid := relationT.GetUIDFromHeader(ctx)
  60. if uid <= 0 && config == 0 {
  61. return
  62. }
  63. wg, _ := errgroup.WithContext(ctx)
  64. pass, page, pageSize, uid, err := CheckUnLiveAnchorParams(ctx, req)
  65. if !pass {
  66. log.Error("[UnLiveAnchor]CheckParamsError,page:%d,pageSize:%d,uid:%d", page, pageSize, uid)
  67. return
  68. }
  69. relationInfo, groupList, mapUfos2Rolaids, mapRolaids2Ufos, setRolaids, err := GetAttentionListAndGroup(ctx)
  70. if err != nil {
  71. log.Error("[LiveAnchor]get_attentionList_rpc_error")
  72. return
  73. }
  74. // 获取有效(曾经直播过)主播,剪枝roomIDs
  75. lastLiveTime, _ := relationT.GetLastLiveTime(ctx, setRolaids)
  76. alienableRolaids, liberateInfo, sorted := FilterEverLived(lastLiveTime)
  77. alienableUfos := GetUID(mapRolaids2Ufos, alienableRolaids)
  78. roomExReq := &roomExV1.RoomNewsMultiGetReq{RoomIds: alienableRolaids, IsDecoded: 1}
  79. roomParams := &roomV1.RoomGetStatusInfoByUidsReq{Uids: groupList["all"], FilterOffline: 0}
  80. userInfo := make(map[int64]*accountM.Card)
  81. roomResp := make(map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo)
  82. roomExResp := make(map[int64]*roomExV1.RoomNewsMultiGetResp_Data)
  83. userfcResp := make(map[int64]*relationV1.FeedGetUserFcBatchResp_RelationList)
  84. // room
  85. wg.Go(func() error {
  86. roomResp, err = relationT.GetRoomInfo(ctx, roomParams)
  87. return err
  88. })
  89. // user信息
  90. wg.Go(func() error {
  91. userInfo, err = s.GetUserInfoData(ctx, alienableUfos)
  92. return err
  93. })
  94. // roomEx
  95. wg.Go(func() error {
  96. roomExResp, err = relationT.GetRoomNewsInfo(ctx, roomExReq)
  97. return err
  98. })
  99. // fansNum
  100. wg.Go(func() error {
  101. userfcResp, err = GetUserFc(ctx, alienableUfos)
  102. return err
  103. })
  104. waitErr := wg.Wait()
  105. if waitErr != nil {
  106. log.Error("[UnLiveAnchor][step2] rpc error: %s", waitErr)
  107. return
  108. }
  109. mapSp := make(map[int64]bool)
  110. normalSp := make(map[int64]bool)
  111. for _, v := range groupList["special"] {
  112. mapSp[v] = true
  113. }
  114. for _, v := range groupList["normal"] {
  115. normalSp[v] = true
  116. }
  117. specialRoomed, normalRoomed := s.GroupByRule(ctx, mapSp, normalSp, liberateInfo, sorted, mapRolaids2Ufos)
  118. specialUID := GetUID(mapRolaids2Ufos, specialRoomed)
  119. normalUID := GetUID(mapRolaids2Ufos, normalRoomed)
  120. liveDesc, newsDesc := CalcTimeLine(liberateInfo, roomExResp)
  121. LiveCount := CountLiveRooms(roomResp)
  122. resp.Rooms = AdaptField(roomResp, userfcResp, userInfo, roomExResp, relationInfo, specialUID, normalUID, mapUfos2Rolaids, liveDesc, newsDesc)
  123. resp.TotalCount = int64(len(resp.Rooms))
  124. resp.NoRoomCount = int64(len(setRolaids) - int(resp.TotalCount) - int(LiveCount))
  125. resp.Rooms = UnLiveAnchorSlice(resp.Rooms, page, pageSize)
  126. if (page * pageSize) >= resp.TotalCount {
  127. resp.HasMore = 0
  128. } else {
  129. resp.HasMore = 1
  130. }
  131. return
  132. }
  133. // CountLiveRooms 计算正在直播数目
  134. func CountLiveRooms(input map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo) (count int) {
  135. if len(input) <= 0 {
  136. count = 0
  137. return
  138. }
  139. for _, v := range input {
  140. if v.LiveStatus == RoomStatusLive {
  141. count++
  142. }
  143. }
  144. return
  145. }
  146. // CheckUnLiveAnchorParams implementation
  147. // 入参校验
  148. func CheckUnLiveAnchorParams(ctx context.Context, req *v1pb.UnLiveAnchorReq) (pass bool, page int64, pageSize int64, uid int64, err error) {
  149. if req == nil {
  150. pass = false
  151. return
  152. }
  153. config := conf.GetDummyUidConf()
  154. uid = relationT.GetUIDFromHeader(ctx)
  155. if uid == 0 && config == 0 {
  156. err = errors.WithMessage(ecode.NeedLogIn, "GET SEA PATROL FAIL")
  157. pass = false
  158. return
  159. }
  160. page = req.Page
  161. pageSize = req.Pagesize
  162. if page <= 0 || pageSize <= 0 {
  163. pass = false
  164. log.Error("CallRelationUnLiveAnchorParamsCheckError|page:%d,pageSize:%d", page, pageSize)
  165. err = errors.WithMessage(ecode.UnliveAnchorReqParamsError, "GET SEA PATROL FAIL")
  166. return
  167. }
  168. pass = true
  169. return
  170. }
  171. // CheckLiveAnchorParams implementation
  172. // 入参校验
  173. func CheckLiveAnchorParams(ctx context.Context, req *v1pb.LiveAnchorReq) (sortRule int64, filterRule int64, uid int64, err error) {
  174. if req == nil {
  175. err = ecode.LiveAnchorReqParamsNil
  176. return
  177. }
  178. sortRule = req.SortRule
  179. filterRule = req.FilterRule
  180. uid = relationT.GetUIDFromHeader(ctx)
  181. config := conf.GetDummyUidConf()
  182. if uid == 0 && config == 0 {
  183. err = errors.WithMessage(ecode.NeedLogIn, "GET SEA PATROL FAIL")
  184. return
  185. }
  186. if sortRule < 0 || filterRule < 0 {
  187. log.Error("CallRelationLiveAnchorParamsCheckError|page:%d,pageSize:%d", sortRule, filterRule)
  188. err = errors.WithMessage(ecode.LiveAnchorReqParamsError, "GET SEA PATROL FAIL")
  189. return
  190. }
  191. return
  192. }
  193. // UnLiveAnchorSlice implementation
  194. // 分页逻辑
  195. func UnLiveAnchorSlice(req []*v1pb.UnLiveAnchorResp_Rooms, page int64, pageSize int64) (resp []*v1pb.UnLiveAnchorResp_Rooms) {
  196. resp = make([]*v1pb.UnLiveAnchorResp_Rooms, 0)
  197. start := (page - 1) * pageSize
  198. end := start + pageSize
  199. length := int64(len(req))
  200. if start >= length {
  201. return
  202. }
  203. if end >= length {
  204. resp = req[start:]
  205. } else {
  206. resp = req[start:end]
  207. }
  208. return
  209. }
  210. // MakeUnLiveDefaultResult implementation
  211. // 缺省返回
  212. func MakeUnLiveDefaultResult(resp *v1pb.UnLiveAnchorResp) {
  213. if resp != nil {
  214. resp.HasMore = 0
  215. resp.NoRoomCount = 0
  216. resp.TotalCount = 0
  217. resp.Rooms = make([]*v1pb.UnLiveAnchorResp_Rooms, 0)
  218. }
  219. }
  220. // GroupByRule implementation
  221. // 按照规则排序,组间按照特别关注优先,组内按照上次关播时间倒序
  222. func (s *RelationService) GroupByRule(ctx context.Context, special map[int64]bool, normal map[int64]bool,
  223. liberate map[int64]int64, sorted relationT.PairList, mapRolaids2Ufos map[int64]int64) (specialRoomed []int64, normalRoomed []int64) {
  224. specialRoomed = make([]int64, 0)
  225. normalRoomed = make([]int64, 0)
  226. if len(liberate) == 0 || liberate == nil {
  227. return
  228. }
  229. for _, v := range sorted {
  230. if _, ok := special[mapRolaids2Ufos[v.Key]]; ok {
  231. specialRoomed = append(specialRoomed, v.Key)
  232. } else {
  233. normalRoomed = append(normalRoomed, v.Key)
  234. }
  235. }
  236. return
  237. }
  238. // AdaptField implementation
  239. // 填充逻辑
  240. func AdaptField(roomInfo map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo,
  241. fansInfo map[int64]*relationV1.FeedGetUserFcBatchResp_RelationList,
  242. userResult map[int64]*accountM.Card,
  243. roomedInfo map[int64]*roomExV1.RoomNewsMultiGetResp_Data,
  244. relationInfo map[int64]*relationV1.BaseInfoGetFollowTypeResp_UidInfo,
  245. specialUID []int64, normalUID []int64,
  246. mapUfos2Rolaids map[int64]int64, liveDesc map[int64]string, newsDesc map[int64]string) (resp []*v1pb.UnLiveAnchorResp_Rooms) {
  247. var item []*v1pb.UnLiveAnchorResp_Rooms
  248. resp = make([]*v1pb.UnLiveAnchorResp_Rooms, 0)
  249. if len(specialUID) > 0 {
  250. item = FireField(roomInfo, fansInfo, userResult, roomedInfo, relationInfo, specialUID, mapUfos2Rolaids, liveDesc, newsDesc)
  251. resp = append(resp, item...)
  252. }
  253. if len(normalUID) > 0 {
  254. item = FireField(roomInfo, fansInfo, userResult, roomedInfo, relationInfo, normalUID, mapUfos2Rolaids, liveDesc, newsDesc)
  255. resp = append(resp, item...)
  256. }
  257. return
  258. }
  259. // CalcTimeLine ...
  260. // 计算时间规则
  261. func CalcTimeLine(liberateInfo map[int64]int64,
  262. roomNewsInfo map[int64]*roomExV1.RoomNewsMultiGetResp_Data) (liveDesc map[int64]string, newsDesc map[int64]string) {
  263. liveDesc, newsDesc = TimeLineRule(liberateInfo, roomNewsInfo)
  264. return
  265. }
  266. // TimeLineRule ...
  267. // 计算时间规则
  268. func TimeLineRule(liberateInfo map[int64]int64, roomNewsInfo map[int64]*roomExV1.RoomNewsMultiGetResp_Data) (liveDesc map[int64]string, newsDesc map[int64]string) {
  269. liveDesc = make(map[int64]string)
  270. newsDesc = make(map[int64]string)
  271. if len(liberateInfo) <= 0 {
  272. return
  273. }
  274. for livedRoomed, lastLiveTime := range liberateInfo {
  275. now := time.Now()
  276. currentYear, currentMonth, currentDay := now.Date()
  277. currentLocation := now.Location()
  278. firstOfMonth := time.Date(currentYear, 1, 1, 0, 0, 0, 0, currentLocation)
  279. thisYearUnixTimeStamp := firstOfMonth.Unix()
  280. todayUnixTimeStamp := time.Date(currentYear, currentMonth, currentDay, 0, 0, 0, 0, currentLocation).Unix()
  281. today24 := math.Abs(float64(todayUnixTimeStamp - lastLiveTime))
  282. liveTime := math.Abs(float64(now.Unix() - lastLiveTime))
  283. if lastLiveTime == 0 {
  284. liveDesc[livedRoomed] = "上次"
  285. }
  286. if liveTime < 60 {
  287. liveDesc[livedRoomed] = "刚刚"
  288. } else if liveTime >= 60 && liveTime < 3600 {
  289. text := int(math.Floor(liveTime / 60))
  290. liveDesc[livedRoomed] = strconv.Itoa(text) + "分钟前"
  291. } else if liveTime >= 3600 && liveTime < 86400 {
  292. text := int(math.Floor(liveTime / 3600))
  293. liveDesc[livedRoomed] = strconv.Itoa(text) + "小时前"
  294. } else if liveTime >= 86400 && today24 <= 86400 {
  295. liveDesc[livedRoomed] = "昨天"
  296. } else if liveTime >= 86400 && lastLiveTime >= thisYearUnixTimeStamp {
  297. tm := time.Unix(lastLiveTime, 0)
  298. text := tm.Format("1-2")
  299. liveDesc[livedRoomed] = text
  300. } else {
  301. if lastLiveTime < thisYearUnixTimeStamp && liveTime >= 86400 {
  302. tm := time.Unix(lastLiveTime, 0)
  303. text := tm.Format("2006-1-2")
  304. liveDesc[livedRoomed] = text
  305. } else {
  306. tm := time.Unix(lastLiveTime, 0)
  307. text := tm.Format("2006-1-2")
  308. liveDesc[livedRoomed] = text
  309. }
  310. }
  311. }
  312. if len(roomNewsInfo) <= 0 {
  313. return
  314. }
  315. for livedRoomed, lastNewsTime := range roomNewsInfo {
  316. lastLiveTimeStr := lastNewsTime.Ctime
  317. now := time.Now()
  318. timeFmt, _ := time.ParseInLocation("2006-01-02 15:04:05", lastLiveTimeStr, time.Local)
  319. lastLiveTime := timeFmt.Unix()
  320. currentYear, currentMonth, currentDay := now.Date()
  321. currentLocation := now.Location()
  322. todayUnixTimeStamp := time.Date(currentYear, currentMonth, currentDay, 0, 0, 0, 0, currentLocation).Unix()
  323. today24 := math.Abs(float64(todayUnixTimeStamp - lastLiveTime))
  324. liveTime := math.Abs(float64(now.Unix() - lastLiveTime))
  325. if lastLiveTime == 0 {
  326. newsDesc[livedRoomed] = ""
  327. }
  328. if liveTime < 60 {
  329. newsDesc[livedRoomed] = "刚刚"
  330. } else if liveTime >= 60 && liveTime < 3600 {
  331. text := int(math.Floor(liveTime / 60))
  332. newsDesc[livedRoomed] = strconv.Itoa(text) + "分钟前"
  333. } else if liveTime >= 3600 && liveTime < 86400 {
  334. text := int(math.Floor(liveTime / 3600))
  335. newsDesc[livedRoomed] = strconv.Itoa(text) + "小时前"
  336. } else if liveTime >= 86400 && today24 <= 86400 {
  337. newsDesc[livedRoomed] = "昨天"
  338. }
  339. }
  340. return
  341. }
  342. // FireField ...
  343. // 适配返回值
  344. func FireField(roomInfo map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo,
  345. fansInfo map[int64]*relationV1.FeedGetUserFcBatchResp_RelationList,
  346. userResult map[int64]*accountM.Card,
  347. roomedInfo map[int64]*roomExV1.RoomNewsMultiGetResp_Data,
  348. relationInfo map[int64]*relationV1.BaseInfoGetFollowTypeResp_UidInfo,
  349. ufos []int64,
  350. mapUfos2Rolaids map[int64]int64, liveDesc map[int64]string, newsDesc map[int64]string) (resp []*v1pb.UnLiveAnchorResp_Rooms) {
  351. for _, v := range ufos {
  352. item := v1pb.UnLiveAnchorResp_Rooms{}
  353. roomID, roomIDExist := mapUfos2Rolaids[v]
  354. if !roomIDExist {
  355. continue
  356. }
  357. roomItem := roomInfo[v]
  358. userItem := userResult[v]
  359. fansItem := fansInfo[v]
  360. relationItem := relationInfo[v]
  361. roomedItem := roomedInfo[roomID]
  362. roomNewsDesc := newsDesc[roomID]
  363. liveDescItem := liveDesc[roomID]
  364. roomNewsContent := ""
  365. roomNewsDescText := ""
  366. if roomItem == nil || userItem == nil || relationItem == nil {
  367. continue
  368. }
  369. if roomItem.LiveStatus == RoomStatusLive {
  370. continue
  371. }
  372. if roomedItem != nil {
  373. roomNewsContent = roomedItem.NewsContent
  374. roomNewsDescText = roomNewsDesc
  375. }
  376. item.Roomid = roomItem.RoomId
  377. item.Uid = roomItem.Uid
  378. item.Uname = userItem.Name
  379. item.Face = userItem.Face
  380. item.LiveStatus = roomItem.LiveStatus
  381. item.Area = roomItem.Area
  382. item.AreaName = roomItem.AreaName
  383. item.AreaV2Id = roomItem.AreaV2Id
  384. item.AreaV2Name = roomItem.AreaV2Name
  385. item.AreaV2ParentId = roomItem.AreaV2ParentId
  386. item.AreaV2ParentName = roomItem.AreaV2ParentName
  387. item.BroadcastType = roomItem.BroadcastType
  388. item.Link = relationT.LiveDomain + strconv.Itoa(int(roomID)) + relationT.BoastURL + strconv.Itoa(int(item.BroadcastType))
  389. item.OfficialVerify = int64(relationT.RoleMap(userItem.Official.Role))
  390. item.Attentions = fansItem.Fc
  391. item.SpecialAttention = relationItem.Special
  392. item.AnnouncementContent = roomNewsContent
  393. item.AnnouncementTime = roomNewsDescText
  394. item.LiveDesc = liveDescItem
  395. resp = append(resp, &item)
  396. }
  397. return
  398. }
  399. // LiveFireField ...
  400. // 适配返回值
  401. func LiveFireField(roomInfo map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo,
  402. roomPendentInfo map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result,
  403. userResult map[int64]*accountM.Card,
  404. pkIDInfo map[string]int64, playURLInfo map[int64]*playurlbvc.PlayUrlItem,
  405. relationInfo map[int64]*relationV1.BaseInfoGetFollowTypeResp_UidInfo,
  406. ufos []int64, mapUfos2Rolaids map[int64]int64) (resp []*v1pb.LiveAnchorResp_Rooms) {
  407. for _, v := range ufos {
  408. item := v1pb.LiveAnchorResp_Rooms{}
  409. roomID, roomIDExist := mapUfos2Rolaids[v]
  410. if !roomIDExist {
  411. continue
  412. }
  413. roomItem := roomInfo[v]
  414. roomPendentItem := roomPendentInfo[roomID]
  415. userItem := userResult[v]
  416. relationItem := relationInfo[v]
  417. pkItem := pkIDInfo[strconv.Itoa(int(roomID))]
  418. playURLItem := playURLInfo[roomID]
  419. if roomItem == nil || userItem == nil || relationItem == nil {
  420. continue
  421. }
  422. PlayURL := ""
  423. PlayURL265 := ""
  424. PlayURLAcc := make([]int64, 0)
  425. PlayURLCur := 0
  426. PendentRu := ""
  427. PendentRuColor := ""
  428. PendentRuPic := ""
  429. if playURLItem != nil {
  430. PlayURL = playURLItem.Url["h264"]
  431. PlayURL265 = playURLItem.Url["h265"]
  432. PlayURLAcc = playURLItem.AcceptQuality
  433. PlayURLCur = int(playURLItem.CurrentQuality)
  434. }
  435. if roomPendentItem != nil {
  436. PendentRu = roomPendentItem.Value
  437. PendentRuColor = roomPendentItem.BgColor
  438. PendentRuPic = roomPendentItem.BgPic
  439. }
  440. if PendentRuColor == "" {
  441. PendentRuColor = MobileIndexBadgeColorDefault
  442. }
  443. item.Roomid = roomItem.RoomId
  444. item.Uid = roomItem.Uid
  445. item.Uname = userItem.Name
  446. item.Face = userItem.Face
  447. item.Title = roomItem.Title
  448. item.LiveTagName = roomItem.AreaV2Name
  449. item.LiveTime = roomItem.LiveTime
  450. item.Online = roomItem.Online
  451. item.Playurl = PlayURL
  452. item.AcceptQuality = PlayURLAcc
  453. item.CurrentQuality = int64(PlayURLCur)
  454. item.PkId = pkItem
  455. item.Area = roomItem.Area
  456. item.AreaName = roomItem.AreaName
  457. item.AreaV2Id = roomItem.AreaV2Id
  458. item.PlayUrlH265 = PlayURL265
  459. item.AreaV2Name = roomItem.AreaV2Name
  460. item.AreaV2ParentId = roomItem.AreaV2ParentId
  461. item.AreaV2ParentName = roomItem.AreaV2ParentName
  462. item.BroadcastType = roomItem.BroadcastType
  463. item.Link = relationT.LiveDomain + strconv.Itoa(int(roomID)) + relationT.BoastURL + strconv.Itoa(int(item.BroadcastType))
  464. item.OfficialVerify = int64(relationT.RoleMap(userItem.Official.Role))
  465. item.SpecialAttention = relationItem.Special
  466. item.PendentRu = PendentRu
  467. item.PendentRuColor = PendentRuColor
  468. item.PendentRuPic = PendentRuPic
  469. if len(roomItem.CoverFromUser) == 0 {
  470. item.Cover = roomItem.Keyframe
  471. } else {
  472. item.Cover = roomItem.CoverFromUser
  473. }
  474. resp = append(resp, &item)
  475. }
  476. return
  477. }
  478. // GroupUfos ...
  479. // 按照关注类型分组
  480. func GroupUfos(input map[int64]*relationV1.BaseInfoGetFollowTypeResp_UidInfo) (resp map[string][]int64, err error) {
  481. if input == nil {
  482. return nil, nil
  483. }
  484. resp = make(map[string][]int64)
  485. for k, v := range input {
  486. if v.Special == 0 {
  487. resp["normal"] = append(resp["normal"], k)
  488. } else {
  489. resp["special"] = append(resp["special"], k)
  490. }
  491. resp["all"] = append(resp["all"], k)
  492. }
  493. return resp, nil
  494. }
  495. // GetUID ...
  496. // 获取uid
  497. func GetUID(idsMap map[int64]int64, input []int64) (resp []int64) {
  498. if idsMap == nil || input == nil {
  499. return nil
  500. }
  501. for _, v := range input {
  502. resp = append(resp, idsMap[int64(v)])
  503. }
  504. return resp
  505. }
  506. // FilterEverLived ...
  507. // 过滤未开播
  508. func FilterEverLived(lastLiveTime map[string]string) (rolaids []int64, lifetime map[int64]int64, sorted relationT.PairList) {
  509. rolaids = make([]int64, 0)
  510. lifetime = make(map[int64]int64)
  511. for roomed, v := range lastLiveTime {
  512. timeFmt, _ := time.ParseInLocation("2006-01-02 15:04:05", v, time.Local)
  513. if !timeFmt.IsZero() {
  514. if mid, err := strconv.ParseInt(roomed, 10, 64); err == nil {
  515. lifetime[mid] = timeFmt.Unix()
  516. rolaids = append(rolaids, mid)
  517. }
  518. }
  519. }
  520. sorted = make([]relationT.Pair, 0)
  521. sorted = relationT.SortMap(lifetime)
  522. return rolaids, lifetime, sorted
  523. }
  524. // GetLastAnchorLiveTime ...
  525. // 获取上一个主播信息
  526. func GetLastAnchorLiveTime(lastLiveTime map[string]string) (rolaids []int64, lifetime map[int64]int64, sorted relationT.PairList) {
  527. rolaids = make([]int64, 0)
  528. lifetime = make(map[int64]int64)
  529. for roomed, v := range lastLiveTime {
  530. timeFmt, _ := time.ParseInLocation("2006-01-02 15:04:05", v, time.Local)
  531. if mid, err := strconv.ParseInt(roomed, 10, 64); err == nil {
  532. lifetime[mid] = timeFmt.Unix()
  533. rolaids = append(rolaids, mid)
  534. }
  535. }
  536. sorted = make([]relationT.Pair, 0)
  537. sorted = relationT.SortMap(lifetime)
  538. return rolaids, lifetime, sorted
  539. }
  540. // MakeLiveAnchorDefaultResult ...
  541. // 正在直播默认返回
  542. func MakeLiveAnchorDefaultResult(resp *v1pb.LiveAnchorResp) {
  543. if resp != nil {
  544. resp.TotalCount = 0
  545. // [历史原因]cardType只能为1,否则客户端报错,见 https://www.tapd.cn/20082211/prong/stories/view/1120082211001086997
  546. resp.CardType = relationT.App533CardType
  547. resp.BigCardType = 0
  548. resp.Rooms = make([]*v1pb.LiveAnchorResp_Rooms, 0)
  549. }
  550. }
  551. // GetAttentionListAndGroup ...
  552. // 关注分组
  553. func GetAttentionListAndGroup(ctx context.Context) (relationInfo map[int64]*relationV1.BaseInfoGetFollowTypeResp_UidInfo, groupList map[string][]int64,
  554. mapUfos2Rolaids map[int64]int64, mapRolaids2Ufos map[int64]int64, setRolaids []int64, attentionErr error) {
  555. relationTimeout := conf.GetTimeout("relation", 200)
  556. attentionErr = nil
  557. attentionData, attentionErr := dao.RelationApi.V1BaseInfo.GetFollowType(
  558. rpcCtx.WithTimeout(ctx, time.Duration(relationTimeout)*time.Millisecond),
  559. &relationV1.BaseInfoGetFollowTypeReq{})
  560. if attentionErr != nil || attentionData == nil {
  561. attentionErr = ecode.AttentionListRPCError
  562. return
  563. }
  564. relationInfo = attentionData.Data
  565. groupList, _ = GroupUfos(attentionData.Data)
  566. // 转换ids
  567. mapUfos2Rolaids, err := relationT.UIDs2roomIDs(ctx, groupList["all"])
  568. if err != nil {
  569. attentionErr = ecode.RoomGetRoomIDCodeRPCError
  570. return
  571. }
  572. mapRolaids2Ufos, setRolaids = TransRoomedUUID(mapUfos2Rolaids)
  573. return
  574. }
  575. // TransRoomedUUID ...
  576. // 转换ids
  577. func TransRoomedUUID(mapUfos2Rolaids map[int64]int64) (mapRolaids2Ufos map[int64]int64, setRolaids []int64) {
  578. mapRolaids2Ufos = make(map[int64]int64)
  579. for k, v := range mapUfos2Rolaids {
  580. mapRolaids2Ufos[v] = k
  581. }
  582. setRolaids = make([]int64, 0)
  583. for _, v := range mapUfos2Rolaids {
  584. setRolaids = append(setRolaids, v)
  585. }
  586. return
  587. }
  588. // AdaptLivingField ...
  589. // 填充逻辑
  590. func AdaptLivingField(roomInfo map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo,
  591. roomPendentInfo map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result,
  592. userResult map[int64]*accountM.Card,
  593. relationInfo map[int64]*relationV1.BaseInfoGetFollowTypeResp_UidInfo,
  594. pkIDInfo map[string]int64, playURLInfo map[int64]*playurlbvc.PlayUrlItem, specialUID []int64, normalUID []int64,
  595. mapUfos2Rolaids map[int64]int64) (resp []*v1pb.LiveAnchorResp_Rooms) {
  596. var item []*v1pb.LiveAnchorResp_Rooms
  597. resp = make([]*v1pb.LiveAnchorResp_Rooms, 0)
  598. normalResp := make([]*v1pb.LiveAnchorResp_Rooms, 0)
  599. if len(specialUID) > 0 {
  600. item = LiveFireField(roomInfo, roomPendentInfo, userResult, pkIDInfo, playURLInfo, relationInfo, specialUID, mapUfos2Rolaids)
  601. tempResp := &v1pb.LiveAnchorResp{}
  602. tempResp.Rooms = item
  603. resp = relationT.AppSortRuleOnline(tempResp)
  604. }
  605. if len(normalUID) > 0 {
  606. item = LiveFireField(roomInfo, roomPendentInfo, userResult, pkIDInfo, playURLInfo, relationInfo, normalUID, mapUfos2Rolaids)
  607. tempResp := &v1pb.LiveAnchorResp{}
  608. tempResp.Rooms = item
  609. normalResp = relationT.AppSortRuleOnline(tempResp)
  610. }
  611. if len(normalResp) > 0 {
  612. resp = append(resp, normalResp...)
  613. }
  614. return
  615. }
  616. // LiveAnchor implementation
  617. // [app端关注二级页][全量]正在直播接口
  618. func (s *RelationService) LiveAnchor(ctx context.Context, req *v1pb.LiveAnchorReq) (resp *v1pb.LiveAnchorResp, err error) {
  619. resp = &v1pb.LiveAnchorResp{}
  620. MakeLiveAnchorDefaultResult(resp)
  621. sortRule, filterRule, uid, err := CheckLiveAnchorParams(ctx, req)
  622. wg, _ := errgroup.WithContext(ctx)
  623. if err != nil {
  624. log.Error("[LiveAnchor]CheckParamsError,page:%d,pageSize:%d,uid:%d", sortRule, filterRule, uid)
  625. return
  626. }
  627. relationInfo, groupList, mapUfos2Rolaids, _, _, err := GetAttentionListAndGroup(ctx)
  628. if err != nil {
  629. log.Error("[LiveAnchor]get_attentionList_rpc_error")
  630. return
  631. }
  632. // 获取有效(正在直播中)主播,剪枝roomIDs
  633. roomParams := &roomV1.RoomGetStatusInfoByUidsReq{Uids: groupList["all"], FilterOffline: 1, NeedBroadcastType: 1}
  634. // room
  635. roomResp, err := relationT.GetRoomInfo(ctx, roomParams)
  636. if err != nil {
  637. log.Error("[LiveAnchor]get_room_rpc_error")
  638. return
  639. }
  640. livingUfos := make([]int64, 0)
  641. livingRolaids := make([]int64, 0)
  642. // 没有人直播
  643. if len(roomResp) == 0 {
  644. return
  645. }
  646. for k, v := range roomResp {
  647. livingUfos = append(livingUfos, k)
  648. livingRolaids = append(livingRolaids, v.RoomId)
  649. }
  650. userResp := make(map[int64]*accountM.Card)
  651. roomCornerResp := make(map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result)
  652. pkResp := make(map[string]int64)
  653. attentionRoomListPlayURLMap := make(map[int64]*playurlbvc.PlayUrlItem)
  654. build, _ := strconv.ParseInt(req.Build, 10, 64)
  655. roomPendentParams := &roomV1.RoomPendantGetPendantByIdsReq{Ids: livingRolaids, Type: relationT.PendentMobileBadge, Position: relationT.PendentPosition}
  656. pkParams := &avV1.PkGetPkIdsByRoomIdsReq{RoomIds: livingRolaids, Platform: req.Platform}
  657. if err != nil {
  658. log.Error("[LiveAnchor]get_roomPendant_rpc_error")
  659. return
  660. }
  661. // user信息
  662. wg.Go(func() error {
  663. userResp, err = s.GetUserInfoData(ctx, livingUfos)
  664. return err
  665. })
  666. // room
  667. wg.Go(func() error {
  668. roomCornerResp, err = relationT.GetRoomPendantInfo(ctx, roomPendentParams)
  669. return err
  670. })
  671. // pk_id
  672. wg.Go(func() error {
  673. pkResp, err = relationT.GetPkID(ctx, pkParams)
  674. return err
  675. })
  676. quality := req.Quality
  677. if quality <= 0 {
  678. quality = 4
  679. }
  680. // playurl
  681. wg.Go(func() error {
  682. attentionRoomListPlayURLMap = dao.BvcApi.GetPlayUrlMulti(ctx, livingRolaids, 0, quality, build, req.Platform)
  683. return err
  684. })
  685. waitErr := wg.Wait()
  686. if waitErr != nil {
  687. log.Error("[LiveAnchor][step2] rpc error: %s", waitErr)
  688. return
  689. }
  690. // 下游数据收集完成
  691. mapSp := make([]int64, 0)
  692. normalSp := make([]int64, 0)
  693. mapSp = append(mapSp, groupList["special"]...)
  694. normalSp = append(normalSp, groupList["normal"]...)
  695. resp.Rooms = AdaptLivingField(roomResp, roomCornerResp, userResp, relationInfo, pkResp, attentionRoomListPlayURLMap, mapSp, normalSp, mapUfos2Rolaids)
  696. resp.TotalCount = int64(len(resp.Rooms))
  697. userExtParams := &userExV1.GrayRuleGetByMarkReq{Mark: relationT.App531GrayRule}
  698. grayRule, err := relationT.GetGrayRule(ctx, userExtParams)
  699. if err != nil {
  700. log.Error("[LiveAnchor]get_GrayRule_rpc_error")
  701. resp.BigCardType = 0
  702. } else if grayRule != nil {
  703. resp.BigCardType = relationT.App531ABTest(ctx, grayRule.Content, req.Build, req.Platform)
  704. }
  705. FilterType(ctx, livingUfos, resp, filterRule)
  706. SortType(ctx, resp, sortRule)
  707. return
  708. }
  709. // FilterType implementation
  710. // [app端关注二级页]按照规则过滤结果集
  711. func FilterType(ctx context.Context, targetUIDs []int64, originResult *v1pb.LiveAnchorResp, filterType int64) {
  712. if originResult == nil || len(originResult.Rooms) == 0 {
  713. return
  714. }
  715. switch filterType {
  716. case relationT.AppFilterDefault:
  717. {
  718. }
  719. case relationT.AppFilterFansMedal:
  720. {
  721. filteredRooms, _ := relationT.AppFilterRuleFansMedal(ctx, originResult, targetUIDs)
  722. originResult.Rooms = filteredRooms
  723. originResult.TotalCount = int64(len(originResult.Rooms))
  724. }
  725. case relationT.AppFilterGoldType:
  726. {
  727. filteredRooms, _ := relationT.AppFilterGold(ctx, originResult)
  728. originResult.Rooms = filteredRooms
  729. originResult.TotalCount = int64(len(originResult.Rooms))
  730. }
  731. }
  732. }
  733. // SortType implementation
  734. // [app端关注二级页]按照规则排序结果集
  735. // 规则见https://www.tapd.cn/20082211/prong/stories/view/1120082211001067961
  736. func SortType(ctx context.Context, originResult *v1pb.LiveAnchorResp, sortType int64) (resp *v1pb.LiveAnchorResp, err error) {
  737. if originResult == nil || len(originResult.Rooms) == 0 {
  738. return
  739. }
  740. switch sortType {
  741. // 组间特别关注、组内人气值
  742. case relationT.AppSortDefaultT:
  743. {
  744. }
  745. case relationT.AppSortRuleLiveTimeT:
  746. {
  747. originResult.Rooms = relationT.AppSortRuleLiveTime(originResult)
  748. }
  749. case relationT.AppSortRuleOnlineT:
  750. {
  751. originResult.Rooms = relationT.AppSortRuleOnline(originResult)
  752. }
  753. case relationT.AppSortRuleGoldT:
  754. {
  755. originResult.Rooms = relationT.AppSortRuleGold(ctx, originResult)
  756. }
  757. default:
  758. }
  759. return
  760. }
  761. // GetUserInfoData ...
  762. // 调用account grpc接口cards获取用户信息
  763. func (s *RelationService) GetUserInfoData(ctx context.Context, UIDs []int64) (userResult map[int64]*accountM.Card, err error) {
  764. rpcChunkSize, RPCTimeout, err := relationT.GetChunkInfo(relationT.AccountGRPC)
  765. params := relationT.ChunkCallInfo{ParamsName: "ufos", URLName: relationT.AccountGRPC, ChunkSize: rpcChunkSize, RPCTimeout: RPCTimeout}
  766. userResult = make(map[int64]*accountM.Card)
  767. lens := len(UIDs)
  768. if lens <= 0 {
  769. return
  770. }
  771. // 批次
  772. params.ChunkNum = int64(math.Ceil(float64(lens) / float64(params.ChunkSize)))
  773. chunkResult := make([]map[int64]*accountM.Card, params.ChunkNum)
  774. wg, _ := errgroup.WithContext(ctx)
  775. for i := int64(1); i <= params.ChunkNum; i++ {
  776. x := i
  777. wg.Go(func() error {
  778. chunkUfosIds := make([]int64, 20)
  779. if x == params.ChunkNum {
  780. chunkUfosIds = UIDs[(x-1)*params.ChunkSize:]
  781. } else {
  782. chunkUfosIds = UIDs[(x-1)*params.ChunkSize : x*params.ChunkSize]
  783. }
  784. ret, err := s.accountRPC.Cards3(ctx, &actmdl.ArgMids{Mids: chunkUfosIds})
  785. if err != nil {
  786. err = errors.WithMessage(ecode.AccountGRPCError, "GET SEA PATROL FAIL")
  787. log.Error("Call main.Account.Cards Error.Infos(%+v) error(%+v)", chunkUfosIds, err)
  788. }
  789. chunkResult[x-1] = ret
  790. return nil
  791. })
  792. }
  793. if err := wg.Wait(); err != nil {
  794. erelongInfo := relationT.ErrLogStrut{}
  795. erelongInfo.ErrType = "GoRoutingWaitError"
  796. erelongInfo.URLName = relationT.AccountGRPC
  797. erelongInfo.ErrDesc = relationT.GoRoutingErr
  798. erelongInfo.Code = 1003001
  799. erelongInfo.RPCTimeout = params.RPCTimeout
  800. erelongInfo.ErrorPtr = &err
  801. log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s",
  802. *erelongInfo.ErrorPtr, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName)
  803. err = errors.WithMessage(ecode.AccountGRPCFrameError, "GET SEA PATROL FAIL")
  804. return nil, err
  805. }
  806. // 整理数据
  807. for _, chunkItemList := range chunkResult {
  808. for _, item := range chunkItemList {
  809. if item != nil {
  810. userResult[item.Mid] = item
  811. }
  812. }
  813. }
  814. return
  815. }
  816. // GetUserFc ...
  817. // 获取用户粉丝
  818. func GetUserFc(ctx context.Context, UIDs []int64) (userResult map[int64]*relationV1.FeedGetUserFcBatchResp_RelationList, err error) {
  819. rpcChunkSize, RPCTimeout, err := relationT.GetChunkInfo(relationT.FansNum)
  820. params := relationT.ChunkCallInfo{ParamsName: "ufos", URLName: relationT.FansNum, ChunkSize: rpcChunkSize, RPCTimeout: RPCTimeout}
  821. userResult = make(map[int64]*relationV1.FeedGetUserFcBatchResp_RelationList)
  822. lens := len(UIDs)
  823. if lens <= 0 {
  824. return
  825. }
  826. // 批次
  827. params.ChunkNum = int64(math.Ceil(float64(lens) / float64(params.ChunkSize)))
  828. chunkResult := make([]map[int64]*relationV1.FeedGetUserFcBatchResp_RelationList, params.ChunkNum)
  829. wg, _ := errgroup.WithContext(ctx)
  830. for i := int64(1); i <= params.ChunkNum; i++ {
  831. x := i
  832. wg.Go(func() error {
  833. chunkUfosIds := make([]int64, 20)
  834. if x == params.ChunkNum {
  835. chunkUfosIds = UIDs[(x-1)*params.ChunkSize:]
  836. } else {
  837. chunkUfosIds = UIDs[(x-1)*params.ChunkSize : x*params.ChunkSize]
  838. }
  839. ret, err := dao.RelationApi.V1Feed.GetUserFcBatch(ctx, &relationV1.FeedGetUserFcBatchReq{Uids: chunkUfosIds})
  840. if err != nil {
  841. err = errors.WithMessage(ecode.AccountGRPCError, "GET SEA PATROL FAIL")
  842. log.Error("Call main.Account.Cards Error.Infos(%+v) error(%+v)", chunkUfosIds, err)
  843. }
  844. chunkResult[x-1] = ret.Data
  845. return nil
  846. })
  847. }
  848. if err := wg.Wait(); err != nil {
  849. erelongInfo := relationT.ErrLogStrut{}
  850. erelongInfo.ErrType = "GoRoutingWaitError"
  851. erelongInfo.URLName = relationT.FansNum
  852. erelongInfo.ErrDesc = relationT.GoRoutingErr
  853. erelongInfo.Code = 1003001
  854. erelongInfo.RPCTimeout = params.RPCTimeout
  855. erelongInfo.ErrorPtr = &err
  856. log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s",
  857. *erelongInfo.ErrorPtr, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName)
  858. err = errors.WithMessage(ecode.AccountGRPCFrameError, "GET SEA PATROL FAIL")
  859. return nil, err
  860. }
  861. // 整理数据
  862. for _, chunkItemList := range chunkResult {
  863. for _, item := range chunkItemList {
  864. if item != nil {
  865. userResult[item.Uid] = item
  866. }
  867. }
  868. }
  869. return
  870. }