achievement.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. package bws
  2. import (
  3. "context"
  4. "database/sql"
  5. "encoding/json"
  6. "fmt"
  7. "strconv"
  8. "time"
  9. bwsmdl "go-common/app/interface/main/activity/model/bws"
  10. "go-common/library/cache/redis"
  11. xsql "go-common/library/database/sql"
  12. "go-common/library/log"
  13. )
  14. const (
  15. _userAchieveKeyFmt = "bws_u_a_%d_%s"
  16. _userAchieveCntFmt = "bws_a_c_%d_%s"
  17. _bwsLotteryKeyFmt = "bws_l_%s_%d"
  18. _awardSQL = "UPDATE act_bws_user_achievements SET award = 2 where `key`= ? AND aid = ?"
  19. _achievementsSQL = "SELECT id,`name`,icon,dic,link_type,`unlock`,bid,icon_big,icon_active,icon_active_big,award,ctime,mtime,image,suit_id FROM act_bws_achievements WHERE del = 0 AND bid = ? ORDER BY ID"
  20. _userAchieveSQL = "SELECT id,aid,award FROM act_bws_user_achievements WHERE bid = ? AND `key` = ? AND del = 0"
  21. _userAchieveAddSQL = "INSERT INTO act_bws_user_achievements(bid,aid,award,`key`) VALUES(?,?,?,?)"
  22. _countAchievesSQL = "SELECT aid,COUNT(1) AS c FROM act_bws_user_achievements WHERE del = 0 AND bid = ? AND ctime BETWEEN ? AND ? GROUP BY aid HAVING c > 0"
  23. _nextDayHour = 16
  24. )
  25. func keyUserAchieve(bid int64, key string) string {
  26. return fmt.Sprintf(_userAchieveKeyFmt, bid, key)
  27. }
  28. func keyAchieveCnt(bid int64, day string) string {
  29. return fmt.Sprintf(_userAchieveCntFmt, bid, day)
  30. }
  31. func keyLottery(aid int64, day string) string {
  32. if day == "" {
  33. day = time.Now().Format("20060102")
  34. }
  35. return fmt.Sprintf(_bwsLotteryKeyFmt, day, aid)
  36. }
  37. // Award achievement award
  38. func (d *Dao) Award(c context.Context, key string, aid int64) (err error) {
  39. if _, err = d.db.Exec(c, _awardSQL, key, aid); err != nil {
  40. log.Error("Award: db.Exec(%d,%s) error(%v)", aid, key, err)
  41. }
  42. return
  43. }
  44. // RawAchievements achievements list
  45. func (d *Dao) RawAchievements(c context.Context, bid int64) (res *bwsmdl.Achievements, err error) {
  46. var (
  47. rows *xsql.Rows
  48. rs []*bwsmdl.Achievement
  49. )
  50. if rows, err = d.db.Query(c, _achievementsSQL, bid); err != nil {
  51. log.Error("RawAchievements: db.Exec(%d) error(%v)", bid, err)
  52. return
  53. }
  54. defer rows.Close()
  55. for rows.Next() {
  56. r := new(bwsmdl.Achievement)
  57. if err = rows.Scan(&r.ID, &r.Name, &r.Icon, &r.Dic, &r.LockType, &r.Unlock, &r.Bid, &r.IconBig, &r.IconActive, &r.IconActiveBig, &r.Award, &r.Ctime, &r.Mtime, &r.Image, &r.SuitID); err != nil {
  58. log.Error("RawAchievements:row.Scan() error(%v)", err)
  59. return
  60. }
  61. rs = append(rs, r)
  62. }
  63. if len(rs) > 0 {
  64. res = new(bwsmdl.Achievements)
  65. res.Achievements = rs
  66. }
  67. return
  68. }
  69. // RawUserAchieves get user achievements from db.
  70. func (d *Dao) RawUserAchieves(c context.Context, bid int64, key string) (rs []*bwsmdl.UserAchieve, err error) {
  71. var (
  72. rows *xsql.Rows
  73. )
  74. if rows, err = d.db.Query(c, _userAchieveSQL, bid, key); err != nil {
  75. log.Error("RawUserAchieves: db.Query error(%v)", err)
  76. return
  77. }
  78. defer rows.Close()
  79. for rows.Next() {
  80. r := new(bwsmdl.UserAchieve)
  81. if err = rows.Scan(&r.ID, &r.Aid, &r.Award); err != nil {
  82. log.Error("RawUserAchieves:row.Scan() error(%v)", err)
  83. return
  84. }
  85. rs = append(rs, r)
  86. }
  87. return
  88. }
  89. // RawAchieveCounts achievements user count
  90. func (d *Dao) RawAchieveCounts(c context.Context, bid int64, day string) (res []*bwsmdl.CountAchieves, err error) {
  91. var (
  92. rows *xsql.Rows
  93. )
  94. start, _ := time.Parse("20060102-15:04:05", day+"-00:00:00")
  95. end, _ := time.Parse("20060102-15:04:05", day+"-23:59:59")
  96. if rows, err = d.db.Query(c, _countAchievesSQL, bid, start, end); err != nil {
  97. log.Error("RawCountAchieves: db.Exec(%d) error(%v)", bid, err)
  98. return
  99. }
  100. defer rows.Close()
  101. for rows.Next() {
  102. r := new(bwsmdl.CountAchieves)
  103. if err = rows.Scan(&r.Aid, &r.Count); err != nil {
  104. log.Error("RawCountAchieves:row.Scan() error(%v)", err)
  105. return
  106. }
  107. res = append(res, r)
  108. }
  109. return
  110. }
  111. // AddUserAchieve .
  112. func (d *Dao) AddUserAchieve(c context.Context, bid, aid, award int64, key string) (lastID int64, err error) {
  113. var res sql.Result
  114. if res, err = d.db.Exec(c, _userAchieveAddSQL, bid, aid, award, key); err != nil {
  115. log.Error("AddUserAchieve error d.db.Exec(%d,%d,%s) error(%v)", bid, aid, key, err)
  116. return
  117. }
  118. return res.LastInsertId()
  119. }
  120. // CacheUserAchieves .
  121. func (d *Dao) CacheUserAchieves(c context.Context, bid int64, key string) (res []*bwsmdl.UserAchieve, err error) {
  122. var (
  123. values []interface{}
  124. cacheKey = keyUserAchieve(bid, key)
  125. conn = d.redis.Get(c)
  126. )
  127. defer conn.Close()
  128. if values, err = redis.Values(conn.Do("ZRANGE", cacheKey, 0, -1)); err != nil {
  129. log.Error("CacheUserAchieves conn.Do(ZRANGE, %s) error(%v)", cacheKey, err)
  130. return
  131. } else if len(values) == 0 {
  132. return
  133. }
  134. for len(values) > 0 {
  135. var bs []byte
  136. if values, err = redis.Scan(values, &bs); err != nil {
  137. log.Error("CacheUserAchieves redis.Scan(%v) error(%v)", values, err)
  138. return
  139. }
  140. item := new(bwsmdl.UserAchieve)
  141. if err = json.Unmarshal(bs, &item); err != nil {
  142. log.Error("CacheUserAchieves conn.Do(ZRANGE, %s) error(%v)", cacheKey, err)
  143. continue
  144. }
  145. res = append(res, item)
  146. }
  147. return
  148. }
  149. // AddCacheUserAchieves .
  150. func (d *Dao) AddCacheUserAchieves(c context.Context, bid int64, data []*bwsmdl.UserAchieve, key string) (err error) {
  151. var bs []byte
  152. if len(data) == 0 {
  153. return
  154. }
  155. cacheKey := keyUserAchieve(bid, key)
  156. conn := d.redis.Get(c)
  157. defer conn.Close()
  158. args := redis.Args{}.Add(cacheKey)
  159. for _, v := range data {
  160. if bs, err = json.Marshal(v); err != nil {
  161. log.Error("AddCacheUserAchieves json.Marshal() error(%v)", err)
  162. return
  163. }
  164. args = args.Add(v.ID).Add(bs)
  165. }
  166. if err = conn.Send("ZADD", args...); err != nil {
  167. log.Error("AddCacheUserAchieves conn.Send(ZADD, %s, %v) error(%v)", cacheKey, args, err)
  168. return
  169. }
  170. if err = conn.Send("EXPIRE", cacheKey, d.userAchExpire); err != nil {
  171. log.Error("AddCacheUserAchieves conn.Send(Expire, %s) error(%v)", cacheKey, err)
  172. return
  173. }
  174. if err = conn.Flush(); err != nil {
  175. log.Error("AddCacheUserAchieves conn.Flush error(%v)", err)
  176. return
  177. }
  178. for i := 0; i < 2; i++ {
  179. if _, err = conn.Receive(); err != nil {
  180. log.Error("AddCacheUserAchieves conn.Receive() error(%v)", err)
  181. return
  182. }
  183. }
  184. return
  185. }
  186. // DelCacheUserAchieves .
  187. func (d *Dao) DelCacheUserAchieves(c context.Context, bid int64, key string) (err error) {
  188. cacheKey := keyUserAchieve(bid, key)
  189. conn := d.redis.Get(c)
  190. defer conn.Close()
  191. if _, err = conn.Do("DEL", cacheKey); err != nil {
  192. log.Error("DelCacheUserAchieves conn.Do(DEL) key(%s) error(%v)", cacheKey, err)
  193. }
  194. return
  195. }
  196. // AppendUserAchievesCache .
  197. func (d *Dao) AppendUserAchievesCache(c context.Context, bid int64, key string, achieve *bwsmdl.UserAchieve) (err error) {
  198. var (
  199. bs []byte
  200. ok bool
  201. cacheKey = keyUserAchieve(bid, key)
  202. conn = d.redis.Get(c)
  203. )
  204. defer conn.Close()
  205. if ok, err = redis.Bool(conn.Do("EXPIRE", cacheKey, d.userAchExpire)); err != nil || !ok {
  206. log.Error("AppendUserAchievesCache conn.Do(EXPIRE %s) error(%v)", key, err)
  207. return
  208. }
  209. args := redis.Args{}.Add(cacheKey)
  210. if bs, err = json.Marshal(achieve); err != nil {
  211. log.Error("AppendUserAchievesCache json.Marshal() error(%v)", err)
  212. return
  213. }
  214. args = args.Add(achieve.ID).Add(bs)
  215. if err = conn.Send("ZADD", args...); err != nil {
  216. log.Error("AddCacheUserAchieves conn.Send(ZADD, %s, %v) error(%v)", cacheKey, args, err)
  217. return
  218. }
  219. if err = conn.Send("EXPIRE", cacheKey, d.userAchExpire); err != nil {
  220. log.Error("AddCacheUserAchieves conn.Send(Expire, %s) error(%v)", cacheKey, err)
  221. return
  222. }
  223. if err = conn.Flush(); err != nil {
  224. log.Error("AddCacheUserAchieves conn.Flush error(%v)", err)
  225. return
  226. }
  227. for i := 0; i < 2; i++ {
  228. if _, err = conn.Receive(); err != nil {
  229. log.Error("AddCacheUserAchieves conn.Receive() error(%v)", err)
  230. return
  231. }
  232. }
  233. return
  234. }
  235. // CacheAchieveCounts get achieve counts from cache
  236. func (d *Dao) CacheAchieveCounts(c context.Context, bid int64, day string) (res []*bwsmdl.CountAchieves, err error) {
  237. var (
  238. bss []int64
  239. key = keyAchieveCnt(bid, day)
  240. conn = d.redis.Get(c)
  241. )
  242. defer conn.Close()
  243. if bss, err = redis.Int64s(conn.Do("HGETALL", key)); err != nil {
  244. log.Error("CacheAchieveCounts conn.Do(HGETALL,%s) error(%v)", key, err)
  245. return
  246. }
  247. for i := 1; i < len(bss); i += 2 {
  248. item := &bwsmdl.CountAchieves{Aid: bss[i-1], Count: bss[i]}
  249. res = append(res, item)
  250. }
  251. return
  252. }
  253. // AddCacheAchieveCounts set achieve counts to cache
  254. func (d *Dao) AddCacheAchieveCounts(c context.Context, bid int64, res []*bwsmdl.CountAchieves, day string) (err error) {
  255. if len(res) == 0 {
  256. return
  257. }
  258. key := keyAchieveCnt(bid, day)
  259. conn := d.redis.Get(c)
  260. defer conn.Close()
  261. if err = conn.Send("DEL", key); err != nil {
  262. log.Error("AddCacheAchieveCounts conn.Send(DEL, %s) error(%v)", key, err)
  263. return
  264. }
  265. args := redis.Args{}.Add(key)
  266. for _, v := range res {
  267. args = args.Add(v.Aid).Add(v.Count)
  268. }
  269. if err = conn.Send("HMSET", args...); err != nil {
  270. log.Error("AddCacheAchieveCounts conn.Send(HMSET, %s) error(%v)", key, err)
  271. return
  272. }
  273. if err = conn.Send("EXPIRE", key, d.achCntExpire); err != nil {
  274. log.Error("AddCacheAchieveCounts conn.Send(Expire, %s, %d) error(%v)", key, d.achCntExpire, err)
  275. return
  276. }
  277. if err = conn.Flush(); err != nil {
  278. log.Error("AddCacheAchieveCounts conn.Flush error(%v)", err)
  279. return
  280. }
  281. for i := 0; i < 2; i++ {
  282. if _, err = conn.Receive(); err != nil {
  283. log.Error("conn.Receive() error(%v)", err)
  284. return
  285. }
  286. }
  287. return
  288. }
  289. // IncrCacheAchieveCounts incr achieve counts to cache
  290. func (d *Dao) IncrCacheAchieveCounts(c context.Context, bid, aid int64, day string) (err error) {
  291. var (
  292. key = keyAchieveCnt(bid, day)
  293. conn = d.redis.Get(c)
  294. )
  295. defer conn.Close()
  296. if err = conn.Send("EXPIRE", key, d.achCntExpire); err != nil {
  297. log.Error("IncrCacheAchieveCounts conn.Send(Expire, %s, %d) error(%v)", key, d.achCntExpire, err)
  298. return
  299. }
  300. if err = conn.Send("HINCRBY", key, aid, 1); err != nil {
  301. log.Error("IncrCacheAchieveCounts conn.Send(HMSET, %s, %d) error(%v)", key, aid, err)
  302. return
  303. }
  304. if err = conn.Flush(); err != nil {
  305. log.Error("IncrCacheAchieveCounts conn.Flush error(%v)", err)
  306. return
  307. }
  308. for i := 0; i < 2; i++ {
  309. if _, err = conn.Receive(); err != nil {
  310. log.Error("conn.Receive() error(%v)", err)
  311. return
  312. }
  313. }
  314. return
  315. }
  316. // DelCacheAchieveCounts delete achieve cnt cache.
  317. func (d *Dao) DelCacheAchieveCounts(c context.Context, bid int64, day string) (err error) {
  318. cacheKey := keyAchieveCnt(bid, day)
  319. conn := d.redis.Get(c)
  320. defer conn.Close()
  321. if _, err = conn.Do("DEL", cacheKey); err != nil {
  322. log.Error("DelCacheAchieveCounts conn.Do(DEL) key(%s) error(%v)", cacheKey, err)
  323. }
  324. return
  325. }
  326. // AddLotteryMidCache add lottery mid cache.
  327. func (d *Dao) AddLotteryMidCache(c context.Context, aid, mid int64) (err error) {
  328. now := time.Now()
  329. hour := now.Hour()
  330. dayInt, _ := strconv.ParseInt(now.Format("20060102"), 10, 64)
  331. if hour >= _nextDayHour {
  332. dayInt = dayInt + 1
  333. }
  334. cacheKey := keyLottery(aid, strconv.FormatInt(dayInt, 10))
  335. conn := d.redis.Get(c)
  336. defer conn.Close()
  337. if _, err = conn.Do("SADD", cacheKey, mid); err != nil {
  338. log.Error("AddLotteryCache conn.Do(LPUSH, %s, %d) error(%v)", cacheKey, mid, err)
  339. }
  340. return
  341. }
  342. // CacheLotteryMid .
  343. func (d *Dao) CacheLotteryMid(c context.Context, aid int64, day string) (mid int64, err error) {
  344. var (
  345. cacheKey = keyLottery(aid, day)
  346. conn = d.redis.Get(c)
  347. )
  348. defer conn.Close()
  349. if mid, err = redis.Int64(conn.Do("SPOP", cacheKey)); err != nil && err != redis.ErrNil {
  350. log.Error("LotteryMidCache SPOP key(%s) error(%v)", cacheKey, err)
  351. }
  352. return
  353. }
  354. // CacheLotteryMids .
  355. func (d *Dao) CacheLotteryMids(c context.Context, aid int64, day string) (mids []int64, err error) {
  356. var cacheKey string
  357. conn := d.redis.Get(c)
  358. defer conn.Close()
  359. cacheKey = keyLottery(aid, day)
  360. if mids, err = redis.Int64s(conn.Do("SMEMBERS", cacheKey)); err != nil {
  361. if err == redis.ErrNil {
  362. err = nil
  363. return
  364. }
  365. log.Error("redis.Int64s(conn.Do(SMEMEBERS,%s)) error(%v)", cacheKey, err)
  366. }
  367. return
  368. }