CDK.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. const logger = require('../utils/log')
  2. interface CDKInfo {
  3. itenList : string, // 物品列表
  4. batch : number, // 当前批次CDK描述
  5. serverList: string // 服务器ID列表
  6. cnt : number
  7. }
  8. interface CDKData {
  9. batch : string, // json字符串
  10. code : string, // json字符串
  11. }
  12. let CDKCache:Map<string,number> = new Map()
  13. const code:string[] = ["0","c","e","u","m",
  14. "k","d","7","x","f",
  15. "9","j","w","6","8",
  16. "t","1","h","4","p",
  17. "y","3","2","b","5","n"]
  18. const codeMap:Map<string,number> = new Map([
  19. ['0',0],["c",1],["e", 2],["u", 3],["m",4],
  20. ["k", 5],["d",6],["7", 7],["x", 8],["f", 9],
  21. ["9", 10],["j",11],["w",12],["6",13],["8",14],
  22. ["t",15],["1",16],["h",17],["4",18],["p",19],
  23. ["y",20],["3",21],["2",22],["b",23],["5",24],["n",25]
  24. ])
  25. const unit = 20
  26. const bit = unit
  27. const bit2 = unit * unit
  28. const maxCDKRand = 25
  29. const redis_batch_incr = "cdk_batch"
  30. const redis_cdk_batch = "cdk_" // cdk批次信息
  31. const redis_cdk = "hcdk_" // 批次对应cdk hset
  32. function transNumber(num:number):[number,number,number]{
  33. let first = 0
  34. let second = 0
  35. if (num >= bit2){
  36. first = Math.floor(num / bit2)
  37. }
  38. if (num >= bit){
  39. let t = num - (first * bit2)
  40. second = Math.floor(t / bit)
  41. }
  42. let third = num - (first * bit2) - (second * bit)
  43. return [first,second,third]
  44. }
  45. function calcNumber(first:number,second:number,third:number) {
  46. if (first === undefined || second === undefined || third === undefined) {
  47. return -1
  48. }
  49. if (first > unit || second > unit || third > unit) {
  50. return -1
  51. }
  52. return first * bit2 + second * bit + third
  53. }
  54. function generateCDK(batch:number , idx:number) {
  55. let ret = ""
  56. for (let i = 0; i <= 1;i++) {
  57. let r = (Math.floor(maxCDKRand * Math.random()) % 20) + 2 // 保证数字在2 - 22之间错在首字母0
  58. ret = ret + code[r]
  59. }
  60. let [idx_f,idx_s,idx_t] = transNumber(idx)
  61. ret = ret + code[idx_t] + code[idx_s] + code[idx_f] // 321
  62. let [batch_f,batch_s,batch_t] = transNumber(batch)
  63. // 是否需要检测是否超标
  64. ret = ret + code[batch_s] + code[batch_t] + code[batch_f] // 231
  65. for (let i = 0; i <= 1;i++) {
  66. let r = Math.floor(maxCDKRand * Math.random())
  67. ret = ret + code[r]
  68. }
  69. return ret
  70. }
  71. function decodeCDK(code:string):[boolean,number,number] {
  72. if (code.length != 10) {
  73. return [false,0,0]
  74. }
  75. let idx = calcNumber(codeMap.get(code[4]),codeMap.get(code[3]),codeMap.get(code[2]))
  76. if (idx < 0 ) {
  77. return [false,0,0]
  78. }
  79. let batch = calcNumber(codeMap.get(code[7]),codeMap.get(code[5]),codeMap.get(code[6]))
  80. if (batch < 0) {
  81. return [false,0,0]
  82. }
  83. return [true,batch,idx]
  84. }
  85. class CDK {
  86. async genCDK (ctx,cnt:number,useCnt:number,serverList:string,itemList:string) {
  87. const redisClient = ctx.redis.client;
  88. let batch = await redisClient.incr(redis_batch_incr)
  89. let batch_info_key = redis_cdk_batch + batch
  90. let data : CDKInfo = {
  91. itenList:itemList,
  92. serverList:serverList,
  93. batch: batch,
  94. cnt:useCnt
  95. }
  96. // 将批次数据存入redis
  97. await redisClient.set(batch_info_key,JSON.stringify(data))
  98. const pipeline = redisClient.pipeline();
  99. const cdk_hset_key = redis_cdk + batch
  100. // 生成cdk代码
  101. for (let i = 1; i <= cnt;i++) {
  102. let cdk = generateCDK(batch,i)
  103. pipeline.hset(cdk_hset_key,cdk,1)
  104. }
  105. // 执行管道代码
  106. return await pipeline.exec()
  107. }
  108. async getCDK(ctx,batch:number){
  109. const redisClient = ctx.redis.client;
  110. let curBatch = await redisClient.get(redis_batch_incr)
  111. if (Number(curBatch) < batch) {
  112. return ""
  113. }
  114. let batch_info_key = redis_cdk_batch + batch
  115. let batch_info = await redisClient.get(batch_info_key)
  116. const cdk_hset_key = redis_cdk + batch
  117. let ret = await redisClient.hgetall(cdk_hset_key)
  118. /*let cdkList = ret.reduce((acc:any,value,index) => {
  119. if (index % 2 == 1) {
  120. acc.push(acc,value)
  121. }
  122. return acc
  123. })*/
  124. let cdkdata : CDKData = {
  125. batch:batch_info,
  126. code: ret
  127. }
  128. return JSON.stringify(cdkdata)
  129. }
  130. async getCDKItemList(ctx,code:string) {
  131. logger.info(`收到cdk is :${code}`)
  132. const redisClient = ctx.redis.client
  133. let [ok,batch,index] = decodeCDK(code)
  134. if (!ok) {
  135. return ""
  136. }
  137. let batch_info_key = redis_cdk_batch + batch
  138. let batch_info_ret = await redisClient.get(batch_info_key)
  139. if (batch_info_ret == undefined || batch_info_ret == null ) {
  140. return ""
  141. }
  142. return batch_info_ret
  143. }
  144. async useCDK(ctx,code:string) {
  145. logger.info(` checkCDK 收到cdk is :${code}`)
  146. let [ok,batch,index] = decodeCDK(code)
  147. if (!ok) {
  148. return "invalid code"
  149. }
  150. const redisClient = ctx.redis.client;
  151. let cdk_hset_key = redis_cdk + batch
  152. // 必须保持原子性,只能用eval
  153. let evalStr = `
  154. local cdk = redis.call('hget',KEYS[1],KEYS[2])
  155. if not cdk then
  156. return -1
  157. end
  158. redis.call('hdel',KEYS[1],KEYS[2])
  159. return 0
  160. `
  161. let ret = await redisClient.eval(evalStr,2,cdk_hset_key,code)
  162. if (ret == -1) {
  163. return 'cdk not found'
  164. }
  165. return "success"
  166. }
  167. async checkCDK(ctx,code:string,serverId : number) {
  168. logger.info(` checkCDK 收到cdk is :${code}`)
  169. let [ok,batch,index] = decodeCDK(code)
  170. if (!ok) {
  171. return "invalid code"
  172. }
  173. let time = CDKCache.get(code)
  174. if (time != undefined && time > Date.now()) {
  175. return "invalid code"
  176. }
  177. const redisClient = ctx.redis.client;
  178. // 先判断是否满足batch
  179. let batch_info_key = redis_cdk_batch + batch
  180. let batch_info_ret = await redisClient.get(batch_info_key)
  181. if (batch_info_ret == undefined || batch_info_ret == null ) {
  182. return "batch not found"
  183. }
  184. let batch_info = JSON.parse(batch_info_ret) as CDKInfo
  185. let jsonret = JSON.parse(batch_info.serverList)
  186. let serverList = jsonret as number[]
  187. let isServer = false
  188. for(let i = 0;i < serverList.length;i++) {
  189. if (serverList[i] == serverId) {
  190. isServer = true
  191. break
  192. }
  193. }
  194. if(!isServer) {
  195. return "serverId error"
  196. }
  197. let cdk_hset_key = redis_cdk + batch
  198. // 必须保持原子性,只能用eval
  199. let evalStr = `
  200. local cdk = redis.call('hget',KEYS[1],KEYS[2])
  201. if not cdk then
  202. return -1
  203. end
  204. return 0
  205. `
  206. let ret = await redisClient.eval(evalStr,2,cdk_hset_key,code)
  207. if (ret == -1) {
  208. return 'cdk not found'
  209. }
  210. CDKCache.set(code,Date.now() + 2000)
  211. return "success"
  212. }
  213. }
  214. module.exports = new CDK()