redis.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. package dao
  2. import (
  3. "context"
  4. "fmt"
  5. "strconv"
  6. "go-common/app/admin/main/reply/model"
  7. "go-common/library/cache/redis"
  8. "go-common/library/log"
  9. )
  10. const (
  11. _prefixIdx = "i_"
  12. _prefixNewRootIdx = "ri_"
  13. _prefixAuditIdx = "ai_%d_%d"
  14. // 针对大忽悠时间被删除评论的人的MID
  15. _prefixAdminDelMid = "mid_%d"
  16. // f_{折叠类型,根评论还是评论区}_{评论区ID或者根评论ID}
  17. _foldedReplyFmt = "f_%s_%d"
  18. // dialog
  19. _prefixDialogIdx = "d_%d"
  20. _maxCount = 20000
  21. )
  22. func keyFolderIdx(kind string, ID int64) string {
  23. return fmt.Sprintf(_foldedReplyFmt, kind, ID)
  24. }
  25. func keyDelMid(mid int64) string {
  26. return fmt.Sprintf(_prefixAdminDelMid, mid)
  27. }
  28. // KeyMainIdx ...
  29. func keyMainIdx(oid int64, tp, sort int32) string {
  30. if oid > _oidOverflow {
  31. return fmt.Sprintf("%s_%d_%d_%d", _prefixIdx, oid, tp, sort)
  32. }
  33. return _prefixIdx + strconv.FormatInt((oid<<16)|(int64(tp)<<8)|int64(sort), 10)
  34. }
  35. // keyDialogIdx ...
  36. func keyDialogIdx(dialog int64) string {
  37. return fmt.Sprintf(_prefixDialogIdx, dialog)
  38. }
  39. // KeyRootIdx ...
  40. func keyRootIdx(root int64) string {
  41. return _prefixNewRootIdx + strconv.FormatInt(root, 10)
  42. }
  43. func keyIdx(oid int64, tp, sort int32) string {
  44. if oid > _oidOverflow {
  45. return fmt.Sprintf("%s_%d_%d_%d", _prefixIdx, oid, tp, sort)
  46. }
  47. return _prefixIdx + strconv.FormatInt((oid<<16)|(int64(tp)<<8)|int64(sort), 10)
  48. }
  49. func keyNewRootIdx(rpID int64) string {
  50. return _prefixNewRootIdx + strconv.FormatInt(rpID, 10)
  51. }
  52. func keyAuditIdx(oid int64, tp int32) string {
  53. return fmt.Sprintf(_prefixAuditIdx, oid, tp)
  54. }
  55. func (d *Dao) ExsistsDelMid(c context.Context, mid int64) (ok bool, err error) {
  56. conn := d.redis.Get(c)
  57. defer conn.Close()
  58. key := keyDelMid(mid)
  59. if ok, err = redis.Bool(conn.Do("EXISTS", key)); err != nil {
  60. log.Error("conn.Do(EXISTS, %s) error(%v)", key, err)
  61. }
  62. return
  63. }
  64. func (d *Dao) SetDelMid(c context.Context, mid int64) (err error) {
  65. conn := d.redis.Get(c)
  66. defer conn.Close()
  67. // 15天内
  68. if err = conn.Send("SETEX", keyDelMid(mid), 86400*15, 1); err != nil {
  69. log.Error("redis SETEX(%s) error(%v)", keyDelMid(mid), err)
  70. }
  71. return
  72. }
  73. // ExpireIndex set expire time for index.
  74. func (d *Dao) ExpireIndex(c context.Context, oid int64, typ, sort int32) (ok bool, err error) {
  75. conn := d.redis.Get(c)
  76. defer conn.Close()
  77. if ok, err = redis.Bool(conn.Do("EXPIRE", keyIdx(oid, typ, sort), d.redisExpire)); err != nil {
  78. log.Error("conn.Do(EXPIRE) error(%v)", err)
  79. }
  80. return
  81. }
  82. // ExpireNewChildIndex set expire time for root's index.
  83. func (d *Dao) ExpireNewChildIndex(c context.Context, root int64) (ok bool, err error) {
  84. conn := d.redis.Get(c)
  85. defer conn.Close()
  86. if ok, err = redis.Bool(conn.Do("EXPIRE", keyNewRootIdx(root), d.redisExpire)); err != nil {
  87. log.Error("conn.Do(EXPIRE) error(%v)", err)
  88. }
  89. return
  90. }
  91. // TopChildReply ...
  92. func (d *Dao) TopChildReply(c context.Context, root, child int64) (err error) {
  93. conn := d.redis.Get(c)
  94. defer conn.Close()
  95. if _, err = conn.Do("ZADD", keyNewRootIdx(root), 0, child); err != nil {
  96. return
  97. }
  98. return
  99. }
  100. // CountReplies get count of reply.
  101. func (d *Dao) CountReplies(c context.Context, oid int64, tp, sort int32) (count int, err error) {
  102. key := keyIdx(oid, tp, sort)
  103. conn := d.redis.Get(c)
  104. defer conn.Close()
  105. if count, err = redis.Int(conn.Do("ZCARD", key)); err != nil {
  106. log.Error("CountReplies error(%v)", err)
  107. }
  108. return
  109. }
  110. // MinScore get the lowest score from sorted set
  111. func (d *Dao) MinScore(c context.Context, oid int64, tp int32, sort int32) (score int32, err error) {
  112. key := keyIdx(oid, tp, sort)
  113. conn := d.redis.Get(c)
  114. defer conn.Close()
  115. values, err := redis.Values(conn.Do("ZRANGE", key, 0, 0, "WITHSCORES"))
  116. if err != nil {
  117. log.Error("conn.Do(ZREVRANGE, %s) error(%v)", key, err)
  118. return
  119. }
  120. if len(values) != 2 {
  121. err = fmt.Errorf("redis zrange items(%v) length not 2", values)
  122. return
  123. }
  124. var id int64
  125. redis.Scan(values, &id, &score)
  126. return
  127. }
  128. // AddFloorIndex add index by floor.
  129. func (d *Dao) AddFloorIndex(c context.Context, rp *model.Reply) (err error) {
  130. min, err := d.MinScore(c, rp.Oid, rp.Type, model.SortByFloor)
  131. if err != nil {
  132. log.Error("s.dao.Redis.AddFloorIndex failed , oid(%d) type(%d) err(%v)", rp.Oid, rp.Type, err)
  133. } else if rp.Floor <= min {
  134. return
  135. }
  136. key := keyIdx(rp.Oid, rp.Type, model.SortByFloor)
  137. conn := d.redis.Get(c)
  138. defer conn.Close()
  139. if err = conn.Send("ZADD", key, rp.Floor, rp.ID); err != nil {
  140. log.Error("conn.Send error(%v)", err)
  141. return
  142. }
  143. if err = conn.Send("EXPIRE", key, d.redisExpire); err != nil {
  144. log.Error("conn.Send error(%v)", err)
  145. return
  146. }
  147. if err = conn.Flush(); err != nil {
  148. log.Error("conn.Flush error(%v)", err)
  149. return
  150. }
  151. if _, err = conn.Receive(); err != nil {
  152. log.Error("conn.Receive error(%v)", err)
  153. return
  154. }
  155. return
  156. }
  157. // AddCountIndex add index by count.
  158. func (d *Dao) AddCountIndex(c context.Context, rp *model.Reply) (err error) {
  159. if rp.IsTop() {
  160. return
  161. }
  162. var count int
  163. if count, err = d.CountReplies(c, rp.Oid, rp.Type, model.SortByCount); err != nil {
  164. return
  165. } else if count >= _maxCount {
  166. var min int32
  167. if min, err = d.MinScore(c, rp.Oid, rp.Type, model.SortByCount); err != nil {
  168. return
  169. }
  170. if rp.RCount <= min {
  171. return
  172. }
  173. }
  174. key := keyIdx(rp.Oid, rp.Type, model.SortByCount)
  175. conn := d.redis.Get(c)
  176. defer conn.Close()
  177. if err = conn.Send("ZADD", key, int64(rp.RCount)<<32|(int64(rp.Floor)&0xFFFFFFFF), rp.ID); err != nil {
  178. log.Error("conn.Send error(%v)", err)
  179. return
  180. }
  181. if err = conn.Send("EXPIRE", key, d.redisExpire); err != nil {
  182. log.Error("conn.Send error(%v)", err)
  183. return
  184. }
  185. if err = conn.Flush(); err != nil {
  186. log.Error("conn.Flush error(%v)", err)
  187. return
  188. }
  189. if _, err = conn.Receive(); err != nil {
  190. log.Error("conn.Receive error(%v)", err)
  191. return
  192. }
  193. return
  194. }
  195. // AddLikeIndex add index by like.
  196. func (d *Dao) AddLikeIndex(c context.Context, rp *model.Reply, rpt *model.Report) (err error) {
  197. if rp.IsTop() {
  198. return
  199. }
  200. var rptCn int32
  201. if rpt != nil {
  202. rptCn = rpt.Count
  203. }
  204. score := int64((float32(rp.Like+model.WeightLike) / float32(rp.Hate+model.WeightHate+rptCn)) * 100)
  205. score = score<<32 | (int64(rp.RCount) & 0xFFFFFFFF)
  206. var count int
  207. if count, err = d.CountReplies(c, rp.Oid, rp.Type, model.SortByLike); err != nil {
  208. return
  209. } else if count >= _maxCount {
  210. var min int32
  211. if min, err = d.MinScore(c, rp.Oid, rp.Type, model.SortByLike); err != nil {
  212. return
  213. }
  214. if score <= int64(min) {
  215. return
  216. }
  217. }
  218. key := keyIdx(rp.Oid, rp.Type, model.SortByLike)
  219. conn := d.redis.Get(c)
  220. defer conn.Close()
  221. if err = conn.Send("ZADD", key, score, rp.ID); err != nil {
  222. log.Error("conn.Send error(%v)", err)
  223. return
  224. }
  225. if err = conn.Send("EXPIRE", key, d.redisExpire); err != nil {
  226. log.Error("conn.Send error(%v)", err)
  227. return
  228. }
  229. if err = conn.Flush(); err != nil {
  230. log.Error("conn.Flush error(%v)", err)
  231. return
  232. }
  233. if _, err = conn.Receive(); err != nil {
  234. log.Error("conn.Receive() error(%v)", err)
  235. return
  236. }
  237. return
  238. }
  239. // DelIndexBySort delete index by sort.
  240. func (d *Dao) DelIndexBySort(c context.Context, rp *model.Reply, sort int32) (err error) {
  241. key := keyIdx(rp.Oid, rp.Type, sort)
  242. conn := d.redis.Get(c)
  243. defer conn.Close()
  244. if _, err = conn.Do("ZREM", key, rp.ID); err != nil {
  245. log.Error("conn.Do(ZREM) error(%v)", err)
  246. }
  247. return
  248. }
  249. // DelReplyIndex delete reply index.
  250. func (d *Dao) DelReplyIndex(c context.Context, rp *model.Reply) (err error) {
  251. var (
  252. key string
  253. n int
  254. )
  255. conn := d.redis.Get(c)
  256. defer conn.Close()
  257. if rp.Root == 0 {
  258. key = keyIdx(rp.Oid, rp.Type, model.SortByFloor)
  259. err = conn.Send("ZREM", key, rp.ID)
  260. key = keyIdx(rp.Oid, rp.Type, model.SortByCount)
  261. err = conn.Send("ZREM", key, rp.ID)
  262. key = keyIdx(rp.Oid, rp.Type, model.SortByLike)
  263. err = conn.Send("ZREM", key, rp.ID)
  264. n += 3
  265. } else {
  266. if rp.Dialog != 0 {
  267. key = keyDialogIdx(rp.Dialog)
  268. err = conn.Send("ZREM", key, rp.ID)
  269. n++
  270. }
  271. key = keyNewRootIdx(rp.Root)
  272. err = conn.Send("ZREM", key, rp.ID)
  273. n++
  274. }
  275. if err != nil {
  276. log.Error("conn.Send error(%v)", err)
  277. return
  278. }
  279. if err = conn.Flush(); err != nil {
  280. log.Error("conn.Flush error(%v)", err)
  281. return
  282. }
  283. for i := 0; i < n; i++ {
  284. if _, err = conn.Receive(); err != nil {
  285. log.Error("conn.Receive error(%v)", err)
  286. return
  287. }
  288. }
  289. return
  290. }
  291. // AddNewChildIndex add root reply index by floor.
  292. func (d *Dao) AddNewChildIndex(c context.Context, rp *model.Reply) (err error) {
  293. key := keyNewRootIdx(rp.Root)
  294. conn := d.redis.Get(c)
  295. defer conn.Close()
  296. if err = conn.Send("ZADD", key, rp.Floor, rp.ID); err != nil {
  297. log.Error("conn.Send error(%v)", err)
  298. return
  299. }
  300. if err = conn.Send("EXPIRE", key, d.redisExpire); err != nil {
  301. log.Error("conn.Send error(%v)", err)
  302. return
  303. }
  304. if err = conn.Flush(); err != nil {
  305. log.Error("conn.Flush error(%v)", err)
  306. return
  307. }
  308. if _, err = conn.Receive(); err != nil {
  309. log.Error("conn.Receive() error(%v)", err)
  310. return
  311. }
  312. return
  313. }
  314. // DelAuditIndex delete audit reply cache.
  315. func (d *Dao) DelAuditIndex(c context.Context, rp *model.Reply) (err error) {
  316. key := keyAuditIdx(rp.Oid, rp.Type)
  317. conn := d.redis.Get(c)
  318. defer conn.Close()
  319. if err = conn.Send("ZREM", key, rp.ID); err != nil {
  320. log.Error("conn.Send(ZREM %s) error(%v)", key, err)
  321. return
  322. }
  323. if err = conn.Flush(); err != nil {
  324. log.Error("conn.Flush error(%v)", err)
  325. return
  326. }
  327. if _, err = conn.Receive(); err != nil {
  328. log.Error("conn.Receive() error(%v)", err)
  329. return
  330. }
  331. return
  332. }
  333. // RemReplyFromRedis ...
  334. func (d *Dao) RemReplyFromRedis(c context.Context, keyMapping map[string][]int64) (err error) {
  335. conn := d.redis.Get(c)
  336. defer conn.Close()
  337. count := 0
  338. for key, rpIDs := range keyMapping {
  339. if len(rpIDs) == 0 {
  340. continue
  341. }
  342. args := make([]interface{}, 0, 1+len(rpIDs))
  343. args = append(args, key)
  344. for _, rpID := range rpIDs {
  345. args = append(args, rpID)
  346. }
  347. if err = conn.Send("ZREM", args...); err != nil {
  348. log.Error("conn.Send(ZREM %s) error(%v)", key, err)
  349. return
  350. }
  351. count++
  352. }
  353. if err = conn.Flush(); err != nil {
  354. log.Error("conn.Flush error(%v)", err)
  355. return
  356. }
  357. for i := 0; i < count; i++ {
  358. if _, err = conn.Receive(); err != nil {
  359. log.Error("conn.Receive() error(%v)", err)
  360. return
  361. }
  362. }
  363. return
  364. }
  365. // ExpireFolder ...
  366. func (d *Dao) ExpireFolder(c context.Context, kind string, ID int64) (ok bool, err error) {
  367. conn := d.redis.Get(c)
  368. defer conn.Close()
  369. if ok, err = redis.Bool(conn.Do("EXPIRE", keyFolderIdx(kind, ID), d.redisExpire)); err != nil {
  370. log.Error("conn.Do(EXPIRE) error(%v)", err)
  371. }
  372. return
  373. }
  374. // AddFolder ...
  375. func (d *Dao) AddFolder(c context.Context, keyMapping map[string][]*model.Reply) (err error) {
  376. conn := d.redis.Get(c)
  377. defer conn.Close()
  378. count := 0
  379. for key, rps := range keyMapping {
  380. var args []interface{}
  381. args = append(args, key)
  382. for _, rp := range rps {
  383. args = append(args, rp.Floor)
  384. args = append(args, rp.ID)
  385. }
  386. if err = conn.Send("ZADD", args...); err != nil {
  387. log.Error("conn.Send(ZADD %s) error(%v)", key, err)
  388. return
  389. }
  390. count++
  391. if err = conn.Send("EXPIRE", key, d.redisExpire); err != nil {
  392. return
  393. }
  394. count++
  395. }
  396. if err = conn.Flush(); err != nil {
  397. log.Error("conn.Flush error(%v)", err)
  398. return
  399. }
  400. for i := 0; i < count; i++ {
  401. if _, err = conn.Receive(); err != nil {
  402. log.Error("conn.Receive() error(%v)", err)
  403. return
  404. }
  405. }
  406. return
  407. }
  408. // RemFolder ...
  409. func (d *Dao) RemFolder(c context.Context, kind string, ID, rpID int64) (err error) {
  410. conn := d.redis.Get(c)
  411. defer conn.Close()
  412. key := keyFolderIdx(kind, ID)
  413. if _, err = conn.Do("ZREM", key, rpID); err != nil {
  414. log.Error("conn.Do(ZREM) error(%v)", err)
  415. }
  416. return
  417. }