import IORedis from "ioredis"; import {IServer_Common_Config_Redis} from './../types/config'; var g_redis:InstanceType; export function getRedisInstance(){ return g_redis } export class Redis { private redis:InstanceType private watchMap:Map=new Map private parseType(value:any,type:any){ let t=typeof type; if(value==null) { return null } if(t=="boolean") { if(value=="true") { return true; } else { return false } } else if(t=="number") { return Number(value) } else if(t=="object") { try{ return JSON.parse(value) }catch(err){ return null } } else { return value } } constructor(info:IServer_Common_Config_Redis){ this.redis=new IORedis({ port:info.port, host:info.url, password:info.password, db:info.db }) // @ts-ignore this.redis.send_command('config', ['set', 'notify-keyspace-events', 'Ex'], ()=>{ let sub=this.redis.duplicate() sub.subscribe(`__keyevent@${info.db}__:expired`,()=>{ sub.on("message",(channel,key)=>{ if(this.watchMap.has(key)){ let func=this.watchMap.get(key) this.watchMap.delete(key) func(key) } }) sub.on("error",()=>{ this.watchMap.clear() }) }) }) g_redis=this; } listenExpired(key:string,func:{(key:string):void}){ this.watchMap.set(key,func) } getIORedis() { return this.redis; } async get(key:string,type:T):Promise { let ret=await this.redis.get(key) let value=this.parseType(ret,type); return value } async mget(key:string[],type:T):Promise { let ret=await this.redis.mget(key) ret=ret.map(item=>{ return this.parseType(item,type) }) return ret } async mset(obj:{ [param:string]:any }) { if(obj===null || obj===undefined) { return } await this.redis.mset(obj) } async set(key:string,value:any,ttl?:number) { if(value===null || value===undefined) { return } if(typeof value=="object") { if(ttl==-1) { await this.redis.set(key,JSON.stringify(value)) await this.redis.persist(key); } else { await this.redis.set(key,JSON.stringify(value),"EX",ttl) } } else { if(ttl==-1) { await this.redis.set(key,String(value)) await this.redis.persist(key); } else { await this.redis.set(key,String(value),"EX",ttl) } } } async scan(key:string):Promise { let index=0,values=[] do { let ret=await this.redis.scan(index,"MATCH",key); index=Number(ret[0]) values=values.concat(ret[1]); } while(index!=0) return values; } async getTTL(key:string):Promise { let ret=await this.redis.ttl(key); return ret; } async setTTL(key:string,seconds:number=-1):Promise { if(seconds==-1) { await this.redis.persist(key) } else { await this.redis.expire(key,seconds); } } async del(key:string) { await this.redis.del(key); } async exists(key:string) { let ret=await this.redis.exists(key) return !!ret } async flush() { await this.redis.flushdb() } async sGet(key:string):Promise { let exist=await this.exists(key) if(exist) { let ret=await this.redis.smembers(key) return ret; } return null; } async sSet(key:string,values:string[],ttl:number=-1) { if(values && values.length>0) { await this.redis.sadd(key,...values) await this.setTTL(key,ttl); } } async hGet(key:string,field:string):Promise { let exist=await this.exists(key) if(exist) { let ret=await this.redis.hget(key,field); return ret } return null; } async hSet(key:string,obj:{ [param:string]:any },ttl:number=-1){ if(Object.keys(obj).length>0) { await this.redis.hset(key,obj) await this.setTTL(key,ttl); } } async hGetAll(key:string) :Promise{ let exist=await this.exists(key) if(exist) { let ret=await this.redis.hgetall(key); return ret; } return null; } async hGetAllKey(key:string) { let exist=await this.exists(key) if(exist) { let ret=await this.redis.hkeys(key) return ret; } return null; } async hExists(key:string,field:string):Promise { let ret=await this.redis.hexists(key,field) return !!ret; } }