| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- const logger = require('../utils/log')
- interface CDKInfo {
- itenList : string, // 物品列表
- batch : number, // 当前批次CDK描述
- serverList: string // 服务器ID列表
- cnt : number
- }
- interface CDKData {
- batch : string, // json字符串
- code : string, // json字符串
- }
- let CDKCache:Map<string,number> = new Map()
- const code:string[] = ["0","c","e","u","m",
- "k","d","7","x","f",
- "9","j","w","6","8",
- "t","1","h","4","p",
- "y","3","2","b","5","n"]
- const codeMap:Map<string,number> = new Map([
- ['0',0],["c",1],["e", 2],["u", 3],["m",4],
- ["k", 5],["d",6],["7", 7],["x", 8],["f", 9],
- ["9", 10],["j",11],["w",12],["6",13],["8",14],
- ["t",15],["1",16],["h",17],["4",18],["p",19],
- ["y",20],["3",21],["2",22],["b",23],["5",24],["n",25]
- ])
- const unit = 20
- const bit = unit
- const bit2 = unit * unit
- const maxCDKRand = 25
- const redis_batch_incr = "cdk_batch"
- const redis_cdk_batch = "cdk_" // cdk批次信息
- const redis_cdk = "hcdk_" // 批次对应cdk hset
- function transNumber(num:number):[number,number,number]{
- let first = 0
- let second = 0
- if (num >= bit2){
- first = Math.floor(num / bit2)
- }
-
- if (num >= bit){
- let t = num - (first * bit2)
- second = Math.floor(t / bit)
- }
- let third = num - (first * bit2) - (second * bit)
- return [first,second,third]
- }
- function calcNumber(first:number,second:number,third:number) {
- if (first === undefined || second === undefined || third === undefined) {
- return -1
- }
- if (first > unit || second > unit || third > unit) {
- return -1
- }
- return first * bit2 + second * bit + third
- }
- function generateCDK(batch:number , idx:number) {
- let ret = ""
- for (let i = 0; i <= 1;i++) {
- let r = (Math.floor(maxCDKRand * Math.random()) % 20) + 2 // 保证数字在2 - 22之间错在首字母0
- ret = ret + code[r]
- }
- let [idx_f,idx_s,idx_t] = transNumber(idx)
- ret = ret + code[idx_t] + code[idx_s] + code[idx_f] // 321
- let [batch_f,batch_s,batch_t] = transNumber(batch)
- // 是否需要检测是否超标
- ret = ret + code[batch_s] + code[batch_t] + code[batch_f] // 231
- for (let i = 0; i <= 1;i++) {
- let r = Math.floor(maxCDKRand * Math.random())
- ret = ret + code[r]
- }
- return ret
- }
- function decodeCDK(code:string):[boolean,number,number] {
- if (code.length != 10) {
- return [false,0,0]
- }
- let idx = calcNumber(codeMap.get(code[4]),codeMap.get(code[3]),codeMap.get(code[2]))
- if (idx < 0 ) {
- return [false,0,0]
- }
- let batch = calcNumber(codeMap.get(code[7]),codeMap.get(code[5]),codeMap.get(code[6]))
- if (batch < 0) {
- return [false,0,0]
- }
- return [true,batch,idx]
- }
- class CDK {
- async genCDK (ctx,cnt:number,useCnt:number,serverList:string,itemList:string) {
- const redisClient = ctx.redis.client;
- let batch = await redisClient.incr(redis_batch_incr)
- let batch_info_key = redis_cdk_batch + batch
- let data : CDKInfo = {
- itenList:itemList,
- serverList:serverList,
- batch: batch,
- cnt:useCnt
- }
- // 将批次数据存入redis
- await redisClient.set(batch_info_key,JSON.stringify(data))
- const pipeline = redisClient.pipeline();
- const cdk_hset_key = redis_cdk + batch
- // 生成cdk代码
- for (let i = 1; i <= cnt;i++) {
- let cdk = generateCDK(batch,i)
- pipeline.hset(cdk_hset_key,cdk,1)
- }
- // 执行管道代码
- return await pipeline.exec()
- }
- async getCDK(ctx,batch:number){
- const redisClient = ctx.redis.client;
- let curBatch = await redisClient.get(redis_batch_incr)
- if (Number(curBatch) < batch) {
- return ""
- }
- let batch_info_key = redis_cdk_batch + batch
- let batch_info = await redisClient.get(batch_info_key)
- const cdk_hset_key = redis_cdk + batch
- let ret = await redisClient.hgetall(cdk_hset_key)
- /*let cdkList = ret.reduce((acc:any,value,index) => {
- if (index % 2 == 1) {
- acc.push(acc,value)
- }
- return acc
- })*/
- let cdkdata : CDKData = {
- batch:batch_info,
- code: ret
- }
- return JSON.stringify(cdkdata)
- }
- async getCDKItemList(ctx,code:string) {
- logger.info(`收到cdk is :${code}`)
- const redisClient = ctx.redis.client
- let [ok,batch,index] = decodeCDK(code)
- if (!ok) {
- return ""
- }
- let batch_info_key = redis_cdk_batch + batch
- let batch_info_ret = await redisClient.get(batch_info_key)
- if (batch_info_ret == undefined || batch_info_ret == null ) {
- return ""
- }
- return batch_info_ret
- }
- async useCDK(ctx,code:string) {
- logger.info(` checkCDK 收到cdk is :${code}`)
- let [ok,batch,index] = decodeCDK(code)
- if (!ok) {
- return "invalid code"
- }
- const redisClient = ctx.redis.client;
- let cdk_hset_key = redis_cdk + batch
- // 必须保持原子性,只能用eval
- let evalStr = `
- local cdk = redis.call('hget',KEYS[1],KEYS[2])
- if not cdk then
- return -1
- end
- redis.call('hdel',KEYS[1],KEYS[2])
- return 0
- `
- let ret = await redisClient.eval(evalStr,2,cdk_hset_key,code)
- if (ret == -1) {
- return 'cdk not found'
- }
- return "success"
- }
- async checkCDK(ctx,code:string,serverId : number) {
- logger.info(` checkCDK 收到cdk is :${code}`)
- let [ok,batch,index] = decodeCDK(code)
- if (!ok) {
- return "invalid code"
- }
- let time = CDKCache.get(code)
- if (time != undefined && time > Date.now()) {
- return "invalid code"
- }
- const redisClient = ctx.redis.client;
- // 先判断是否满足batch
- let batch_info_key = redis_cdk_batch + batch
- let batch_info_ret = await redisClient.get(batch_info_key)
- if (batch_info_ret == undefined || batch_info_ret == null ) {
- return "batch not found"
- }
- let batch_info = JSON.parse(batch_info_ret) as CDKInfo
- let jsonret = JSON.parse(batch_info.serverList)
- let serverList = jsonret as number[]
- let isServer = false
- for(let i = 0;i < serverList.length;i++) {
- if (serverList[i] == serverId) {
- isServer = true
- break
- }
- }
- if(!isServer) {
- return "serverId error"
- }
- let cdk_hset_key = redis_cdk + batch
- // 必须保持原子性,只能用eval
- let evalStr = `
- local cdk = redis.call('hget',KEYS[1],KEYS[2])
- if not cdk then
- return -1
- end
- return 0
- `
- let ret = await redisClient.eval(evalStr,2,cdk_hset_key,code)
- if (ret == -1) {
- return 'cdk not found'
- }
- CDKCache.set(code,Date.now() + 2000)
- return "success"
- }
- }
- module.exports = new CDK()
|