channel_archive.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. package service
  2. import (
  3. "context"
  4. "sync"
  5. "time"
  6. "go-common/app/interface/main/space/conf"
  7. "go-common/app/interface/main/space/model"
  8. arcmdl "go-common/app/service/main/archive/api"
  9. "go-common/library/ecode"
  10. "go-common/library/log"
  11. "go-common/library/sync/errgroup"
  12. xtime "go-common/library/time"
  13. )
  14. const _aidBulkSize = 50
  15. // AddChannelArc add channel archive.
  16. func (s *Service) AddChannelArc(c context.Context, mid, cid int64, aids []int64) (fakeAids []int64, err error) {
  17. var (
  18. lastID int64
  19. orderNum int
  20. chAids, addAids []int64
  21. arcs map[int64]*arcmdl.Arc
  22. videos []*model.ChannelArc
  23. videoMap map[int64]int64
  24. remainVideos []*model.ChannelArcSort
  25. ts = time.Now()
  26. )
  27. fakeAids = make([]int64, 0)
  28. if _, _, err = s.channel(c, mid, cid); err != nil {
  29. log.Error("s.dao.Channel(%d,%d) error(%v)", mid, cid, err)
  30. return
  31. }
  32. if videos, err = s.dao.ChannelVideos(c, mid, cid, false); err != nil {
  33. log.Error("s.dao.channelVideos(%d,%d) error(%v)", mid, cid, err)
  34. return
  35. } else if orderNum = len(videos); orderNum > 0 {
  36. if len(aids)+orderNum > conf.Conf.Rule.MaxChArcLimit {
  37. err = ecode.ChMaxArcCount
  38. return
  39. }
  40. videoMap = make(map[int64]int64)
  41. for _, video := range videos {
  42. chAids = append(chAids, video.Aid)
  43. videoMap[video.Aid] = video.Aid
  44. }
  45. }
  46. for _, aid := range aids {
  47. if _, ok := videoMap[aid]; ok {
  48. fakeAids = append(fakeAids, aid)
  49. } else {
  50. addAids = append(addAids, aid)
  51. }
  52. }
  53. if len(addAids) == 0 {
  54. err = ecode.ChAidsExist
  55. return
  56. }
  57. if err = s.arcsCheck(c, mid, chAids); err != nil {
  58. return
  59. }
  60. if arcs, err = s.archives(c, addAids); err != nil {
  61. log.Error("s.arc.Archive3(%v) error(%v)", addAids, err)
  62. return
  63. }
  64. for _, aid := range addAids {
  65. if arc, ok := arcs[aid]; !ok || !arc.IsNormal() || arc.Author.Mid != mid {
  66. fakeAids = append(fakeAids, aid)
  67. continue
  68. }
  69. orderNum++
  70. remainVideos = append(remainVideos, &model.ChannelArcSort{Aid: aid, OrderNum: orderNum})
  71. }
  72. if len(remainVideos) == 0 {
  73. err = ecode.ChAidsExist
  74. return
  75. }
  76. if lastID, err = s.dao.AddChannelArc(c, mid, cid, ts, remainVideos); err != nil {
  77. log.Error("s.dao.AddChannelArc(mid:%d,cid:%d) error(%v)", mid, cid, err)
  78. return
  79. } else if lastID > 0 {
  80. var arcs []*model.ChannelArc
  81. for _, v := range remainVideos {
  82. arc := &model.ChannelArc{ID: lastID, Mid: mid, Cid: cid, Aid: v.Aid, OrderNum: v.OrderNum, Mtime: xtime.Time(ts.Unix())}
  83. arcs = append(arcs, arc)
  84. }
  85. s.dao.AddChannelArcCache(context.Background(), mid, cid, arcs)
  86. }
  87. return
  88. }
  89. func (s *Service) arcsCheck(c context.Context, mid int64, aids []int64) (err error) {
  90. var arcs map[int64]*arcmdl.Arc
  91. if arcs, err = s.archives(c, aids); err != nil {
  92. log.Error("s.archives error(%v)", err)
  93. return
  94. }
  95. for _, aid := range aids {
  96. if arc, ok := arcs[aid]; !ok || !arc.IsNormal() || arc.Author.Mid != mid {
  97. err = ecode.ChFakeAid
  98. return
  99. }
  100. }
  101. return
  102. }
  103. // DelChannelArc delete channel archive.
  104. func (s *Service) DelChannelArc(c context.Context, mid, cid, aid int64) (err error) {
  105. var (
  106. affected int64
  107. orderNum int
  108. videos []*model.ChannelArc
  109. )
  110. if videos, err = s.dao.ChannelVideos(c, mid, cid, false); err != nil {
  111. log.Error("s.dao.Channel(%d,%d) error(%v)", mid, cid, err)
  112. return
  113. } else if len(videos) == 0 {
  114. err = ecode.ChNoArcs
  115. return
  116. } else {
  117. check := false
  118. for _, video := range videos {
  119. if aid == video.Aid {
  120. check = true
  121. orderNum = video.OrderNum
  122. }
  123. }
  124. if !check {
  125. err = ecode.ChNoArc
  126. return
  127. }
  128. }
  129. if affected, err = s.dao.DelChannelArc(c, mid, cid, aid, orderNum); err != nil {
  130. log.Error("s.dao.DelChannelArc(%d,%d) error(%v)", mid, aid, err)
  131. return
  132. } else if affected > 0 {
  133. s.dao.DelChannelArcCache(c, mid, cid, aid)
  134. s.setChannelArcSortCache(c, mid, cid)
  135. }
  136. return
  137. }
  138. // SortChannelArc sort channel archive.
  139. func (s *Service) SortChannelArc(c context.Context, mid, cid, aid int64, orderNum int) (err error) {
  140. var (
  141. videos []*model.ChannelArc
  142. bfSortBegin, bfSortEnd, chSort, afSort []*model.ChannelArcSort
  143. affected int64
  144. aidIndex, aidOn int
  145. aidCheck bool
  146. ts = time.Now()
  147. )
  148. if videos, err = s.dao.ChannelVideos(c, mid, cid, false); err != nil {
  149. log.Error("s.dao.ChannelVideos(%d,%d) error(%v)", mid, cid, err)
  150. return
  151. } else if len(videos) == 0 {
  152. err = ecode.ChNoArcs
  153. return
  154. } else {
  155. videoLen := len(videos)
  156. if orderNum > videoLen {
  157. err = ecode.RequestErr
  158. return
  159. }
  160. for index, video := range videos {
  161. if aid == video.Aid {
  162. aidCheck = true
  163. aidIndex = index
  164. aidOn = video.OrderNum
  165. break
  166. }
  167. }
  168. if !aidCheck {
  169. err = ecode.RequestErr
  170. return
  171. }
  172. if orderNum > aidOn {
  173. chSort = append(chSort, &model.ChannelArcSort{Aid: aid, OrderNum: orderNum})
  174. for i, v := range videos {
  175. if i < videoLen-orderNum {
  176. bfSortBegin = append(bfSortBegin, &model.ChannelArcSort{Aid: v.Aid, OrderNum: v.OrderNum})
  177. } else if i >= videoLen-orderNum && i < aidIndex {
  178. chSort = append(chSort, &model.ChannelArcSort{Aid: v.Aid, OrderNum: v.OrderNum - 1})
  179. } else if i > aidIndex {
  180. bfSortEnd = append(bfSortEnd, &model.ChannelArcSort{Aid: v.Aid, OrderNum: v.OrderNum})
  181. }
  182. }
  183. } else if orderNum < aidOn {
  184. for i, v := range videos {
  185. if i < aidIndex {
  186. bfSortBegin = append(bfSortBegin, &model.ChannelArcSort{Aid: v.Aid, OrderNum: v.OrderNum})
  187. } else if i > aidIndex && i <= videoLen-orderNum {
  188. chSort = append(chSort, &model.ChannelArcSort{Aid: v.Aid, OrderNum: v.OrderNum + 1})
  189. } else if i > videoLen-orderNum {
  190. bfSortEnd = append(bfSortEnd, &model.ChannelArcSort{Aid: v.Aid, OrderNum: v.OrderNum})
  191. }
  192. }
  193. chSort = append(chSort, &model.ChannelArcSort{Aid: aid, OrderNum: orderNum})
  194. } else {
  195. return
  196. }
  197. afSort = append(afSort, bfSortBegin...)
  198. afSort = append(afSort, chSort...)
  199. afSort = append(afSort, bfSortEnd...)
  200. }
  201. if affected, err = s.dao.EditChannelArc(c, mid, cid, ts, chSort); err != nil {
  202. log.Error("s.dao.s.dao.EditChannelArc(%d,%d,%d,%d) error(%v)", mid, cid, aid, orderNum, err)
  203. return
  204. } else if affected > 0 {
  205. s.dao.SetChannelArcSortCache(c, mid, cid, afSort)
  206. }
  207. return
  208. }
  209. // ChannelVideos get channel and channel video info.
  210. func (s *Service) ChannelVideos(c context.Context, mid, cid int64, pn, ps int, isGuest, order bool) (res *model.ChannelDetail, err error) {
  211. var (
  212. channel *model.Channel
  213. start = (pn - 1) * ps
  214. end = start + ps - 1
  215. )
  216. if channel, err = s.Channel(c, mid, cid); err != nil {
  217. return
  218. }
  219. res = &model.ChannelDetail{Channel: channel}
  220. res.Archives, err = s.channelArc(c, mid, cid, start, end, isGuest, order)
  221. return
  222. }
  223. func (s *Service) channelVideos(c context.Context, mid, cid int64, start, end int, order bool) (res []*model.ChannelArc, err error) {
  224. var (
  225. videos []*model.ChannelArc
  226. addCache = true
  227. )
  228. if res, err = s.dao.ChannelArcsCache(c, mid, cid, start, end, order); err != nil {
  229. addCache = false
  230. } else if len(res) > 0 {
  231. return
  232. }
  233. if videos, err = s.dao.ChannelVideos(c, mid, cid, order); err != nil {
  234. log.Error("s.dao.ChannelVideos(%d,%d) error(%v)", mid, cid, err)
  235. return
  236. } else if len(videos) > 0 {
  237. if addCache {
  238. s.cache.Do(c, func(c context.Context) {
  239. s.dao.SetChannelArcsCache(c, mid, cid, videos)
  240. s.setChannelArcSortCache(c, mid, cid)
  241. })
  242. }
  243. length := len(videos)
  244. if length < start {
  245. res = make([]*model.ChannelArc, 0)
  246. return
  247. }
  248. if length > end {
  249. res = videos[start : end+1]
  250. } else {
  251. res = videos[start:]
  252. }
  253. }
  254. return
  255. }
  256. // CheckChannelVideo check useless channel video.
  257. func (s *Service) CheckChannelVideo(c context.Context, mid, cid int64) (err error) {
  258. var (
  259. videos []*model.ChannelArc
  260. aids []int64
  261. )
  262. if videos, err = s.dao.ChannelVideos(c, mid, cid, false); err != nil {
  263. log.Error("s.dao.channelVideos(%d,%d) error(%v)", mid, cid, err)
  264. return
  265. }
  266. for _, v := range videos {
  267. aids = append(aids, v.Aid)
  268. }
  269. err = s.arcsCheck(c, mid, aids)
  270. return
  271. }
  272. func (s *Service) channelArc(c context.Context, mid, cid int64, start, end int, isGuest, order bool) (res []*arcmdl.Arc, err error) {
  273. var (
  274. videoAids []*model.ChannelArc
  275. archives map[int64]*arcmdl.Arc
  276. aids []int64
  277. )
  278. if videoAids, err = s.channelVideos(c, mid, cid, start, end, order); err != nil {
  279. log.Error("s.dao.ChannelVideos(%d,%d) error(%v)", mid, cid, err)
  280. return
  281. } else if len(videoAids) == 0 {
  282. res = _emptyChArc
  283. return
  284. }
  285. for _, video := range videoAids {
  286. aids = append(aids, video.Aid)
  287. }
  288. if archives, err = s.archives(c, aids); err != nil {
  289. log.Error("s.arc.Archives3(%v) error(%v)", aids, err)
  290. return
  291. }
  292. for _, video := range videoAids {
  293. if arc, ok := archives[video.Aid]; ok {
  294. if arc.IsNormal() {
  295. if arc.Access >= 10000 {
  296. arc.Stat.View = -1
  297. }
  298. res = append(res, arc)
  299. } else {
  300. res = append(res, &arcmdl.Arc{Aid: video.Aid, Title: arc.Title, Pic: arc.Pic, Stat: arc.Stat, PubDate: arc.PubDate, State: arc.State})
  301. }
  302. }
  303. }
  304. return
  305. }
  306. func (s *Service) setChannelArcSortCache(c context.Context, mid, cid int64) (err error) {
  307. var (
  308. videos []*model.ChannelArc
  309. sorts []*model.ChannelArcSort
  310. )
  311. if videos, err = s.dao.ChannelVideos(c, mid, cid, false); err != nil {
  312. log.Error("s.dao.ChannelVideos(%d,%d) error(%v)", mid, cid, err)
  313. return
  314. } else if len(videos) == 0 {
  315. return
  316. }
  317. for _, v := range videos {
  318. sort := &model.ChannelArcSort{Aid: v.Aid, OrderNum: v.OrderNum}
  319. sorts = append(sorts, sort)
  320. }
  321. return s.dao.SetChannelArcSortCache(c, mid, cid, sorts)
  322. }
  323. func (s *Service) archives(c context.Context, aids []int64) (archives map[int64]*arcmdl.Arc, err error) {
  324. var (
  325. mutex = sync.Mutex{}
  326. aidsLen = len(aids)
  327. group, errCtx = errgroup.WithContext(c)
  328. )
  329. archives = make(map[int64]*arcmdl.Arc, aidsLen)
  330. for i := 0; i < aidsLen; i += _aidBulkSize {
  331. var partAids []int64
  332. if i+_aidBulkSize > aidsLen {
  333. partAids = aids[i:]
  334. } else {
  335. partAids = aids[i : i+_aidBulkSize]
  336. }
  337. group.Go(func() (err error) {
  338. var arcs *arcmdl.ArcsReply
  339. arg := &arcmdl.ArcsRequest{Aids: partAids}
  340. if arcs, err = s.arcClient.Arcs(errCtx, arg); err != nil {
  341. log.Error("s.arcClient.Arcs(%v) error(%v)", partAids, err)
  342. return
  343. }
  344. mutex.Lock()
  345. for _, v := range arcs.Arcs {
  346. archives[v.Aid] = v
  347. }
  348. mutex.Unlock()
  349. return
  350. })
  351. }
  352. err = group.Wait()
  353. return
  354. }