import { ResLogin, playerAppend, playerInfo } from "../shared/protocols/user/PtlLogin"; //进程内数据玩家字典 const GUD : { [key: string]: { gud: ResLogin['gud'], version: { pid : number, ver?: number } } } = {}; export async function clearGud(uid) { //玩家断线,清空uid数据 if(GUD[uid]){ console.log("玩家断线,清空GUD数据", uid); delete GUD[uid]; G.ioredis.del(`gudVersion:${uid}_pid`); G.ioredis.del(`gudVersion:${uid}_ver`); } //清空Redis缓存 G.ioredis.del(`tanxian:${uid}`); G.ioredis.del(`dxlt:${uid}`); }; /** * 获取玩家的gud数据 * !!!警告:因为数据会进程内缓存,请将返回值当做引用类型看待 * @param uid 玩家的uid * @returns */ export async function getGud(uid:string) : Promise{ let gud; if(GUD[uid]){ //如果本进程里存在,则判断版本号 let redisVersion = await G.ioredis.mget([`gudVersion:${uid}_pid`, `gudVersion:${uid}_ver`]); if(redisVersion[0]==null || redisVersion[1]==null || redisVersion[0].toString() != (GUD[uid].version.pid).toString()){ //最新的数据,已经不是本进程生成的了,则说明本进程持久了一份脏数据 delete GUD[uid]; }else{ if(redisVersion[1].toString() != (GUD[uid].version.ver).toString()){ //虽然数据是本进程生成的,但是版本号不一致,说明其他进程里更新过数据了 gud = await getGudFromDB(uid); GUD[uid].gud = gud; GUD[uid].version.ver = parseInt(redisVersion[1]); }else{ //本进程的数据是最新的,直接返回 gud = GUD[uid].gud; //console.log("getGud==>", uid); } } } if(!gud){ //本进程里没有,则直接从db获取 gud = await getGudFromDB(uid); } return gud; } /** * 更新玩家的数据,注意,这里只负责更新进程内的缓存数据及维护数据版本 * 实际DB的操作需要调用者自己做 * @param uid */ export async function setGud(uid:string, updateKV:{[key:string]:any}) : Promise{ let nver = await G.ioredis.incr(`gudVersion:${uid}_ver`); //如果数据不在本进程,只更新版本即可 if(!GUD[uid])return; GUD[uid].version.ver = nver; Object.assign(GUD[uid].gud, updateKV); return GUD[uid].gud; } /** * 在本进程初始化玩家的数据 * 该过程会将玩家数据从db里加热到内存 * 仅允许在玩家登录的时候执行该方法 * 并且玩家离线时,需要销毁对应的数据 * 以避免多个进程持有同一个玩家的数据导致数据统一性错误 * @param uid * @param _gud 在登录时,前面的逻辑里已经查询过一次db了,没必要再查一次浪费性能,这种情况下则直接传入_gud */ export async function initGud(uid:string, _gud?:ResLogin['gud']) : Promise{ let gud = _gud || await getGudFromDB(uid); if(gud){ console.log('initGud==>', uid); //设置gud版本号 await G.ioredis.set(`gudVersion:${uid}_pid`, process.pid ); let ver = await G.ioredis.incr(`gudVersion:${uid}_ver`); GUD[uid] = { gud : gud, version : { pid : process.pid, ver : ver } }; } return GUD?.[uid]?.gud; } /** * 从db从获取玩家的gud数据 * 业务逻辑中,请统一使用getGud方法,不然可能会造成数据一致性错误 * @param uid */ export async function getGudFromDB(uid:string) : Promise{ //console.warn("getGudFromDB", uid); let gud = await G.mongodb.collection('user').findOne({uid: uid}); return gud; }