history.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. "sort"
  6. "strconv"
  7. "time"
  8. "go-common/app/interface/main/history/model"
  9. arcmdl "go-common/app/service/main/archive/model/archive"
  10. "go-common/library/ecode"
  11. "go-common/library/log"
  12. "go-common/library/net/metadata"
  13. )
  14. var (
  15. _countLimit = 50
  16. _emptyVideos = []*model.Video{}
  17. _emptyHis = []*model.History{}
  18. _emptyHismap = make(map[int64]*model.History)
  19. )
  20. func (s *Service) key(aid int64, typ int8) string {
  21. if typ < model.TypeArticle {
  22. return strconv.FormatInt(aid, 10)
  23. }
  24. return fmt.Sprintf("%d_%d", aid, typ)
  25. }
  26. // AddHistories batch update history.
  27. // +wd:ignore
  28. func (s *Service) AddHistories(c context.Context, mid int64, typ int8, ip string, hs []*model.History) (err error) {
  29. var (
  30. ok bool
  31. his, h *model.History
  32. hm2 map[string]*model.History
  33. hmc, res map[int64]*model.History
  34. expire = time.Now().Unix() - 60*60*24*90
  35. )
  36. if len(hs) > _countLimit {
  37. return ecode.TargetNumberLimit
  38. }
  39. s.serviceAdds(mid, hs)
  40. if hm2, err = s.historyDao.Map(c, mid); err != nil {
  41. return
  42. }
  43. if typ < model.TypeArticle {
  44. if hmc, err = s.historyDao.CacheMap(c, mid); err != nil {
  45. return err
  46. }
  47. }
  48. res = make(map[int64]*model.History)
  49. for _, his = range hs {
  50. if his.Unix < expire {
  51. continue
  52. }
  53. if len(hm2) > 0 {
  54. if h, ok = hm2[s.key(his.Aid, his.TP)]; ok && his.Unix < h.Unix {
  55. continue
  56. }
  57. }
  58. if len(hmc) > 0 {
  59. if h, ok = hmc[his.Aid]; ok && his.Unix < h.Unix {
  60. continue
  61. }
  62. }
  63. // TODO comment && merge
  64. res[his.Aid] = his
  65. }
  66. if err = s.historyDao.AddMap(c, mid, res); err == nil {
  67. return
  68. }
  69. if typ < model.TypeArticle {
  70. s.historyDao.AddCacheMap(c, mid, res)
  71. }
  72. return nil
  73. }
  74. // AddHistory add hisotry progress into hbase.
  75. func (s *Service) AddHistory(c context.Context, mid, rtime int64, h *model.History) (err error) {
  76. if h.TP < model.TypeUnknown || h.TP > model.TypeComic {
  77. err = ecode.RequestErr
  78. return
  79. }
  80. if h.Aid == 0 {
  81. return ecode.RequestErr
  82. }
  83. if h.TP == model.TypeBangumi || h.TP == model.TypeMovie || h.TP == model.TypePGC {
  84. msg := playPro{
  85. Type: h.TP,
  86. SubType: h.STP,
  87. Mid: mid,
  88. Sid: h.Sid,
  89. Epid: h.Epid,
  90. Cid: h.Cid,
  91. Progress: h.Pro,
  92. IP: metadata.String(c, metadata.RemoteIP),
  93. Ts: h.Unix,
  94. RealTime: rtime,
  95. }
  96. s.addPlayPro(&msg)
  97. }
  98. // NOTE if login user to save history
  99. if mid == 0 {
  100. return
  101. }
  102. return s.addHistory(c, mid, h)
  103. }
  104. // Progress get view progress from cache/hbase.
  105. func (s *Service) Progress(c context.Context, mid int64, aids []int64) (res map[int64]*model.History, err error) {
  106. if mid == 0 {
  107. res = _emptyHismap
  108. return
  109. }
  110. if s.migration(mid) {
  111. res, err = s.servicePosition(c, mid, model.BusinessByTP(model.TypeUGC), aids)
  112. if err == nil {
  113. return
  114. }
  115. }
  116. if res, _, err = s.historyDao.Cache(c, mid, aids); err != nil {
  117. return
  118. } else if len(res) == 0 {
  119. res = _emptyHismap
  120. }
  121. return
  122. }
  123. // Position get view progress from cache/hbase.
  124. func (s *Service) Position(c context.Context, mid int64, aid int64, typ int8) (res *model.History, err error) {
  125. if mid == 0 {
  126. err = ecode.NothingFound
  127. return
  128. }
  129. if s.migration(mid) {
  130. var hm map[int64]*model.History
  131. hm, err = s.servicePosition(c, mid, model.BusinessByTP(typ), []int64{aid})
  132. if err == nil && hm != nil {
  133. if res = hm[aid]; res == nil {
  134. err = ecode.NothingFound
  135. }
  136. return
  137. }
  138. }
  139. if typ < model.TypeArticle {
  140. var hm map[int64]*model.History
  141. hm, _, err = s.historyDao.Cache(c, mid, []int64{aid})
  142. if err != nil {
  143. return
  144. }
  145. if len(hm) > 0 {
  146. if h, ok := hm[aid]; ok {
  147. res = h
  148. }
  149. }
  150. if res == nil {
  151. err = ecode.NothingFound
  152. }
  153. return
  154. }
  155. var mhis map[string]*model.History
  156. mhis, err = s.historyDao.Map(c, mid)
  157. if err != nil {
  158. return
  159. }
  160. if len(mhis) > 0 {
  161. key := fmt.Sprintf("%d_%d", aid, typ)
  162. if h, ok := mhis[key]; ok {
  163. res = h
  164. }
  165. }
  166. if res == nil {
  167. err = ecode.NothingFound
  168. }
  169. return
  170. }
  171. // addHistory add new history into set.
  172. func (s *Service) addHistory(c context.Context, mid int64, h *model.History) (err error) {
  173. var cmd int64
  174. // note: the type is video to increase experience of user .
  175. if h.TP < model.TypeArticle {
  176. s.historyDao.PushFirstQueue(c, mid, h.Aid, h.Unix)
  177. }
  178. if cmd, err = s.Shadow(c, mid); err != nil {
  179. return
  180. }
  181. if cmd == model.ShadowOn {
  182. return
  183. }
  184. h.Mid = mid
  185. s.serviceAdd(h)
  186. // note: the type is video to redis`cache .
  187. if h.TP >= model.TypeArticle {
  188. s.addProPub(h)
  189. if !s.conf.History.Pub {
  190. err = s.historyDao.Add(c, mid, h)
  191. }
  192. return
  193. }
  194. // NOTE first view
  195. if h.Pro < 30 && h.Pro != -1 {
  196. h.Pro = 0
  197. }
  198. // NOTE after 30s
  199. if err = s.historyDao.AddCache(c, mid, h); err != nil {
  200. return
  201. }
  202. s.addMerge(mid, h.Unix)
  203. return
  204. }
  205. // ClearHistory clear user's historys.
  206. func (s *Service) ClearHistory(c context.Context, mid int64, tps []int8) (err error) {
  207. s.serviceClear(mid, tps)
  208. if len(tps) == 0 {
  209. s.historyDao.ClearCache(c, mid)
  210. err = s.historyDao.Clear(c, mid)
  211. s.userActionLog(mid, model.HistoryClear)
  212. return
  213. }
  214. tpsMap := make(map[int8]bool)
  215. for _, tp := range tps {
  216. tpsMap[tp] = true
  217. }
  218. var (
  219. histories map[string]*model.History
  220. dels []*model.History
  221. chis map[int64]*model.History
  222. aids []int64
  223. )
  224. if histories, err = s.historyDao.Map(c, mid); err != nil {
  225. return
  226. }
  227. chis, _ = s.historyDao.CacheMap(c, mid)
  228. for _, v := range chis {
  229. histories[s.key(v.Aid, v.TP)] = v
  230. }
  231. logMap := make(map[int8]struct{})
  232. for _, h := range histories {
  233. oldType := h.TP
  234. h.ConvertType()
  235. if tpsMap[h.TP] {
  236. if (h.TP == model.TypeUGC) || (h.TP == model.TypePGC) {
  237. aids = append(aids, h.Aid)
  238. }
  239. h.TP = oldType
  240. dels = append(dels, h)
  241. logMap[oldType] = struct{}{}
  242. }
  243. }
  244. if len(dels) == 0 {
  245. return
  246. }
  247. if len(aids) > 0 {
  248. s.historyDao.DelCache(c, mid, aids)
  249. }
  250. if err = s.historyDao.Delete(c, mid, dels); err != nil {
  251. return
  252. }
  253. for k := range logMap {
  254. s.userActionLog(mid, fmt.Sprintf(model.HistoryClearTyp, model.BusinessByTP(k)))
  255. }
  256. return
  257. }
  258. // DelHistory delete user's history del archive .
  259. // +wd:ignore
  260. func (s *Service) DelHistory(ctx context.Context, mid int64, aids []int64, typ int8) (err error) {
  261. if err = s.serviceDels(ctx, mid, aids, typ); err != nil {
  262. return
  263. }
  264. if err = s.historyDao.DelAids(ctx, mid, aids); err != nil {
  265. return
  266. }
  267. if typ >= model.TypeArticle {
  268. return
  269. }
  270. return s.historyDao.DelCache(ctx, mid, aids)
  271. }
  272. // Videos get videos of user view history.
  273. // +wd:ignore
  274. func (s *Service) Videos(c context.Context, mid int64, pn, ps int, typ int8) (res []*model.Video, err error) {
  275. var (
  276. arc *arcmdl.View3
  277. ok bool
  278. arcs map[int64]*arcmdl.View3
  279. video *model.Video
  280. history []*model.History
  281. his *model.History
  282. aids, epids []int64
  283. aidFavs map[int64]bool
  284. epban map[int64]*model.Bangumi
  285. )
  286. res = _emptyVideos
  287. mOK := s.migration(mid)
  288. if mOK {
  289. businesses := []string{model.BusinessByTP(model.TypeUGC), model.BusinessByTP(model.TypePGC)}
  290. history, epids, err = s.servicePnPsCursor(c, mid, businesses, pn, ps)
  291. }
  292. if !mOK || err != nil {
  293. if history, epids, err = s.histories(c, mid, pn, ps, true); err != nil {
  294. return
  295. }
  296. }
  297. if len(history) == 0 {
  298. return
  299. }
  300. for _, his = range history {
  301. aids = append(aids, his.Aid)
  302. }
  303. if typ >= model.TypeArticle {
  304. // TODO Article info .
  305. return
  306. }
  307. // bangumi info
  308. if len(epids) > 0 {
  309. epban = s.bangumi(c, mid, epids)
  310. }
  311. // archive info
  312. arcAids := &arcmdl.ArgAids2{Aids: aids}
  313. if arcs, err = s.arcRPC.Views3(c, arcAids); err != nil {
  314. return
  315. } else if len(arcs) == 0 {
  316. return
  317. }
  318. // favorite info
  319. aidFavs = s.favoriteds(c, mid, aids)
  320. res = make([]*model.Video, 0, len(aids))
  321. for _, his = range history {
  322. if arc, ok = arcs[his.Aid]; !ok || arc.Archive3 == nil {
  323. continue
  324. }
  325. // NOTE all no pay
  326. arc.Rights.Movie = 0
  327. video = &model.Video{
  328. Archive3: arc.Archive3,
  329. ViewAt: his.Unix,
  330. DT: his.DT,
  331. STP: his.STP,
  332. TP: his.TP,
  333. Progress: his.Pro,
  334. Count: len(arc.Pages),
  335. }
  336. if aidFavs != nil {
  337. video.Favorite = aidFavs[his.Aid]
  338. }
  339. for n, p := range arc.Pages {
  340. if p.Cid == his.Cid {
  341. p.Page = int32(n + 1)
  342. video.Page = p
  343. break
  344. }
  345. }
  346. if video.TP == model.TypeBangumi || video.TP == model.TypeMovie || video.TP == model.TypePGC {
  347. if epban != nil {
  348. video.BangumiInfo = epban[his.Epid]
  349. }
  350. video.Count = 0
  351. }
  352. res = append(res, video)
  353. }
  354. return
  355. }
  356. // AVHistories return the user all av history.
  357. // +wd:ignore
  358. func (s *Service) AVHistories(c context.Context, mid int64) (hs []*model.History, err error) {
  359. if s.migration(mid) {
  360. businesses := []string{model.BusinessByTP(model.TypeUGC), model.BusinessByTP(model.TypePGC)}
  361. hs, _, err = s.servicePnPsCursor(c, mid, businesses, 1, s.conf.History.Max)
  362. if err == nil {
  363. return
  364. }
  365. }
  366. hs, _, err = s.histories(c, mid, 1, s.conf.History.Max, true)
  367. return
  368. }
  369. // Histories return the user all av history.
  370. func (s *Service) Histories(c context.Context, mid int64, typ int8, pn, ps int) (res []*model.Resource, err error) {
  371. var hs []*model.History
  372. mOK := s.migration(mid)
  373. if mOK {
  374. var businesses []string
  375. if typ > 0 {
  376. businesses = []string{model.BusinessByTP(typ)}
  377. }
  378. hs, _, err = s.servicePnPsCursor(c, mid, businesses, pn, ps)
  379. }
  380. if !mOK || err != nil {
  381. if typ >= model.TypeArticle {
  382. hs, err = s.platformHistories(c, mid, typ, pn, ps)
  383. } else {
  384. hs, _, err = s.histories(c, mid, pn, ps, false)
  385. }
  386. }
  387. if err != nil {
  388. return
  389. }
  390. if len(hs) == 0 {
  391. return
  392. }
  393. for _, h := range hs {
  394. h.ConvertType()
  395. r := &model.Resource{
  396. Mid: h.Mid,
  397. Oid: h.Aid,
  398. Sid: h.Sid,
  399. Epid: h.Epid,
  400. Cid: h.Cid,
  401. DT: h.DT,
  402. Pro: h.Pro,
  403. Unix: h.Unix,
  404. TP: h.TP,
  405. STP: h.STP,
  406. }
  407. res = append(res, r)
  408. }
  409. return
  410. }
  411. // histories get aids of user view history
  412. func (s *Service) histories(c context.Context, mid int64, pn, ps int, onlyAV bool) (his []*model.History, epids []int64, err error) {
  413. var (
  414. size int
  415. ok bool
  416. e, h *model.History
  417. mhis map[string]*model.History
  418. chis, ehis map[int64]*model.History
  419. dhis []*model.History
  420. start = (pn - 1) * ps
  421. end = start + ps - 1
  422. total = s.conf.History.Total
  423. )
  424. if mhis, err = s.historyDao.Map(c, mid); err != nil {
  425. err = nil
  426. mhis = make(map[string]*model.History)
  427. }
  428. chis, _ = s.historyDao.CacheMap(c, mid)
  429. for _, v := range chis {
  430. mhis[s.key(v.Aid, v.TP)] = v
  431. }
  432. if len(mhis) == 0 {
  433. his = _emptyHis
  434. return
  435. }
  436. ehis = make(map[int64]*model.History, len(mhis))
  437. for _, h = range mhis {
  438. if onlyAV && h.TP >= model.TypeArticle {
  439. continue
  440. }
  441. if (h.TP == model.TypeBangumi || h.TP == model.TypeMovie || h.TP == model.TypePGC) && h.Sid != 0 {
  442. if e, ok = ehis[h.Sid]; !ok || h.Unix > e.Unix {
  443. ehis[h.Sid] = h
  444. if e != nil {
  445. dhis = append(dhis, e)
  446. }
  447. }
  448. } else {
  449. his = append(his, h)
  450. }
  451. }
  452. for _, h = range ehis {
  453. if h.Epid != 0 {
  454. epids = append(epids, h.Epid)
  455. }
  456. his = append(his, h)
  457. }
  458. sort.Sort(model.Histories(his))
  459. if size = len(his); size > total {
  460. dhis = append(dhis, his[total:]...)
  461. s.delChan.Do(c, func(ctx context.Context) {
  462. s.historyDao.Delete(ctx, mid, dhis)
  463. })
  464. his = his[:total]
  465. size = total
  466. }
  467. switch {
  468. case size > start && size > end:
  469. his = his[start : end+1]
  470. case size > start && size <= end:
  471. his = his[start:]
  472. default:
  473. his = _emptyHis
  474. }
  475. return
  476. }
  477. // platformHistories get aids of user view history
  478. func (s *Service) platformHistories(c context.Context, mid int64, typ int8, pn, ps int) (his []*model.History, err error) {
  479. var (
  480. size int
  481. h *model.History
  482. mhis map[string]*model.History
  483. start = (pn - 1) * ps
  484. end = start + ps - 1
  485. total = s.conf.History.Total
  486. )
  487. if mhis, err = s.historyDao.Map(c, mid); err != nil {
  488. return
  489. }
  490. if len(mhis) == 0 {
  491. his = _emptyHis
  492. return
  493. }
  494. for _, h = range mhis {
  495. if typ != h.TP {
  496. continue
  497. }
  498. his = append(his, h)
  499. }
  500. sort.Sort(model.Histories(his))
  501. if size = len(his); size > total {
  502. his = his[:total]
  503. size = total
  504. }
  505. switch {
  506. case size > start && size > end:
  507. his = his[start : end+1]
  508. case size > start && size <= end:
  509. his = his[start:]
  510. default:
  511. his = _emptyHis
  512. }
  513. return
  514. }
  515. // HistoryType get aids of user view history
  516. // +wd:ignore
  517. func (s *Service) HistoryType(c context.Context, mid int64, typ int8, oids []int64, ip string) (his []*model.History, err error) {
  518. var (
  519. mhis map[string]*model.History
  520. )
  521. if s.migration(mid) {
  522. his, err = s.serviceHistoryType(c, mid, model.BusinessByTP(typ), oids)
  523. if err == nil {
  524. return
  525. }
  526. }
  527. if mhis, err = s.historyDao.Map(c, mid); err != nil {
  528. return
  529. }
  530. if len(mhis) == 0 {
  531. his = _emptyHis
  532. return
  533. }
  534. for _, oid := range oids {
  535. key := fmt.Sprintf("%d_%d", oid, typ)
  536. if h, ok := mhis[key]; ok && h != nil {
  537. his = append(his, h)
  538. }
  539. }
  540. return
  541. }
  542. // HistoryCursor return the user all av history.
  543. func (s *Service) HistoryCursor(c context.Context, mid, max, viewAt int64, ps int, tp int8, tps []int8, ip string) (res []*model.Resource, err error) {
  544. var hs []*model.History
  545. if s.migration(mid) {
  546. var businesses []string
  547. for _, b := range tps {
  548. businesses = append(businesses, model.BusinessByTP(b))
  549. }
  550. res, err = s.serviceHistoryCursor(c, mid, max, businesses, model.BusinessByTP(tp), viewAt, ps)
  551. if err == nil {
  552. return
  553. }
  554. }
  555. hs, err = s.historyCursor(c, mid, max, viewAt, ps, tp, tps, ip)
  556. if err != nil {
  557. return
  558. }
  559. if len(hs) == 0 {
  560. return
  561. }
  562. for _, h := range hs {
  563. r := &model.Resource{
  564. TP: h.TP,
  565. STP: h.STP,
  566. Mid: h.Mid,
  567. Oid: h.Aid,
  568. Sid: h.Sid,
  569. Epid: h.Epid,
  570. Cid: h.Cid,
  571. Business: h.Business,
  572. DT: h.DT,
  573. Pro: h.Pro,
  574. Unix: h.Unix,
  575. }
  576. res = append(res, r)
  577. }
  578. return
  579. }
  580. // historyCursor get aids of user view history.
  581. func (s *Service) historyCursor(c context.Context, mid, max, viewAt int64, ps int, tp int8, tps []int8, ip string) (his []*model.History, err error) {
  582. var (
  583. ok bool
  584. e, h *model.History
  585. mhis map[string]*model.History
  586. chis, ehis map[int64]*model.History
  587. dhis []*model.History
  588. total = s.conf.History.Total
  589. tpMap = make(map[int8]bool)
  590. )
  591. for _, tp := range tps {
  592. tpMap[tp] = true
  593. }
  594. if mhis, err = s.historyDao.Map(c, mid); err != nil {
  595. err = nil
  596. mhis = make(map[string]*model.History)
  597. }
  598. for k, v := range mhis {
  599. v.ConvertType()
  600. if (len(tps) > 0) && !tpMap[v.TP] {
  601. delete(mhis, k)
  602. }
  603. }
  604. chis, _ = s.historyDao.CacheMap(c, mid)
  605. for k, v := range chis {
  606. v.ConvertType()
  607. if (len(tps) > 0) && !tpMap[v.TP] {
  608. delete(chis, k)
  609. continue
  610. }
  611. mhis[s.key(v.Aid, v.TP)] = v
  612. }
  613. if len(mhis) == 0 {
  614. his = _emptyHis
  615. return
  616. }
  617. ehis = make(map[int64]*model.History, len(mhis))
  618. for _, h = range mhis {
  619. if (h.TP == model.TypePGC) && h.Sid != 0 {
  620. if e, ok = ehis[h.Sid]; !ok || h.Unix > e.Unix {
  621. ehis[h.Sid] = h
  622. if e != nil {
  623. dhis = append(dhis, e)
  624. }
  625. }
  626. } else {
  627. his = append(his, h)
  628. }
  629. }
  630. for _, h = range ehis {
  631. his = append(his, h)
  632. }
  633. sort.Sort(model.Histories(his))
  634. if len(his) > total {
  635. dhis = append(dhis, his[total:]...)
  636. s.delChan.Do(c, func(ctx context.Context) {
  637. s.historyDao.Delete(ctx, mid, dhis)
  638. })
  639. his = his[:total]
  640. }
  641. if viewAt != 0 || max != 0 && tp != 0 {
  642. for index, h := range his {
  643. if viewAt != 0 && h.Unix <= viewAt || h.Aid == max && h.TP == tp {
  644. index++
  645. if index+ps <= len(his) {
  646. return his[index : index+ps], nil
  647. }
  648. return his[index:], nil
  649. }
  650. }
  651. return _emptyHis, nil
  652. }
  653. if len(his) >= ps {
  654. return his[:ps], nil
  655. }
  656. return
  657. }
  658. // SetShadow set the user switch.
  659. // +wd:ignore
  660. func (s *Service) SetShadow(c context.Context, mid, value int64) (err error) {
  661. s.serviceHide(mid, value == model.ShadowOn)
  662. if err = s.historyDao.SetInfoShadow(c, mid, value); err != nil {
  663. return
  664. }
  665. return s.historyDao.SetShadowCache(c, mid, value)
  666. }
  667. // Delete .
  668. func (s *Service) Delete(ctx context.Context, mid int64, his []*model.History) (err error) {
  669. if err = s.serviceDel(ctx, mid, his); err != nil {
  670. return
  671. }
  672. if err = s.historyDao.Delete(ctx, mid, his); err != nil {
  673. return
  674. }
  675. var aids []int64
  676. for _, h := range his {
  677. if h.TP < model.TypeArticle {
  678. aids = append(aids, h.Aid)
  679. }
  680. }
  681. if len(aids) == 0 {
  682. return
  683. }
  684. return s.historyDao.DelCache(ctx, mid, aids)
  685. }
  686. // Shadow return the user switch by mid.
  687. // +wd:ignore
  688. func (s *Service) Shadow(c context.Context, mid int64) (value int64, err error) {
  689. var (
  690. ok bool
  691. cache = true
  692. )
  693. if s.migration(mid) {
  694. value, err = s.serviceHideState(c, mid)
  695. if err == nil {
  696. return
  697. }
  698. }
  699. if value, err = s.historyDao.ShadowCache(c, mid); err != nil {
  700. err = nil
  701. cache = false
  702. } else if value != model.ShadowUnknown {
  703. return
  704. }
  705. if value, err = s.historyDao.InfoShadow(c, mid); err != nil {
  706. ok = true
  707. }
  708. if cache {
  709. s.cache.Do(c, func(ctx context.Context) {
  710. s.historyDao.SetShadowCache(ctx, mid, value)
  711. if ok && value == model.ShadowOn {
  712. s.historyDao.SetInfoShadow(ctx, mid, value)
  713. }
  714. })
  715. }
  716. return
  717. }
  718. // FlushHistory flush to hbase from cache.
  719. func (s *Service) FlushHistory(c context.Context, mids []int64, stime int64) (err error) {
  720. var (
  721. aids, miss []int64
  722. res map[int64]*model.History
  723. limit = s.conf.History.Cache
  724. )
  725. for _, mid := range mids {
  726. if aids, err = s.historyDao.IndexCacheByTime(c, mid, stime); err != nil {
  727. log.Error("s.historyDao.IndexCacheByTime(%d,%v) error(%v)", mid, stime, err)
  728. err = nil
  729. continue
  730. }
  731. if len(aids) == 0 {
  732. continue
  733. }
  734. if res, miss, err = s.historyDao.Cache(c, mid, aids); err != nil {
  735. log.Error("historyDao.Cache(%d,%v) miss:%v error(%v)", mid, aids, miss, err)
  736. err = nil
  737. continue
  738. }
  739. // * typ < model.TypeArticle all can .
  740. if err = s.historyDao.AddMap(c, mid, res); err != nil {
  741. log.Error("historyDao.AddMap(%d,%+v) error(%v)", mid, res, err)
  742. err = nil
  743. }
  744. if err = s.historyDao.TrimCache(c, mid, limit); err != nil {
  745. log.Error("historyDao.TrimCache(%d,%d) error(%v)", mid, limit, err)
  746. err = nil
  747. }
  748. }
  749. return
  750. }
  751. func (s *Service) merge(hmap map[int64]int64) {
  752. var (
  753. size = int64(s.conf.History.Size)
  754. merges = make(map[int64][]*model.Merge, size)
  755. )
  756. for k, v := range hmap {
  757. merges[k%size] = append(merges[k%size], &model.Merge{Mid: k, Now: v})
  758. }
  759. for k, v := range merges {
  760. s.historyDao.Merge(context.TODO(), int64(k), v)
  761. }
  762. }
  763. func (s *Service) bangumi(c context.Context, mid int64, epids []int64) (bangumiMap map[int64]*model.Bangumi) {
  764. var n = 50
  765. bangumiMap = make(map[int64]*model.Bangumi, len(epids))
  766. for len(epids) > 0 {
  767. if n > len(epids) {
  768. n = len(epids)
  769. }
  770. epban, _ := s.historyDao.Bangumis(c, mid, epids[:n])
  771. epids = epids[n:]
  772. for k, v := range epban {
  773. bangumiMap[k] = v
  774. }
  775. }
  776. return
  777. }
  778. // ManagerHistory ManagerHistory.
  779. // +wd:ignore
  780. func (s *Service) ManagerHistory(c context.Context, onlyAV bool, mid int64) (his []*model.History, err error) {
  781. var (
  782. mhis map[string]*model.History
  783. chis, ehis map[int64]*model.History
  784. )
  785. if mhis, err = s.historyDao.Map(c, mid); err != nil {
  786. err = nil
  787. mhis = make(map[string]*model.History)
  788. }
  789. chis, _ = s.historyDao.CacheMap(c, mid)
  790. for _, v := range chis {
  791. mhis[s.key(v.Aid, v.TP)] = v
  792. }
  793. if len(mhis) == 0 {
  794. his = _emptyHis
  795. return
  796. }
  797. ehis = make(map[int64]*model.History, len(mhis))
  798. for _, h := range mhis {
  799. if onlyAV && h.TP >= model.TypeArticle {
  800. continue
  801. }
  802. if (h.TP == model.TypeBangumi || h.TP == model.TypeMovie || h.TP == model.TypePGC) && h.Sid != 0 {
  803. if e, ok := ehis[h.Sid]; !ok || h.Unix > e.Unix {
  804. ehis[h.Sid] = h
  805. }
  806. } else {
  807. his = append(his, h)
  808. }
  809. }
  810. for _, h := range ehis {
  811. his = append(his, h)
  812. }
  813. sort.Sort(model.Histories(his))
  814. return
  815. }