Merge remote-tracking branch 'origin/bugfix' into bugfix

This commit is contained in:
dy 2023-12-28 18:19:52 +08:00
commit cc6aad7223

View File

@ -1,6 +1,5 @@
import { rankType, ResOpen } from '../../shared/protocols/rank/PtlOpen'; import { rankType, ResOpen } from '../../shared/protocols/rank/PtlOpen';
import { rankInfo } from '../../shared/protocols/type'; import { rankInfo } from '../../shared/protocols/type';
import { player } from '../../shared/protocols/user/type';
import { Queue } from '../../shared/public/queue'; import { Queue } from '../../shared/public/queue';
import { RankClslCross } from './rank_clsl'; import { RankClslCross } from './rank_clsl';
//import { RankHbzbJfsCross, RankHbzbJfsLocal, RankHbzbZbsCross } from './rank_hbzb_jfs'; //import { RankHbzbJfsCross, RankHbzbJfsLocal, RankHbzbZbsCross } from './rank_hbzb_jfs';
@ -12,21 +11,17 @@ import { RankTujian } from './rank_tujian';
import { RankWzryCross } from './rank_wzry'; import { RankWzryCross } from './rank_wzry';
import { RankXszm } from './rank_xszm'; import { RankXszm } from './rank_xszm';
import { RankZccg } from './rank_zccg'; import { RankZccg } from './rank_zccg';
import { sortEd } from '../../module/redis'
import * as util from 'util' import * as util from 'util'
import {RankKfjs} from "./rank_kfjs"; import { RankKfjs } from "./rank_kfjs";
import { clusterRunOnce } from '../../clusterUtils'; import { clusterRunOnce } from '../../clusterUtils';
export abstract class Rank { export abstract class Rank {
static list: Partial<{ static list: Partial<{
qjzzd: RankQjzzd; qjzzd: RankQjzzd;
zhanli: RankPower; zhanli: RankPower;
tanxian: RankTanXian; tanxian: RankTanXian;
//hbzbLocal: RankHbzbJfsLocal;
// hbzbCross: RankHbzbJfsCross;
// hbzbZbsCross: RankHbzbZbsCross;
slzd1: RankSlzd1; slzd1: RankSlzd1;
slzd2: RankSlzd2; slzd2: RankSlzd2;
slzd3: RankSlzd3; slzd3: RankSlzd3;
@ -41,17 +36,12 @@ export abstract class Rank {
kfjs: RankKfjs kfjs: RankKfjs
}> = {}; }> = {};
// list: rankInfo[];
queue = new Queue(); queue = new Queue();
findKey = 'uid'; findKey = 'uid';
countMaxNum = 50; countMaxNum = 50;
utimeTTL = 60; utimeTTL = 60;
abstract getType(): rankType; abstract getType(): rankType;
// abstract compare(other: rankInfo, cur: rankInfo): boolean;
// abstract compareSort(a: rankInfo, b: rankInfo): number;
// abstract getRankList(uid: string, obj?: {gud?:player, min?: number, max?:number}): Promise<ResOpen['']>;
// abstract getValArr(info: rankInfo): number|string; // 运算后的积分值,排名依据
// 获取rank数据, 注可能重写具体根据type类型判断 // 获取rank数据, 注可能重写具体根据type类型判断
async getRankList(uid: string, { min, max }): Promise<{ rankList: rankInfo[]; myRank: rankInfo; }> { async getRankList(uid: string, { min, max }): Promise<{ rankList: rankInfo[]; myRank: rankInfo; }> {
@ -65,13 +55,18 @@ export abstract class Rank {
myRank: { myRank: {
rank, rank,
player: data?.player || conn?.gud || {}, player: data?.player || conn?.gud || {},
valArr: [ score ] valArr: [score]
} }
}; };
} }
// 积分, 排名依据, 可能重写具体根据type类型判断 /**
getValArr(info: rankInfo):number|string { * RankInfo数据
* type类型判断
* @param info
* @returns
*/
getValArr(info: rankInfo): number | string {
return info?.valArr[0] || 0 return info?.valArr[0] || 0
} }
@ -79,15 +74,19 @@ export abstract class Rank {
compare(other: rankInfo, cur: rankInfo): boolean { compare(other: rankInfo, cur: rankInfo): boolean {
return cur.valArr[0] > other.valArr[0]; return cur.valArr[0] > other.valArr[0];
} }
// rankList排序可能重写具体根据type类型判断 // rankList排序可能重写具体根据type类型判断
compareSort(a: rankInfo, b: rankInfo): number { compareSort(a: rankInfo, b: rankInfo): number {
return b.valArr[0] - a.valArr[0]; return b.valArr[0] - a.valArr[0];
} }
/**
// 页码转换为minmax * page和offset转换出min和max
static pageToMin (page, offset) { * @param page
* @param offset
* @returns
*/
static pageToMin(page: number, offset: number) {
let res = { let res = {
min: page * offset, min: page * offset,
max: page * offset + offset max: page * offset + offset
@ -95,9 +94,16 @@ export abstract class Rank {
return res return res
} }
/**
* DB连接对象
*/
get db() { get db() {
return G.mongodb.collection('rankList'); return G.mongodb.collection('rankList');
} }
/**
*
*/
get type() { get type() {
return this.getType(); return this.getType();
} }
@ -107,10 +113,16 @@ export abstract class Rank {
this.cotr(); this.cotr();
} }
/**
* typeredis Data的key
*/
get getRedisKey() { get getRedisKey() {
return util.format('rank:%s:data', this.getType()) return util.format('rank:%s:data', this.getType())
} }
/**
* typeredis Sort的key
*/
get getRedisKeySort() { get getRedisKeySort() {
return util.format('rank:%s:sort', this.getType()) return util.format('rank:%s:sort', this.getType())
} }
@ -119,152 +131,275 @@ export abstract class Rank {
async cotr() { async cotr() {
clusterRunOnce(async () => { clusterRunOnce(async () => {
// redis已存在则不初始化 // redis已存在则不初始化
if(await this.getRankLen() > 0) return //if(await this.getRankLen() > 0) return
this.db.find({ type: this.type }).toArray().then(listArr => {
//将db里的数据写入到 rank:xxx:sort里
//写入的单条数据为: {uid:score}
this.db.find({ type: this.type }, {
projection: {
"idKey": 1,
"type": 1,
"data.valArr": 1,
"utime": 1
}
}).toArray().then(listArr => {
// 写入初始化数据 // 写入初始化数据
listArr = listArr || []; listArr = listArr || [];
listArr.forEach(item => { listArr.forEach(item => {
if(item.idKey && item.data) this.setRankData(item.idKey, item.data) if (item.idKey && item.data) this.setRankData(item.idKey, item.data)
}) })
}); });
}) })
this.getRankListRange();
} }
// 更新数据与排名 /**
async setRankData(idKey: string, data: rankInfo) { *
let key = this.getRedisKey * @param uid uidrank里通常保存于idKey这个字段
* @param data data.valArr字段
* @returns
*/
async setRankData(uid: string, data: rankInfo) {
let keySort = this.getRedisKeySort let keySort = this.getRedisKeySort
data.utime = G.time
// data // let key = this.getRedisKey
G.redis.hSet(key, idKey, data) // G.redis.hSet(key, idKey, data)
// sort
let valArr = await this.getValArr(data) /**积分 */
G.redis.zAdd(keySort, <sortEd>{value: idKey, score: valArr}) let score = await this.getValArr(data)
return //G.redis.zAdd(keySort, <sortEd>{value: idKey, score: valArr})
await G.ioredis.zadd(keySort, score, uid)
return
} }
// 获取单个用户的数据 /**
async getRankData(idKey: string) { *
let key = this.getRedisKey * @param uid uid
let data = await G.redis.hGet(key, idKey) * @returns
if(!data || data.utime < (G.time - this.utimeTTL)) { */
let type = this.getType() async getRankData(uid: string) {
let res = await this.db.findOne({isKey: idKey, type}) let data: rankInfo;
if(res) { let res = await this.db.findOne({ "idKey": uid, "type": this.getType() })
data = G.mongodb.conversionIdObj(res)
this.setRankData(idKey, data.data) if (res?.data && res.data.utime + 60 > G.time) {
} data = (G.mongodb.conversionIdObj(res)).data;
} else if (res?.data) {
let player = await G.mongodb.collection("user").findOne({ uid: uid }, { projection: { _id: 0 } });
data = Object.assign(res.data, { player: player });
this.db.updateOne({ idKey: uid, type: this.getType() }, { $set: { "data.player": data.player, "data.utime": G.time } });
} }
if(data) return data return data;
return undefined || {}
// let key = this.getRedisKey
// let data = await G.redis.hGet(key, idKey)
// if(!data || data.utime < (G.time - this.utimeTTL)) {
// let type = this.getType()
// let res = await this.db.findOne({isKey: idKey, type}) //<--isKey意味着整个rank从来不会更新res永远是空
// if(res) {
// data = G.mongodb.conversionIdObj(res)
// this.setRankData(idKey, data.data)
// }
// }
// if(data) return data
// return undefined || {}
} }
// 获取单个用户的分数 /**
async getRankScore(idKey:string): Promise<number> { *
let score = await G.redis.zScore(this.getRedisKeySort, idKey) * @param uid
* @returns
*/
async getRankScore(uid: string): Promise<number> {
let score = await G.redis.zScore(this.getRedisKeySort, uid)
return score || 0 return score || 0
}
// 获取单个用户的排名 *降序
async getRankSortByOne(idKey: string):Promise<number> {
let rank = await G.redis.zRevRank(this.getRedisKeySort, idKey)
return rank === 0 || rank > 0 ? rank: -1;
} }
// 获取单个指定排名的用户数据 *降序 /**
* redis中获取单个用户的排名 *
* @param uid
* @returns
*/
async getRankSortByOne(uid: string): Promise<number> {
let rank = await G.redis.zRevRank(this.getRedisKeySort, uid)
return rank === 0 || rank > 0 ? rank : -1;
}
// 从redis中获取单个指定排名的用户数据 *降序
async getRankSortDataByOne(rank: number): Promise<rankInfo> { async getRankSortDataByOne(rank: number): Promise<rankInfo> {
let rankList:rankInfo[] = await this.getRankListRange(rank, rank + 1) let rankList: rankInfo[] = await this.getRankListRange(rank, rank + 1)
let rankInfo = rankList && rankList.length > 0 ? rankList[0] : {} as rankInfo let rankInfo = rankList && rankList.length > 0 ? rankList[0] : {} as rankInfo
return rankInfo return rankInfo
} }
// 获取排名长度 // 获取排名长度
async getRankLen() { // async getRankLen() {
return await G.redis.hLen(this.getRedisKey) // return await G.redis.hLen(this.getRedisKey)
} // }
// 获取指定排名范围的数据 *降序 /**
async getRankListRange(min:number = 0, max:number = 50): Promise<rankInfo[]> { * *
let idKeys = await this.getRankListIdKeyRange(min, max) * @param min
if(idKeys && idKeys.length > 0) { * @param max
let res = await G.redis.hmGet(this.getRedisKey, idKeys) * @returns
res = await this.checkData(res) */
return res.sort(this.compareSort) async getRankListRange(min: number = 0, max: number = 50): Promise<rankInfo[]> {
} let uids = await this.getRankListIdKeyRange(min, max)
return [] if (uids && uids.length > 0) {
} let res = await this.db.find({ idKey: { $in: uids }, type: this.getType() }).toArray()
// 获取指定排名范围的idKey *降序
async getRankListIdKeyRange(min:number = 0, max: number = 50): Promise<string[]> {
let idKeys = await G.redis.zRevRange(this.getRedisKeySort, min, max - 1)
return idKeys || []
}
// 获取指定类型的全部rank列表,返回为积分排序后的数组 switch (this.getType()) {
async getRankListAll(): Promise<rankInfo[]> { case "slzd1":
let res = await G.redis.hGetAll(this.getRedisKey) case "slzd2":
if(res) { case "slzd3":
// 如果是用户数据则比对utime更新数据 case "slzd4":
// res = await this.checkData(res) case "slzd5":
return Object.values(res).sort(this.compareSort) case "slzd6":
let ghid = [];
res = res.map(item => {
if (!item.data?.player?.ghid || item.data.utime + 60 < G.time) {
ghid.push(G.mongodb.conversionId(item.idKey));
}
return item;
})
if(ghid.length > 0){
(await G.mongodb.collection("gonghui").find(
{ _id: { $in: ghid } }, { projection: { name: 1 } }
)).forEach(item => {
let index = res.findIndex(x => x.idKey == item._id.toHexString());
res[index].data.player.ghName = item.name;
this.db.updateOne({ idKey: item._id.toHexString(), type: this.getType() }, { $set: { "data.player.ghName": item.name } });
})
}
break;
default: // 排行数据更新逻辑 默认更新playerInfo
let updateUids = [];
res = res.map(item => {
// 没有player 或者 player 过期
if (!item.data?.player || item.data.utime + 60 < G.time) {
updateUids.push(item.idKey);
}
return item;
});
let newUserArr = await G.mongodb.collection('user').find(
{ uid: { $in: updateUids } }, { projection: { _id: 0 } }
).toArray();
newUserArr.forEach(item => {
// 每次遍历查找?
let index = res.findIndex(x => x.idKey == item.uid);
res[index].data.player = item;
this.db.updateOne({ idKey: item.uid, type: this.getType() }, { $set: { "data.player": item } });
// 跟新redis score
// this.setRankData(item.uid, res[index].data as any);
})
}
return res.map(ele => ele.data).sort(this.compareSort) as any;
} }
return [] return []
} }
// 按排名获取全部的idKey /**
* redis中获取指定排名范围的uid集合 *
* @param min
* @param max
* @returns uid集合数组
*/
async getRankListIdKeyRange(min: number = 0, max: number = 50): Promise<string[]> {
let uids = await G.redis.zRevRange(this.getRedisKeySort, min, max - 1)
return uids || []
}
/**
* rank列表,
* @returns
*/
async getRankListAll(): Promise<rankInfo[]> {
// let res = await G.redis.hGetAll(this.getRedisKey)
let res = (await this.db.find({ type: this.getType() }).toArray()).map(ele => ele.data);
if (res) {
// 如果是用户数据则比对utime更新数据
// res = await this.checkData(res)
return res.sort(this.compareSort)
}
return []
}
/**
* idKey
* @returns
*/
async getRankListIdKeyAll(): Promise<string[]> { async getRankListIdKeyAll(): Promise<string[]> {
let res = this.getRankListIdKeyRange(0, -1) let res = this.getRankListIdKeyRange(0, -1)
return res return res
} }
// 验证数据的过期时间,更新数据 // 验证数据的过期时间,更新数据
async checkData(rankList: rankInfo[]): Promise<rankInfo[]> { // async checkData(rankList: rankInfo[]): Promise<rankInfo[]> {
let updateUid = [] // let updateUid = []
rankList.forEach((value,key) => { // rankList.forEach((value,key) => {
// 仅针对用户表,公会表暂不考虑 // // 仅针对用户表,公会表暂不考虑
if(rankList[key].player?.uid && (rankList[key].utime || 0) < (G.time - this.utimeTTL)) { // if(rankList[key].player?.uid && (rankList[key].utime || 0) < (G.time - this.utimeTTL)) {
// 更新数据 // // 更新数据
updateUid.push(rankList[key].player.uid) // updateUid.push(rankList[key].player.uid)
} // }
}) // })
if(updateUid.length > 0) { // if(updateUid.length > 0) {
let newUserArr = await G.mongodb.collection('user').find({uid:{$in: updateUid}}).toArray() // let newUserArr = await G.mongodb.collection('user').find({uid:{$in: updateUid}}).toArray()
// let newUserArr = await G.redis.gets('user', ...updateUid.map(uid => [uid] as [string])) // // let newUserArr = await G.redis.gets('user', ...updateUid.map(uid => [uid] as [string]))
// let newUserArr = await G.mongodb.collection('user').find({uid:{$in: updateUid}}).toArray() // // let newUserArr = await G.mongodb.collection('user').find({uid:{$in: updateUid}}).toArray()
newUserArr.forEach(item => { // newUserArr.forEach(item => {
let index = rankList.findIndex( x => x.player.uid == item.uid); // let index = rankList.findIndex( x => x.player.uid == item.uid);
rankList[index].player = item; // rankList[index].player = item;
this.setRankData(item.uid, rankList[index]); // this.setRankData(item.uid, rankList[index]);
}) // })
} // }
return rankList // return rankList
// }
/**
* idk的排名数据
* @param idKey
* @returns
*/
async delRankData(idKey: string) {
// G.redis.hDel(this.getRedisKey, idKey)
G.redis.zRem(this.getRedisKeySort, idKey);
this.db.updateOne({ idKey: idKey, type: this.getType() }, {
$set: { idKey: `del_${idKey}` }
});
} }
async delRankData(idKey:string) { /**
G.redis.hDel(this.getRedisKey, idKey) * 50(countMaxNum)
G.redis.zRem(this.getRedisKeySort, idKey) * @param info
} * @returns
*/
// 原逻辑前50(countMaxNum)名才更新数据(上榜),多余的数据会删除。
async addNew(info: rankInfo) { async addNew(info: rankInfo) {
//this.queue.enqueue(async () => { //this.queue.enqueue(async () => {
await this.setRankData(info.player[this.findKey], info) await this.setRankData(info.player[this.findKey], info)
await this.db.updateOne({ type: this.type, idKey: info.player[this.findKey] }, { $set: { data: info } }, { upsert: true }); await this.db.updateOne({ type: this.type, idKey: info.player[this.findKey] }, { $set: { data: info } }, { upsert: true });
// 删除第50名以后的数据排名从0开始计算 // 删除第50名以后的数据排名从0开始计算
// let idKeys:string[] = await this.getRankListIdKeyRange(50, -1) // let idKeys:string[] = await this.getRankListIdKeyRange(50, -1)
// idKeys.forEach(idKey => { // idKeys.forEach(idKey => {
// this.db.deleteOne({ type: this.type, idKey: idKey }); // this.db.deleteOne({ type: this.type, idKey: idKey });
// this.delRankData(idKey) // this.delRankData(idKey)
// }) // })
//}); //});
} }
// 清空相关rank数据 // 清空相关rank数据
async clear() { async clear() {
this.queue.enqueue(async () => { this.queue.enqueue(async () => {
// G.redis.rawDel(this.getRedisKey)
G.redis.rawDel(this.getRedisKeySort);
await this.db.deleteMany({ type: this.type }); await this.db.deleteMany({ type: this.type });
G.redis.rawDel(this.getRedisKey)
G.redis.rawDel(this.getRedisKeySort)
}); });
} }
} }