Files
ZYZ/game-server/app/services/pushService.ts
luying 7bc9e1fe49 Revert " feat(db): 修改role表数据库操作方式"
This reverts commit e39af3649288cc5802739cfe862c818fe56e194e.
2023-05-22 19:43:21 +08:00

390 lines
18 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Channel, pinus } from "pinus";
import { CHANNEL_PREFIX, PUSH_BATCH, PUSH_INTERVAL, PUSH_ROUTE, SDK_PUSH_MSG_PLAYER_TYPE, SDK_PUSH_MSG_TYPE, SDK_PUSH_TARGET_TYPE, STATUS } from "../consts";
import { genCode, resResult } from "../pubUtils/util";
import { getCityChannelSid, getGuildChannelSid, getWorldChannelSid, groupRoomId, getGroupShopSid, getGVGAreaChannelSid, getGVGAreaTeamChannelSid, getGVGCityTeamChannelSid } from "./chatService";
import { getAllOnlineRoles, getAllServers, getRoleOnlineInfo } from "./redisService";
import { errlogger, infologger } from '../util/logger';
import { MsgEncrypt } from "../pubUtils/sysUtil";
import { isSkipEncode, needPushMsg } from "../pubUtils/sdkUtil";
import { isDevelopEnv } from "./utilService";
import { gameData } from "../pubUtils/data";
import { pushMsg37 } from "./sdkService";
import { RoleModel, RoleType } from "../db/Role";
import { nowSeconds } from "../pubUtils/timeUtil";
import { GVGLeagueModel } from "../db/GVGLeague";
import { resolve } from "bluebird";
export async function sendMessageToAllWithSuc(route: string, data: any, filterCb?: ({ lv, topLineupCe }) => boolean) {
await sendMessageToAll(route, resResult(STATUS.SUCCESS, data), filterCb);
}
export async function sendMessageToAll(route: string, data: any, filterCb?: ({ lv, topLineupCe }) => boolean) {
let allOnlineUsers = await getAllOnlineRoles();
if(filterCb) {
allOnlineUsers = allOnlineUsers.filter(filterCb);
}
let n = Math.ceil(allOnlineUsers.length / PUSH_BATCH); // 一共多少批
let sendToUser = (i: number) => {
let users = allOnlineUsers.slice(i * PUSH_BATCH, (i + 1) * PUSH_BATCH - 1);
let uids = users.map(cur => ({ uid: cur.roleId, sid: cur.sid }));
sendMessageToUsers(route, data, uids);
}
let i = -1;
sendToUser(++i);
let interval = setInterval(() => {
if (++i < n) {
sendToUser(i);
} else {
clearInterval(interval);
}
}, PUSH_INTERVAL);
}
export async function sendMessageToAllServersWithSuc(route: string, data: any) {
let servers = await getAllServers();
for(let serverId of servers) {
await sendMessageToServerWithSuc(serverId, route, data);
}
}
export async function sendMessageToServerWithSuc(serverId: number, route: string, data: any, isBatch = false) {
await sendMessageToServer(serverId, route, resResult(STATUS.SUCCESS, data), isBatch);
}
export async function sendMessageToServer(serverId: number, route: string, data: any, isBatch = false) {
let channelSid = await getWorldChannelSid(serverId);
let roomId = groupRoomId(CHANNEL_PREFIX.WORLD, serverId);
await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, data, isBatch);
}
export async function sendMessageToGuildWithSuc(guildCode: string, route: string, data: any) {
await sendMessageToGuild(guildCode, route, resResult(STATUS.SUCCESS, data));
}
export async function sendMessageToGuild(guildCode: string, route: string, data: any) {
let channelSid = await getGuildChannelSid(guildCode);
let roomId = groupRoomId(CHANNEL_PREFIX.GUILD, guildCode);
await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, data);
}
export async function sendMessageToGVGAreaWithSuc(groupKey: string, areaId: number, route: string, data: any) {
let channelSid = await getGVGAreaChannelSid(groupKey, areaId);
let roomId = groupRoomId(CHANNEL_PREFIX.GVG_AREAS, `${groupKey}_${areaId}`);
await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, resResult(STATUS.SUCCESS, data));
}
export async function sendMessageToGVGAreaByTeamWithSuc(groupKey: string, areaId: number, route: string, data: any) {
let channelSid = await getGVGAreaTeamChannelSid(groupKey, areaId);
let roomId = groupRoomId(CHANNEL_PREFIX.GVG_AREA_BY_TEAM, `${groupKey}_${areaId}`);
await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, resResult(STATUS.SUCCESS, data));
}
export async function sendMessageToGVGCityWithSuc(groupKey: string, cityId: number, route: string, data: any) {
let channelSid = await getGVGCityTeamChannelSid(groupKey, cityId);
let roomId = groupRoomId(CHANNEL_PREFIX.GVG_CITY, `${groupKey}_${cityId}`);
await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, resResult(STATUS.SUCCESS, data));
}
export async function sendMessageToCityWithSuc(serverId: number, cityId: number, route: string, data: any) {
await sendMessageToCity(serverId, cityId, route, resResult(STATUS.SUCCESS, data));
}
export async function sendMessageToCity(serverId: number, cityId: number, route: string, data: any) {
let channelSid = await getCityChannelSid(serverId, cityId);
let roomId = groupRoomId(CHANNEL_PREFIX.CITY, `${serverId}_${cityId}`);
await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, data);
}
export async function sendMessageToGroupShopWithSuc(route: string, data: any) {
let channelSid = await getGroupShopSid();
let roomId = groupRoomId(CHANNEL_PREFIX.GROUP_SHOP);
await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, resResult(STATUS.SUCCESS, data));
}
export async function sendMessageToUserWithSuc(roleId: string, route: string, data: any, sid?: string) {
await sendMessageToUser(roleId, route, resResult(STATUS.SUCCESS, data), sid);
}
export async function sendMessageToUser(roleId: string, route: string, data: any, sid?: string) {
let uids = [];
if (!sid) {
let onlineUser = await getRoleOnlineInfo(roleId);
sid = onlineUser.sid;
}
if (!!sid) {
uids.push({ uid: roleId, sid });
sendMessageToUsers(route, data, uids);
}
}
export async function sendMessageToUsersWithSuc(route: string, data: any, uids: { uid: string, sid: string }[]) {
await sendMessageToUsers(route, resResult(STATUS.SUCCESS, data), uids);
}
// 推送给个人的方法收束于这个函数
export async function sendMessageToUsers(route: string, data: any, uids: { uid: string, sid: string }[]) {
if(uids.length > 0) {
pinus.app.get('channelService').pushMessageByUids(route, encryptMsg(route, data), uids);
infologger.debug(`pushMessage route: ${route} data: ${JSON.stringify(data)} members: ${uids.map(obj => obj.uid).join()}`);
}
}
export async function sendMessageToTeam(teamCode: string, route: string, data: any) {
const channel = pinus.app.get('channelService').getChannel(teamCode);
sendMessageToChannel(channel, route, resResult(STATUS.SUCCESS, data));
}
/**
*
* @param user
*/
export function addUserToTeamChannel(teamCode: string, isCreate: boolean, roleId: string, sid: string) {
let channel = pinus.app.get('channelService').getChannel(teamCode, isCreate);
if(channel) addUserToChannel(channel, roleId, sid);
return channel
}
export function addUserToChannel(channel: Channel, roleId: string, sid: string) {
let member = channel.getMember(roleId);
if(member && member.sid != sid) channel.removeMember(roleId);
const users = channel.getMembers();
if (users.indexOf(roleId) === -1) {
channel.add(roleId, sid);
}
}
export function sendMessgeToChannelByBatch(channel: Channel, route: string, data: any) {
let members = channel.getMembers();
if(members.length > PUSH_BATCH) {
let n = Math.ceil(members.length / PUSH_BATCH); // 一共多少批
// console.log(n)
let i = -1;
let interval = setInterval(() => {
if (++i < n) {
let uidlist = members.slice(i * PUSH_BATCH, (i + 1) * PUSH_BATCH - 1);
let uids: { uid: string, sid: string }[] = [];
for (let uid of uidlist) {
uids.push(channel.getMember(uid));
}
sendMessageToUsers(route, data, uids);
} else {
clearInterval(interval);
}
}, PUSH_INTERVAL);
} else {
sendMessageToChannel(channel, route, data);
}
}
// 抽下下来pushMessage收束
export function sendMessageToChannel(channel: Channel, route: string, data: any) {
if(channel.getMembers().length <= 0) return;
channel.pushMessage(route, encryptMsg(route, data));
infologger.debug(`pushMessage route: ${route} data: ${JSON.stringify(data)} members: ${channel.getMembers().join()}`);
}
export function delTeamChannel(teamCode: string) {
let channel = pinus.app.get('channelService').getChannel(teamCode);
if(!!channel) channel.destroy();
}
export function removeFromTeamChannel(teamCode: string, roleId: string) {
let channel = pinus.app.get('channelService').getChannel(teamCode);
if(!channel) return null;
let users: string[] = channel.getMembers();
if (users.indexOf(roleId) !== -1) {
channel.removeMember(roleId);
}
}
function getKvFromMemory() {
let aesKey = pinus.app.get('aesKey');
let aesIV = pinus.app.get('aesIV');
let originK = pinus.app.get('originK');
let originV = pinus.app.get('originV');
let kvRefTime = pinus.app.get('kvRefTime');
let now = new Date().setMinutes(0, 0, 0);
if(!kvRefTime || now - kvRefTime >= 60 * 60 * 1000) {
originK = genCode(24);
originV = genCode(16);
let msgEncrypt = new MsgEncrypt({ k: originK, v: originV });
({ aesKey, aesIV } = msgEncrypt.getEncodeKv());
setKvToRemote(originK, originV, aesKey, aesIV, now);
}
return { aesKey, aesIV, originK, originV, now }
}
function setKvToRemote(originK: string, originV: string, aesKey: string, aesIV: string, now: number) {
pinus.app.rpc.activity.activityRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
pinus.app.rpc.battle.battleRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
pinus.app.rpc.chat.chatRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
pinus.app.rpc.connector.connectorRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
pinus.app.rpc.guild.guildRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
pinus.app.rpc.order.orderRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
pinus.app.rpc.role.roleRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
pinus.app.rpc.systimer.systimerRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
pinus.app.rpc.comBattle.comBattleRemote.setKvToMemory.broadcast(originK, originV, aesKey, aesIV, now);
}
export function setKvToMemory(originK: string, originV: string, aesKey: string, aesIV: string, now: number) {
pinus.app.set('originK', originK);
pinus.app.set('originV', originV);
pinus.app.set('aesKey', aesKey);
pinus.app.set('aesIV', aesIV);
pinus.app.set('kvRefTime', now);
}
function encryptMsg(event: string, json: any) {
if(checkNotEncryptRoute(event)) return json
let { aesKey, aesIV, originK, originV } = getKvFromMemory();
let msgEncrypt = new MsgEncrypt({ originK, originV });
let data = msgEncrypt.encryptMsg(json);
return { data, k: aesKey, v: aesIV }
}
function checkNotEncryptRoute(event: string) {
return isSkipEncode(isDevelopEnv()) || [
PUSH_ROUTE.PUSH_CURRENT_TIME, // onPushCurrentTime 推送时间
PUSH_ROUTE.RACE_START, // onRaceStart 粮草先行开始
PUSH_ROUTE.GUILD_ACTIVITY_END, // onGuildActivityEnd 军团活动结束
PUSH_ROUTE.GUILD_RACE_UPDATE, // onRaceHorseUpdate 粮草先行状态
PUSH_ROUTE.GUILD_RACE_EVENT, // onRaceEventUpdate 更新木马事件
PUSH_ROUTE.TEAMMATE_ACT, // onTeammateAct 寻宝队友行动
PUSH_ROUTE.CITY_ACT_RANK, // onGuildCityRankUpdate 诸侯混战排行榜
PUSH_ROUTE.GUILD_CITY_ACT_HP, // onGuildCityGateHpUpdate 诸侯混战城门血条
PUSH_ROUTE.GUILD_GATE_ACT_HP, // onGuildGateHpUpdate 蛮夷入侵城门血条
PUSH_ROUTE.GATE_ACT_RANK, // onGuildGateRankUpdate 蛮夷入侵排行榜
PUSH_ROUTE.BOSS_HP_UPDATE, // onBossHpUpdate 演武台更新
PUSH_ROUTE.DIVIDEND_UPDATE, // onDividendsUpdate 拍卖行分红更新
PUSH_ROUTE.AUCTION_OVER, // onAuctionOver 拍卖价格超过
PUSH_ROUTE.GUILD_BOSS_ENCOURAGE, // onGuildBossEncourage 鼓舞
PUSH_ROUTE.GVG_TEAM_ATTACKED, // onTeamAttacked 当队伍受到攻击
PUSH_ROUTE.GVG_MY_TEAM_ATTACKED, // onMyTeamAttacked 当队伍受到攻击
PUSH_ROUTE.GVG_AREA_SPINE_CHANGE, // onAreaSpinesChange 可见区域内spine的变动每隔5秒会下发
PUSH_ROUTE.GVG_AREA_POINT_CHANGE, // onMyAreaPointChange 积分点上的驻守人变更
PUSH_ROUTE.GVG_PLAYER_AREA_ADD, // onPlayerAddToArea 积分点上的驻守人变更
PUSH_ROUTE.GVG_PLAYER_LEAVE_AREA, // onPlayerLeaveArea 积分点上的驻守人变更
PUSH_ROUTE.GVG_CITY_RANK_UPDATE, // onGVGCityRankUpdate 城池积分排名
PUSH_ROUTE.GVG_SPINE_ATTACKED, // onSpinesAttacked 队伍在地图上受到攻击
].indexOf(event) != -1
}
/**
* 推送客户端下拉消息
* @param type SDK_PUSH_MSG_TYPE
* @returns
*/
export async function pushClientMsg(type: SDK_PUSH_MSG_TYPE) {
let dicPushMessage = gameData.dicPushMessage.get(type);
if(!dicPushMessage) return;
let targetObj = await getPushTarget(dicPushMessage.playerType);
if(!targetObj) return;
if(!needPushMsg(pinus.app.get('env'))) return;
let { target, audiences } = targetObj;
let t = Date.now();
for(let i = 0; i < audiences.length; i++) {
let audience = audiences[i];
// console.log(target, audience)
if(audience || target == SDK_PUSH_TARGET_TYPE.ALL ) {
await timeoutAsync(i * 10)
await pushMsg37(t.toString(), dicPushMessage, target, audience);
}
}
}
function timeoutAsync(time: number) {
return new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, time);
})
}
// 只推送all
async function getPushTarget(playerType: number): Promise<{ target: SDK_PUSH_TARGET_TYPE, audiences: string[] }> {
return { target: SDK_PUSH_TARGET_TYPE.ALL, audiences: [''] }
// let uids: number[] = [];
// switch(playerType) {
// case SDK_PUSH_MSG_PLAYER_TYPE.HAS_GUILD:
// { uids = await getHasGuildPlayers(); break; }
// case SDK_PUSH_MSG_PLAYER_TYPE.HAS_LEAGUE:
// { uids = await getHasLeaguePlayers(); break; }
// case SDK_PUSH_MSG_PLAYER_TYPE.AFK:
// { uids = await getAfkPlayers(); break; }
// case SDK_PUSH_MSG_PLAYER_TYPE.ACTIVE_PLAYER:
// { uids = await getActivePlayers(); break; }
// }
// let len = uids.length;
// if(len == 0) return null;
// if(len == 1) return { target: SDK_PUSH_TARGET_TYPE.SINGLE, audiences: [uids.join()] };
// let audiences: string[] = [];
// for(let i = 0; i < Math.ceil(len/200); i++) {
// audiences.push(uids.slice(i * 200, i * 200 + 200).join())
// }
// return { target: SDK_PUSH_TARGET_TYPE.LIST, audiences };
}
// 有军团且24小时内登录过但当前未在线的玩家
async function getHasGuildPlayers() {
let uids: number[] = [], players: RoleType[] = [];
let createdAt: Date;
while(!createdAt || players.length > 0) {
players = await RoleModel.findHasGuildPlayers(createdAt);
if(players.length == 0) break;
createdAt = players[players.length -1].createdAt;
players.forEach(player => {
if(player.userInfo && player.userInfo.channelInfo && player.quitTime != player.loginTime && !player.isClosePush) uids.push(player.userInfo.channelInfo.uid);
});
}
return uids;
}
// 有联军且48小时内登录过但当前未在线的玩家
async function getHasLeaguePlayers() {
let leagues = await GVGLeagueModel.findActiveLeagueMembers();
let uids: number[] = [], roleIds: string[] = [];
for(let { members } of leagues) roleIds.push(...members.map(member => member.roleId));
let len = roleIds.length;
for(let i = 0; i < Math.ceil(len/1000); i++) {
let curRoleIds = roleIds.slice(i * 1000, i * 1000 + 1000);
let players = await RoleModel.findByRoleIds(curRoleIds, 'userInfo.channelInfo isClosePush');
players.forEach(player => {
if(player.userInfo && player.userInfo.channelInfo && player.quitTime != player.loginTime && !player.isClosePush) uids.push(player.userInfo.channelInfo.uid);
});
}
return uids;
}
// 至少48小时未上线且等级>=20级的玩家
async function getAfkPlayers() {
let uids: number[] = [], players: RoleType[] = [];
let createdAt: Date;
while(!createdAt || players.length > 0) {
players = await RoleModel.findAfkPlayers(createdAt);
if(players.length == 0) break;
createdAt = players[players.length -1].createdAt;
players.forEach(player => {
if(player.userInfo && player.userInfo.channelInfo && player.quitTime != player.loginTime && !player.isClosePush) uids.push(player.userInfo.channelInfo.uid);
});
}
return uids;
}
// 24小时内登录过但当前未在线的玩家
async function getActivePlayers() {
let uids: number[] = [], players: RoleType[] = [];
let createdAt: Date;
while(!createdAt || players.length > 0) {
players = await RoleModel.findActivePlayers(createdAt);
if(players.length == 0) break;
createdAt = players[players.length -1].createdAt;
players.forEach(player => {
if(player.userInfo && player.userInfo.channelInfo && player.quitTime != player.loginTime) uids.push(player.userInfo.channelInfo.uid);
});
}
return uids;
}