Merge remote-tracking branch 'origin/bugfix' into bugfix
This commit is contained in:
commit
cc6aad7223
@ -1,6 +1,5 @@
|
||||
import { rankType, ResOpen } from '../../shared/protocols/rank/PtlOpen';
|
||||
import { rankInfo } from '../../shared/protocols/type';
|
||||
import { player } from '../../shared/protocols/user/type';
|
||||
import { Queue } from '../../shared/public/queue';
|
||||
import { RankClslCross } from './rank_clsl';
|
||||
//import { RankHbzbJfsCross, RankHbzbJfsLocal, RankHbzbZbsCross } from './rank_hbzb_jfs';
|
||||
@ -12,21 +11,17 @@ import { RankTujian } from './rank_tujian';
|
||||
import { RankWzryCross } from './rank_wzry';
|
||||
import { RankXszm } from './rank_xszm';
|
||||
import { RankZccg } from './rank_zccg';
|
||||
import { sortEd } from '../../module/redis'
|
||||
import * as util from 'util'
|
||||
import { RankKfjs } from "./rank_kfjs";
|
||||
|
||||
import { clusterRunOnce } from '../../clusterUtils';
|
||||
|
||||
|
||||
|
||||
export abstract class Rank {
|
||||
static list: Partial<{
|
||||
qjzzd: RankQjzzd;
|
||||
zhanli: RankPower;
|
||||
tanxian: RankTanXian;
|
||||
//hbzbLocal: RankHbzbJfsLocal;
|
||||
// hbzbCross: RankHbzbJfsCross;
|
||||
// hbzbZbsCross: RankHbzbZbsCross;
|
||||
slzd1: RankSlzd1;
|
||||
slzd2: RankSlzd2;
|
||||
slzd3: RankSlzd3;
|
||||
@ -41,17 +36,12 @@ export abstract class Rank {
|
||||
kfjs: RankKfjs
|
||||
}> = {};
|
||||
|
||||
// list: rankInfo[];
|
||||
queue = new Queue();
|
||||
findKey = 'uid';
|
||||
countMaxNum = 50;
|
||||
utimeTTL = 60;
|
||||
|
||||
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类型判断
|
||||
async getRankList(uid: string, { min, max }): Promise<{ rankList: rankInfo[]; myRank: rankInfo; }> {
|
||||
@ -70,7 +60,12 @@ export abstract class Rank {
|
||||
};
|
||||
}
|
||||
|
||||
// 积分, 排名依据, ,注:可能重写,具体根据type类型判断
|
||||
/**
|
||||
* 根据RankInfo数据,获取用于排名的积分值得
|
||||
* 注:可能重写,具体根据type类型判断
|
||||
* @param info
|
||||
* @returns 积分值
|
||||
*/
|
||||
getValArr(info: rankInfo): number | string {
|
||||
return info?.valArr[0] || 0
|
||||
}
|
||||
@ -85,9 +80,13 @@ export abstract class Rank {
|
||||
return b.valArr[0] - a.valArr[0];
|
||||
}
|
||||
|
||||
|
||||
// 页码转换为min,max
|
||||
static pageToMin (page, offset) {
|
||||
/**
|
||||
* 页面转换,根据page和offset转换出min和max
|
||||
* @param page 页面
|
||||
* @param offset 每页数量
|
||||
* @returns
|
||||
*/
|
||||
static pageToMin(page: number, offset: number) {
|
||||
let res = {
|
||||
min: page * offset,
|
||||
max: page * offset + offset
|
||||
@ -95,9 +94,16 @@ export abstract class Rank {
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回排行榜DB连接对象
|
||||
*/
|
||||
get db() {
|
||||
return G.mongodb.collection('rankList');
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回排行榜类型
|
||||
*/
|
||||
get type() {
|
||||
return this.getType();
|
||||
}
|
||||
@ -107,10 +113,16 @@ export abstract class Rank {
|
||||
this.cotr();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据type,获取redis Data的key
|
||||
*/
|
||||
get getRedisKey() {
|
||||
return util.format('rank:%s:data', this.getType())
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据type,获取redis Sort的key
|
||||
*/
|
||||
get getRedisKeySort() {
|
||||
return util.format('rank:%s:sort', this.getType())
|
||||
}
|
||||
@ -119,8 +131,18 @@ export abstract class Rank {
|
||||
async cotr() {
|
||||
clusterRunOnce(async () => {
|
||||
// redis已存在则不初始化
|
||||
if(await this.getRankLen() > 0) return
|
||||
this.db.find({ type: this.type }).toArray().then(listArr => {
|
||||
//if(await this.getRankLen() > 0) return
|
||||
|
||||
//将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.forEach(item => {
|
||||
@ -128,50 +150,83 @@ export abstract class Rank {
|
||||
})
|
||||
});
|
||||
})
|
||||
|
||||
this.getRankListRange();
|
||||
}
|
||||
|
||||
// 更新数据与排名
|
||||
async setRankData(idKey: string, data: rankInfo) {
|
||||
let key = this.getRedisKey
|
||||
/**
|
||||
* 更新玩家的积分
|
||||
* @param uid uid,在rank里通常保存于idKey这个字段
|
||||
* @param data 积分数据,主要是需要里面的data.valArr字段
|
||||
* @returns
|
||||
*/
|
||||
async setRankData(uid: string, data: rankInfo) {
|
||||
let keySort = this.getRedisKeySort
|
||||
data.utime = G.time
|
||||
// data
|
||||
G.redis.hSet(key, idKey, data)
|
||||
// sort
|
||||
let valArr = await this.getValArr(data)
|
||||
G.redis.zAdd(keySort, <sortEd>{value: idKey, score: valArr})
|
||||
|
||||
// let key = this.getRedisKey
|
||||
// G.redis.hSet(key, idKey, data)
|
||||
|
||||
/**积分 */
|
||||
let score = await this.getValArr(data)
|
||||
//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
|
||||
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})
|
||||
if(res) {
|
||||
data = G.mongodb.conversionIdObj(res)
|
||||
this.setRankData(idKey, data.data)
|
||||
/**
|
||||
* 获取单个用户的数据
|
||||
* @param uid uid
|
||||
* @returns
|
||||
*/
|
||||
async getRankData(uid: string) {
|
||||
let data: rankInfo;
|
||||
let res = await this.db.findOne({ "idKey": uid, "type": this.getType() })
|
||||
|
||||
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 undefined || {}
|
||||
return data;
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 获取单个用户的排名 *降序
|
||||
async getRankSortByOne(idKey: string):Promise<number> {
|
||||
let rank = await G.redis.zRevRank(this.getRedisKeySort, idKey)
|
||||
/**
|
||||
* 从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> {
|
||||
let rankList: rankInfo[] = await this.getRankListRange(rank, rank + 1)
|
||||
let rankInfo = rankList && rankList.length > 0 ? rankList[0] : {} as rankInfo
|
||||
@ -179,73 +234,152 @@ export abstract class Rank {
|
||||
}
|
||||
|
||||
// 获取排名长度
|
||||
async getRankLen() {
|
||||
return await G.redis.hLen(this.getRedisKey)
|
||||
// async getRankLen() {
|
||||
// return await G.redis.hLen(this.getRedisKey)
|
||||
// }
|
||||
|
||||
/**
|
||||
* 获取指定排名范围的数据 *降序
|
||||
* @param min
|
||||
* @param max
|
||||
* @returns
|
||||
*/
|
||||
async getRankListRange(min: number = 0, max: number = 50): Promise<rankInfo[]> {
|
||||
let uids = await this.getRankListIdKeyRange(min, max)
|
||||
if (uids && uids.length > 0) {
|
||||
let res = await this.db.find({ idKey: { $in: uids }, type: this.getType() }).toArray()
|
||||
|
||||
switch (this.getType()) {
|
||||
case "slzd1":
|
||||
case "slzd2":
|
||||
case "slzd3":
|
||||
case "slzd4":
|
||||
case "slzd5":
|
||||
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);
|
||||
})
|
||||
}
|
||||
|
||||
// 获取指定排名范围的数据 *降序
|
||||
async getRankListRange(min:number = 0, max:number = 50): Promise<rankInfo[]> {
|
||||
let idKeys = await this.getRankListIdKeyRange(min, max)
|
||||
if(idKeys && idKeys.length > 0) {
|
||||
let res = await G.redis.hmGet(this.getRedisKey, idKeys)
|
||||
res = await this.checkData(res)
|
||||
return res.map(ele => ele.data).sort(this.compareSort) as any;
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* 从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 *降序
|
||||
async getRankListIdKeyRange(min:number = 0, max: number = 50): Promise<string[]> {
|
||||
let idKeys = await G.redis.zRevRange(this.getRedisKeySort, min, max - 1)
|
||||
return idKeys || []
|
||||
}
|
||||
|
||||
// 获取指定类型的全部rank列表,返回为积分排序后的数组
|
||||
async getRankListAll(): Promise<rankInfo[]> {
|
||||
let res = await G.redis.hGetAll(this.getRedisKey)
|
||||
if(res) {
|
||||
// 如果是用户数据,则比对utime,更新数据
|
||||
// res = await this.checkData(res)
|
||||
return Object.values(res).sort(this.compareSort)
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
// 按排名获取全部的idKey
|
||||
/**
|
||||
* 按排名获取全部的idKey
|
||||
* @returns
|
||||
*/
|
||||
async getRankListIdKeyAll(): Promise<string[]> {
|
||||
let res = this.getRankListIdKeyRange(0, -1)
|
||||
return res
|
||||
}
|
||||
|
||||
// 验证数据的过期时间,更新数据
|
||||
async checkData(rankList: rankInfo[]): Promise<rankInfo[]> {
|
||||
let updateUid = []
|
||||
rankList.forEach((value,key) => {
|
||||
// 仅针对用户表,公会表暂不考虑
|
||||
if(rankList[key].player?.uid && (rankList[key].utime || 0) < (G.time - this.utimeTTL)) {
|
||||
// 更新数据
|
||||
updateUid.push(rankList[key].player.uid)
|
||||
}
|
||||
})
|
||||
if(updateUid.length > 0) {
|
||||
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]))
|
||||
// async checkData(rankList: rankInfo[]): Promise<rankInfo[]> {
|
||||
// let updateUid = []
|
||||
// rankList.forEach((value,key) => {
|
||||
// // 仅针对用户表,公会表暂不考虑
|
||||
// if(rankList[key].player?.uid && (rankList[key].utime || 0) < (G.time - this.utimeTTL)) {
|
||||
// // 更新数据
|
||||
// updateUid.push(rankList[key].player.uid)
|
||||
// }
|
||||
// })
|
||||
// if(updateUid.length > 0) {
|
||||
// let newUserArr = await G.mongodb.collection('user').find({uid:{$in: updateUid}}).toArray()
|
||||
newUserArr.forEach(item => {
|
||||
let index = rankList.findIndex( x => x.player.uid == item.uid);
|
||||
rankList[index].player = item;
|
||||
this.setRankData(item.uid, rankList[index]);
|
||||
})
|
||||
}
|
||||
return rankList
|
||||
}
|
||||
// // 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()
|
||||
// newUserArr.forEach(item => {
|
||||
// let index = rankList.findIndex( x => x.player.uid == item.uid);
|
||||
// rankList[index].player = item;
|
||||
// this.setRankData(item.uid, rankList[index]);
|
||||
// })
|
||||
// }
|
||||
// return rankList
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* 删除指定idk的排名数据
|
||||
* @param idKey
|
||||
* @returns
|
||||
*/
|
||||
async delRankData(idKey: string) {
|
||||
G.redis.hDel(this.getRedisKey, idKey)
|
||||
G.redis.zRem(this.getRedisKeySort, idKey)
|
||||
// G.redis.hDel(this.getRedisKey, idKey)
|
||||
G.redis.zRem(this.getRedisKeySort, idKey);
|
||||
this.db.updateOne({ idKey: idKey, type: this.getType() }, {
|
||||
$set: { idKey: `del_${idKey}` }
|
||||
});
|
||||
}
|
||||
|
||||
// 原逻辑前50(countMaxNum)名才更新数据(上榜),多余的数据会删除。
|
||||
/**
|
||||
* 原逻辑前50(countMaxNum)名才更新数据(上榜),多余的数据会删除。
|
||||
* @param info
|
||||
* @returns
|
||||
*/
|
||||
async addNew(info: rankInfo) {
|
||||
//this.queue.enqueue(async () => {
|
||||
await this.setRankData(info.player[this.findKey], info)
|
||||
@ -259,12 +393,13 @@ export abstract class Rank {
|
||||
//});
|
||||
}
|
||||
|
||||
|
||||
// 清空相关rank数据
|
||||
async clear() {
|
||||
this.queue.enqueue(async () => {
|
||||
// G.redis.rawDel(this.getRedisKey)
|
||||
G.redis.rawDel(this.getRedisKeySort);
|
||||
await this.db.deleteMany({ type: this.type });
|
||||
G.redis.rawDel(this.getRedisKey)
|
||||
G.redis.rawDel(this.getRedisKeySort)
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user