Files
ZYZ/game-server/app/services/redisService.ts
T
2021-11-02 16:08:56 +08:00

469 lines
14 KiB
TypeScript

import { COM_BTL_QUALITY, GUILD_ACTIVITY_TYPE } from './../consts';
import * as Redis from 'redis';
import {REDIS_KEY} from '../consts'
import { GameModel } from "../db/Game";
import { promisifyAll } from 'bluebird';
import { pinus, ServerInfo } from 'pinus';
import { GuildRankParam, GuildLeader, RankParam, LineupParam } from '../domain/rank';
import { comBtlRanges } from '../pubUtils/data';
import { setRankRedisFromDb } from './rankService';
import { ServerlistModel } from '../db/Serverlist';
import moment = require('moment');
/**
* 在服务重新启动时,将信息存入redis
*/
export async function initAllRank() {
console.log('******* initAllRank ******')
const serverList = await ServerlistModel.getAllServerList();
await delKeys(REDIS_KEY.ONLINE_USERS);
await delKeys(REDIS_KEY.USER_INFO);
await delKeys(REDIS_KEY.GUILD_INFO);
await delKeys(REDIS_KEY.TOP_LINEUP_INFO);
await delKeys(REDIS_KEY.HERO_INFO);
await delKeys(REDIS_KEY.TOWER_RANK);
await delKeys(REDIS_KEY.GUILD_LV_RANK);
await delKeys(REDIS_KEY.GUILD_ACTIVE_RANK);
await delKeys(REDIS_KEY.TOP_LINEUP_RANK);
await delKeys(REDIS_KEY.TOP_HERO_RANK);
await delKeys(REDIS_KEY.HERO_NUM_RANK);
await delKeys(REDIS_KEY.USER_LV);
await delKeys(REDIS_KEY.SUM_CE_RANK);
// await delKeys(REDIS_KEY.DUNGEON_RANK);
await delKeys(REDIS_KEY.DUNGEON_LINEUP);
await delKeys(REDIS_KEY.MAIN_RANK);
await delKeys(REDIS_KEY.MAIN_ELITE_RANK);
await delKeys(REDIS_KEY.HERO_RANK);
await delKeys(REDIS_KEY.SHOW_LINEUP);
// await delKeys(REDIS_KEY.PVP_RANK);
await setRankRedisFromDb(REDIS_KEY.PVP_RANK, {});
for(let {id} of serverList) {
await initRank(id);
}
}
/**
* 分服内初始redis排行榜
*
* @param serverId 服务器
*/
export async function initRank(serverId: number) {
// console.log('*****', 'initRank')
await setRankRedisFromDb(REDIS_KEY.TOWER_RANK, { serverId });
await setRankRedisFromDb(REDIS_KEY.GUILD_ACTIVE_RANK, { serverId });
await setRankRedisFromDb(REDIS_KEY.GUILD_LV_RANK, { serverId });
await setRankRedisFromDb(REDIS_KEY.TOP_LINEUP_RANK, { serverId });
await setRankRedisFromDb(REDIS_KEY.TOP_HERO_RANK, { serverId });
await setRankRedisFromDb(REDIS_KEY.HERO_NUM_RANK, { serverId });
await setRankRedisFromDb(REDIS_KEY.USER_LV, { serverId });
await setRankRedisFromDb(REDIS_KEY.SUM_CE_RANK, { serverId });
// await setRankRedisFromDb(REDIS_KEY.DUNGEON_RANK, { serverId });
await setRankRedisFromDb(REDIS_KEY.MAIN_RANK, { serverId });
await setRankRedisFromDb(REDIS_KEY.MAIN_ELITE_RANK, { serverId });
await setRankRedisFromDb(REDIS_KEY.HERO_RANK, { serverId });
}
/**
* 初始化某一个排行榜,如定时器内
* @param key redis内的key
*/
export async function initSingleRank(key: string) {
await delKeys(key);
if(key == REDIS_KEY.PVP_RANK) {
await setRankRedisFromDb(key, {});
} else {
const serverList = await GameModel.getAllServerList();
for(let { id } of serverList) {
await setRankRedisFromDb(key, { serverId: id });
}
}
}
/**
* debug接口使用,直接删除排行榜数据
* @param params serverId => guildCodes
*/
export async function delGuildActivityRank(aid: number) {
if(aid == GUILD_ACTIVITY_TYPE.GATE_ACTIVITY) {
await delKeys(REDIS_KEY.USER_GATE_ACTIVITY);
await delKeys(REDIS_KEY.GATE_ACTIVITY);
} else if (aid == GUILD_ACTIVITY_TYPE.CITY_ACTIVITY) {
await delKeys(REDIS_KEY.USER_CITY_ACTIVITY);
await delKeys(REDIS_KEY.CITY_ACTIVITY);
} else if (aid == GUILD_ACTIVITY_TYPE.RACE_ACTIVITY) {
await delKeys(REDIS_KEY.RACE_ACTIVITY);
}
}
export async function delKeys(key: string) {
let keys = await redisClient().keysAsync(`${key}*`);
for(let key of keys) {
await redisClient().delAsync(key);
}
return keys
}
export async function setUserInfo(key: string, roleId: string, params: RankParam|GuildRankParam|LineupParam[]) {
let value = JSON.stringify(params);
return await redisClient().hsetAsync(key, roleId, value);
}
export async function updateUserInfo(key: string, roleId: string, arr: Array<{field: string, value:(string|number|GuildLeader)}>) {
let params = await redisClient().hgetAsync(key, roleId);
if(params) {
let obj = JSON.parse(params);
for(let {field, value} of arr) {
obj[field] = value;
}
return await redisClient().hsetAsync(key, roleId, JSON.stringify(obj));
}
}
/********排行榜结束 */
/**************** 寻宝相关 start */
/**
* @description 拼接匹配分组的 key
* @param {number} quality 品质
* @param {number} lvRange 等级范围
*/
function getComTeamKey(quality: number, lvRange: number) {
return `${REDIS_KEY.COM_TEAM_SEARCH_PRE}:${quality}_${lvRange}`;
}
/**
* @description 拼接匹配分组中 member 的值
* @param {string} roleId
* @param {string} sid connector serverId
* @returns
*/
function getComTeamValue(roleId: string, sid: string) {
return `${roleId}:${sid}`;
}
/**
* @description 把寻宝的玩家信息存入 redis
* @export
* @param {string} roleId
* @param {string} sid
* @param {Array<number>} qualityArr
* @param {number} lvRange
* @returns
*/
export async function setTeamSearchReq(roleId: string, sid: string, qualityArr: Array<number>, lvRange: number) {
let cmds = [];
qualityArr.forEach(quality => {
if (quality) {
cmds.push(['sadd', getComTeamKey(quality, lvRange), getComTeamValue(roleId, sid)]);
}
});
const res = await redisClient().multi(cmds).execAsync();
console.log('setTeamSearchReq: ', res);
return res;
}
/**
* @description 从匹配队列中删除某个用户
* @export
* @param {string} roleId
* @param {string} sid
* @param {Array<number>} qualityArr
* @param {number} lvRange
*/
export async function rmRoleFromQueue(roleId: string, sid: string, qualityArr: Array<number>, lvRange: number) {
let cmds = [];
for (let q of qualityArr) {
if (lvRange) {
cmds.push(['srem', getComTeamKey(q, lvRange), getComTeamValue(roleId, sid)]);
} else {
for (let range of comBtlRanges()) {
cmds.push(['srem', getComTeamKey(q, range), getComTeamValue(roleId, sid)]);
}
}
};
await redisClient().multi(cmds).execAsync();
}
/**
* @description 在寻宝匹配队列中随机两个玩家
* @export
* @param {number} quality 队伍品质
* @param {number} lvRange 等级范围
* @returns
*/
export async function getTeamSearchByQuality(quality: number, lvRange: number) {
// TODO: 操作不具有原子性
const userInfos = await redisClient().srandmemberAsync(getComTeamKey(quality, lvRange), 2);
console.log('getTeamSearchByQuality: ' + userInfos);
if (!userInfos || !userInfos.length) return null;
let res = [];
for (let userInfo of userInfos) {
const decodeData = `${userInfo}`.split(':');
if (decodeData.length !== 2) return null;
res.push({roleId: decodeData[0], sid: decodeData[1]});
}
console.log('getTeamSearchByQuality res: ', res);
return res;
}
/**
* @description 检查玩家是否在某个队列中等待寻宝匹配
* @export
* @param {string} roleId
* @param {string} sid
* @param {Array<number>} qualityArr
* @param {number} lvRange
* @returns
*/
export async function checkRoleInQueue(roleId: string, sid: string, qualityArr: Array<number>, lvRange: number) {
for (let quality of qualityArr) {
let res = await redisClient().sismemberAsync(getComTeamKey(quality, lvRange), `${roleId}:${sid}`);
if (res) {
return true;
}
};
return false;
}
/**
* @description 清除所有的寻宝匹配队列
* @export
*/
export async function clearComBtlQueue() {
for (let q of COM_BTL_QUALITY) {
for (let lvRange of comBtlRanges()) {
await redisClient().delAsync(getComTeamKey(q, lvRange));
}
}
}
export function setRedis(key: string, data: string) {
redisClient().setAsync(key, data);
}
export async function getRedis(key: string) {
const str = await redisClient().getAsync(key);
return str;
}
export async function delRedis(key: string) {
await redisClient().delAsync(key);
}
export function redisSidKey(roleId: string) {
return `login_roleId_${roleId}`;
}
export async function redisChannelServer(roomId: string) {
const sid = await redisClient().hgetAsync(REDIS_KEY.CHANNEL_SERVERS, roomId);
return sid;
}
export async function addRedisChannel(roomId: string, sid: string) {
const result = await redisClient().hsetAsync(REDIS_KEY.CHANNEL_SERVERS, roomId, sid);
return result;
}
export async function clearChannelServers() {
const result = await redisClient().delAsync(REDIS_KEY.CHANNEL_SERVERS);
return result;
}
/**
* 玩家上线
* @param roleId role表id
* @param userCode user表唯一字符串标识
* @param sid connector服的那个sid
*/
export async function roleLogin(roleId: string, userCode: string, sid: string, pkgName: string) {
let param = { userCode, sid, pkgName };
return await redisClient().hsetAsync(REDIS_KEY.ONLINE_USERS, roleId, JSON.stringify(param));
}
/**
* 玩家下线
* @param roleId role表id
*/
export async function roleLeave(roleId: string) {
let role = await getRoleOnlineInfo(roleId);
await redisClient().hdelAsync(REDIS_KEY.ONLINE_USERS, roleId);
return role;
}
/**
* 判断玩家是否在线
* @param roleId role表id
*/
export async function isRoleOnline(roleId: string) {
let result = await redisClient().hexistsAsync(REDIS_KEY.ONLINE_USERS, roleId);
return !!result;
}
/**
* 获得在线玩家userCode和sid
* @param roleId
*/
export async function getRoleOnlineInfo(roleId: string) {
let str = await redisClient().hgetAsync(REDIS_KEY.ONLINE_USERS, roleId);
if(str) {
try {
let result = JSON.parse(str);
return {
isOnline: true,
userCode: result.userCode,
sid: result.sid,
pkgName: result.pkgName
}
} catch(e) {
return { isOnline: false }
}
} else {
return { isOnline: false }
}
}
/**
* 获得所有在线的玩家
*/
export async function getAllOnlineRoles() {
const client: Redis.RedisClient = pinus.app.get('redis');
let allRoles = await redisClient().hgetallAsync(REDIS_KEY.ONLINE_USERS);
let result = new Array<{roleId: string, userCode: string, sid: string, pkgName: string}>();
for(let roleId in allRoles) {
try{
let param = JSON.parse(allRoles[roleId]);
if(param) {
result.push({ roleId, userCode: param.userCode, sid: param.sid, pkgName: param.pkgName });
}
} catch(e) {
continue;
}
}
return result;
}
/**
* 将玩家登录时间记录到
* @param userCode 玩家user表里的userCode
* @param isToday 累计记录还是当日记录
* @returns 分钟
*/
export async function incOnlineTime(userCode: string, isToday: boolean, incTime: number) {
moment.locale('zh-cn');
let today = moment().format('YYYYMMDD');
let key = isToday? `${REDIS_KEY.ONLINE_TIME}:${today}`: REDIS_KEY.ONLINE_TIME;
if(isToday) {
let tomorrow = moment().add(1, 'days').hours(0).minutes(0).seconds(0).unix();
let result = await redisClient().hincrbyAsync(key, userCode, incTime);
let result2 = await redisClient().expireatAsync(key, tomorrow);
// console.log(result2)
return result;
} else {
return await redisClient().hincrbyAsync(key, userCode, incTime);
}
}
export async function setOnlineTime(userCode: string, isToday: boolean, setTime: number) {
moment.locale('zh-cn');
let today = moment().format('YYYYMMDD');
let key = isToday? REDIS_KEY.ONLINE_TIME: `${REDIS_KEY.ONLINE_TIME}:${today}`;
if(isToday) {
let tomorrow = moment().add(1, 'days').hours(0).minutes(0).seconds(0).format('x');
await redisClient().expireatAsync(key, parseInt(tomorrow));
}
return await redisClient().hsetAsync(key, userCode, setTime);
}
// 排行榜是否存在
export async function smembersAsync(key: string) {
const result = await redisClient().smembersAsync(key);
return result;
}
export async function saddAsync(key: string, values: Array<string>) {
const result = await redisClient().saddAsync(key, values);
return result;
}
export async function sismemberAsync(key: string, value: string) {
const result = await redisClient().sismemberAsync(key, value);
return result;
}
export async function delAsync(key:string) {
await redisClient().delAsync(key);
}
export async function sremAsync(key:string, member:string) {
await redisClient().sremAsync(key, member);
}
/**************** 寻宝相关 end */
/**************** 数据库表存入缓存 */
export async function readDataBase() {
await setServerList();
}
async function setServerList() {
const serverList = await ServerlistModel.getAllServerList();
await redisClient().delAsync(REDIS_KEY.DB_GAME);
for(let { id, name } of serverList) {
// console.log(roleId);
await redisClient().hsetAsync(REDIS_KEY.DB_GAME, `${id}`, name);
}
}
export async function getAllServers() {
let servers = await redisClient().hgetallAsync(REDIS_KEY.DB_GAME);
let serverlist = new Array<number>();
for(let serverStr in servers) {
let serverId = parseInt(serverStr);
if(!isNaN(serverId) && !serverlist.includes(serverId)) {
serverlist.push(serverId);
}
}
return serverlist;
}
export async function getServerName(serverId: number) {
let name = await redisClient().hgetAsync(REDIS_KEY.DB_GAME, `${serverId}`);
return name||'常山少年'
}
export function redisClient() {
const client: Redis.RedisClient = pinus.app.get('redis');
return client;
}
/**************** 数据库表end */
/*************** 将connector服插入redis *******/
export async function setConnectors(servers: ServerInfo[]) {
for(let server of servers) {
if(server.serverType == 'connector') {
let { serverType, clientHost, clientPort, id } = server;
await redisClient().hsetAsync(REDIS_KEY.SYS_SERVER, server.id, JSON.stringify({ serverType, clientHost, clientPort, id }));
}
}
}
export async function removeConnectors(servers: string[]) {
for(let server of servers) {
let hasServer = await redisClient().hgetAsync(REDIS_KEY.SYS_SERVER, server);
if(!!hasServer) await redisClient().hdelAsync(REDIS_KEY.SYS_SERVER, server);
}
}