From 8a122b6a4d2a2cdd874a6a1bfbacb684882b4266 Mon Sep 17 00:00:00 2001 From: luying Date: Thu, 4 Mar 2021 20:36:59 +0800 Subject: [PATCH] =?UTF-8?q?=E9=98=B2=E6=B2=89=E8=BF=B7=EF=BC=9A=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../servers/connector/handler/entryHandler.ts | 2 +- game-server/app/services/redisService.ts | 21 +++++- .../app/services/redlockCacheService.ts | 2 +- game-server/app/services/timeTaskService.ts | 75 ++++++++++++++++--- game-server/package-lock.json | 9 +++ game-server/package.json | 1 + shared/consts/constModules/httpConst.ts | 3 +- shared/db/User.ts | 18 ++++- shared/pubUtils/httpUtil.ts | 27 ++++++- web-server/app/controller/account.ts | 4 +- web-server/app/service/Auth.ts | 11 +-- 11 files changed, 141 insertions(+), 32 deletions(-) diff --git a/game-server/app/servers/connector/handler/entryHandler.ts b/game-server/app/servers/connector/handler/entryHandler.ts index 44798915f..ad5620e7b 100644 --- a/game-server/app/servers/connector/handler/entryHandler.ts +++ b/game-server/app/servers/connector/handler/entryHandler.ts @@ -54,7 +54,7 @@ export class EntryHandler { await self.app.rpc.connector.connectorRemote.remoteLogin.toServer(connect.sid, role.roleId); } let serverName = this.app.getServerId(); - await roleLogin(role.roleId, user.userCode, serverName); // 保存在线用户 + await roleLogin(role.roleId, user.userCode, serverName, user.pkgName); // 保存在线用户 await session.abind(role.roleId); session.set('uid', role.roleId); session.set('roleId', role.roleId); diff --git a/game-server/app/services/redisService.ts b/game-server/app/services/redisService.ts index bfb0929ad..b08d21cde 100644 --- a/game-server/app/services/redisService.ts +++ b/game-server/app/services/redisService.ts @@ -10,6 +10,7 @@ import { SystemConfigModel } from '../db/SystemConfig'; import { GuildRankParam, GuildLeader, RankParam } from '../domain/rank'; import { GuildModel } from '../db/Guild'; import { comBtlRanges } from '../pubUtils/gamedata'; +import { stringify } from 'querystring'; /** * 在服务重新启动时,将信息存入redis */ @@ -369,9 +370,9 @@ export function redisSidKey(roleId: string) { * @param userCode user表唯一字符串标识 * @param sid connector服的那个sid */ -export async function roleLogin(roleId: string, userCode: string, sid: string) { +export async function roleLogin(roleId: string, userCode: string, sid: string, pkgName: string) { const client: Redis.RedisClient = pinus.app.get('redis'); - let param = { userCode, sid }; + let param = { userCode, sid, pkgName }; return await client.hsetAsync(REDIS_KEY.ONLINE_USERS, roleId, JSON.stringify(param)); } @@ -407,7 +408,8 @@ export async function getRoleOnlineInfo(roleId: string) { return { isOnline: true, userCode: result.userCode, - sid: result.sid + sid: result.sid, + pkgName: result.pkgName } } catch(e) { return { isOnline: false } @@ -423,7 +425,18 @@ export async function getRoleOnlineInfo(roleId: string) { export async function getAllOnlineRoles() { const client: Redis.RedisClient = pinus.app.get('redis'); let allRoles = await client.hgetallAsync(REDIS_KEY.ONLINE_USERS); - return allRoles; + 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; } export async function resetPvpRanks() { diff --git a/game-server/app/services/redlockCacheService.ts b/game-server/app/services/redlockCacheService.ts index d1cfb177a..51c85bd67 100644 --- a/game-server/app/services/redlockCacheService.ts +++ b/game-server/app/services/redlockCacheService.ts @@ -9,7 +9,7 @@ interface UserCache { var userCacheMap = new Map(); export function init() { - scheduleJob("0/5 * * * * *", clearDirtyData, {name:'clearDirtyData'});//每个5秒钟,释放redis锁 + scheduleJob('clearDirtyData', "0/5 * * * * *", clearDirtyData);//每个5秒钟,释放redis锁 } /** * 释放锁 diff --git a/game-server/app/services/timeTaskService.ts b/game-server/app/services/timeTaskService.ts index 55033d709..2128b87d5 100644 --- a/game-server/app/services/timeTaskService.ts +++ b/game-server/app/services/timeTaskService.ts @@ -3,12 +3,12 @@ import { scheduleJob, Job } from 'node-schedule'; import { SystemConfigModel } from '../db/SystemConfig'; import PvpDefenseType,{ PvpDefenseModel } from '../db/PvpDefense'; import { PVP } from '../pubUtils/dicParam'; -import { nowSeconds, getTodayZeroPoint } from '../pubUtils/timeUtil'; +import { nowSeconds, getTodayZeroPoint, getAge } from '../pubUtils/timeUtil'; import { getPvpGkWarIds, getPvpRankRewards, getPvpHeroRewards, getResultMaxRank } from '../pubUtils/data'; -import { deepCopy, getRandomArr, resResult } from '../pubUtils/util'; +import { deepCopy, getRandomArr, resResult, shouldRefresh } from '../pubUtils/util'; import { getLvByScore } from './pvpService'; -import { getMyRank, setRank, resetPvpRanks } from './redisService'; -import { MAIL_TYPE, REDIS_KEY } from '../consts'; +import { getMyRank, setRank, resetPvpRanks, getAllOnlineRoles } from './redisService'; +import { MAIL_TYPE, REDIS_KEY, ADULT_AGE, GUEST_MAX_TIME } from '../consts'; import { RankParam } from '../domain/rank'; import { RoleModel } from '../db/Role'; import { MailModel, MailType } from '../db/Mail'; @@ -18,6 +18,8 @@ import { PvpSeasonResultModel } from '../db/PvpSeasonResult'; import { settleGuildWeekly } from './guildService'; import { STATUS } from '../consts/statusCode'; import { getMailContent, sendMail } from './mailService'; +import { reportOnline } from '../pubUtils/httpUtil'; +import User, { UserModel } from '../db/User'; const PER_SECOND = 1 * 1000; const PER_DAY = 24 * 60 * 60; const SETTLE_DIFF = 29 * 60; @@ -50,21 +52,27 @@ export async function init() { } } let settleTime = (seasonEndTime - SETTLE_DIFF)* PER_SECOND; - seasonJobId = scheduleJob(settleTime, setPvpSeasonResult, { name: 'setPvpSeasonResult' });//设置实际赛季结算时间 + seasonJobId = scheduleJob('setPvpSeasonResult', settleTime, setPvpSeasonSchdule);//设置实际赛季结算时间 - seasonEndTimeJobId = scheduleJob(seasonEndTime* PER_SECOND, resetPvpRanks, { name: 'resetRank' });//由于24之后,才展示结算之后的信息,为保排行榜信息一致性,设置实际重置排行榜的时间为12点 + seasonEndTimeJobId = scheduleJob('resetRank', seasonEndTime * PER_SECOND, resetPvpRanks);//由于24之后,才展示结算之后的信息,为保排行榜信息一致性,设置实际重置排行榜的时间为12点 warJobId = scheduleJob("0 0 0 * * 1", resetPvpWarId);//每周1零点重置地图 await resetPvpRanks();//服务器重启,重置排行榜的信息 // 周功勋结算任务 - guildWeeklyJobId = scheduleJob('0 0 0 * * 1', settleGuildWeekly, { name: 'settleGuildWeekly' }); + guildWeeklyJobId = scheduleJob('settleGuildWeekly', '0 0 0 * * 1', settleGuildWeekly); + scheduleJob('reportOnline', '* 0/5 * * * *', reportOnlineSchedule) } + +function setPvpSeasonSchdule() { + setPvpSeasonResult(); +} + /** * pvp定时任务赛季结算 * @param obj */ -export async function setPvpSeasonResult(obj:{ name:string, notSetNext?: boolean, notPush?: boolean }) { +export async function setPvpSeasonResult(obj?:{ name:string, notSetNext?: boolean, notPush?: boolean }) { console.log('exce setPvpSeasonResult'+ obj?.name); let { seasonNum, seasonEndTime, oldSeasonEndTime } = await setNextPvpTime(obj?.notSetNext);//设置下个结算任务 let resultMaxRank = getResultMaxRank();//根据排行榜的奖励表,获得最大排名挡位的最小值,其余不在结算中结算的玩家按照最大排名挡位在登录或进入pvp时结算 @@ -214,8 +222,8 @@ async function setNextPvpTime(notSetNext: boolean) { seasonEndTime = (PVP.PVP_SEASON_DAYS + 1) * PER_DAY + getTodayZeroPoint(); await SystemConfigModel.updateSeason(seasonEndTime, oldSeasonEndTime); let settleTime = (seasonEndTime - SETTLE_DIFF)* PER_SECOND; - seasonJobId = scheduleJob(settleTime, setPvpSeasonResult, { name: 'setPvpSeasonResult' }); - seasonEndTimeJobId = scheduleJob(seasonEndTime* PER_SECOND, resetPvpRanks, { name: 'resetRank' }); + seasonJobId = scheduleJob('setPvpSeasonResult', settleTime, setPvpSeasonSchdule); + seasonEndTimeJobId = scheduleJob('resetRank', seasonEndTime* PER_SECOND, resetPvpRanks); return { seasonEndTime, seasonNum: seasonNum + 1, oldSeasonEndTime }; } @@ -254,6 +262,51 @@ export async function resetPvpSeasonTime(hour: number) { } let settleTime = (seasonEndTime - SETTLE_DIFF)* PER_SECOND; console.log('settleTime = ' + settleTime) - seasonJobId = scheduleJob(settleTime, setPvpSeasonResult, { name: 'setPvpSeasonResult' }); + seasonJobId = scheduleJob('setPvpSeasonResult', settleTime, setPvpSeasonSchdule); return { seasonEndTime, seasonNum }; +} + + +export async function reportOnlineSchedule() { + let allRoles = await getAllOnlineRoles(); + console.log('reportOnlineSchedule all roles count: ', allRoles.length) + for(let { roleId, userCode, sid, pkgName } of allRoles) { + let result = await reportOnline(userCode, pkgName); // 连接sdk + if(!result || result.code == -1) continue; + + let user = await UserModel.findUserByUserCode(userCode); + if(!user) continue; + let { reportTime = new Date(), lastLoginTime = new Date(), guestTime, isGuest, hasAuthenticated, birthday } = user; + + let age = getAge(birthday); + let isAdult = age >= ADULT_AGE; + // TODO 将code含义写入const + if(result.code != 1) { // 未成年人防沉迷 + pinus.app.channelService.pushMessageByUids('onPlayTime', resResult(STATUS.SUCCESS, { + isGuest, + guestTime, // 游客已体验时间 + hasAuthenticated, // 是否进行过实名认证 + isAdult, // 是否已成年 + todayPlayTime: result.total, // 今天已游戏时长 + type: result.code + } ), [{uid: roleId, sid: sid}]); + } else { + let lastTime = lastLoginTime > reportTime? lastLoginTime.getTime(): reportTime.getTime(); + let guestTimeInc = Math.floor((Date.now() - lastTime)/1000); + user = await UserModel.updatePlayTime(userCode, guestTimeInc, result.total); // 记录时间 + + guestTime = user.guestTime; + if (isGuest && guestTime > GUEST_MAX_TIME) { + pinus.app.channelService.pushMessageByUids('onPlayTime', resResult(STATUS.SUCCESS, { + isGuest, + guestTime, // 游客已体验时间 + hasAuthenticated, // 是否进行过实名认证 + isAdult, // 是否已成年 + todayPlayTime: result.total, // 今天已游戏时长 + type: 1 + } ), [{uid: roleId, sid: sid}]); + } + } + + } } \ No newline at end of file diff --git a/game-server/package-lock.json b/game-server/package-lock.json index 94d01183d..98fd8071d 100644 --- a/game-server/package-lock.json +++ b/game-server/package-lock.json @@ -126,6 +126,15 @@ "resolved": "https://registry.npm.taobao.org/@types/node/download/@types/node-8.10.54.tgz?cache=0&sync_timestamp=1595281257528&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-8.10.54.tgz", "integrity": "sha1-HIjrJTrBIQ8aWHaVP7cPfMSShAI=" }, + "@types/node-schedule": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/node-schedule/-/node-schedule-1.3.1.tgz", + "integrity": "sha512-xAY/ZATrThUkMElSDfOk+5uXprCrV6c6GQ5gTw3U04qPS6NofE1dhOUW+yrOF2UyrUiAax/Zc4WtagrbPAN3Tw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/redis": { "version": "2.8.25", "resolved": "https://registry.npm.taobao.org/@types/redis/download/@types/redis-2.8.25.tgz", diff --git a/game-server/package.json b/game-server/package.json index c0faa1ef1..9272ad8bc 100644 --- a/game-server/package.json +++ b/game-server/package.json @@ -52,6 +52,7 @@ "ts-node": "^8.2.0" }, "devDependencies": { + "@types/node-schedule": "^1.3.1", "tslint": "^5.9.1", "typescript": "^3.9.7" } diff --git a/shared/consts/constModules/httpConst.ts b/shared/consts/constModules/httpConst.ts index 558bab778..6fac35c26 100644 --- a/shared/consts/constModules/httpConst.ts +++ b/shared/consts/constModules/httpConst.ts @@ -1,5 +1,6 @@ export enum BANTU_VID_ADDR { HOST = 'https://sdks.trgame.cn', - IDCARD = '/vid/idcard' // 实名认证 + IDCARD = '/vid/idcard', // 实名认证 + REPORT_ONLINE = '/addiction_prevention/report_online' } export const BANTU_VID_APP_KEY = '05c1c495369769e3c5d98426e9c8c2c0'; diff --git a/shared/db/User.ts b/shared/db/User.ts index 899acbe2c..73bacf767 100644 --- a/shared/db/User.ts +++ b/shared/db/User.ts @@ -58,7 +58,7 @@ export default class User extends BaseModel { @prop({ required: false, default: 0 }) todayPlayTime: number; // 今日游戏时间 @prop({ required: false }) - refDaily: Date; // 刷新todayPlayTime时间 + reportTime: Date; // 汇报时间 @prop({ required: false, default: false }) hasSetPw: boolean; // 是否设置过密码 @@ -149,9 +149,8 @@ export default class User extends BaseModel { return user; } - public static async bindTel(uid: number, tel: string, password: string, lean = true) { - let r = await this.encryptPass(password); - const user: UserType = await UserModel.findOneAndUpdate({ uid, isGuest: true }, { $set: { password: r.npassword, salt: r.salt, hasSetPw: true, tel, isGuest: false }}, {new: true}).lean(lean); + public static async bindTel(uid: number, tel: string, lean = true) { + const user: UserType = await UserModel.findOneAndUpdate({ uid, isGuest: true }, { $set: { tel, isGuest: false }}, {new: true}).lean(lean); return user; } @@ -188,6 +187,11 @@ export default class User extends BaseModel { return user; } + public static async findUserByUserCode(userCode: string, lean = true) { + const user: UserType = await UserModel.findOne({ userCode }).lean(lean); + return user; + } + public static async addAuth(uid: number, auth: number, lean = true) { const user: UserType = await UserModel.findOneAndUpdate({ uid }, { auth }).select('uid tel').lean(lean); return user; @@ -208,6 +212,12 @@ export default class User extends BaseModel { const user: UserType[] = await UserModel.find(searchObj).select('uid tel username serverType auth').lean(lean); return user; } + + + public static async updatePlayTime(userCode: string, guestTimeInc: number, todayPlayTime: number, lean = true) { + const user: UserType = await UserModel.findOneAndUpdate({ userCode }, { $inc: { guestTime: guestTimeInc }, $set: { todayPlayTime, reportTime: new Date() }}, { new: true }).lean(lean); + return user; + } } diff --git a/shared/pubUtils/httpUtil.ts b/shared/pubUtils/httpUtil.ts index 128e2d7ac..bf6b85c87 100644 --- a/shared/pubUtils/httpUtil.ts +++ b/shared/pubUtils/httpUtil.ts @@ -2,20 +2,41 @@ import * as request from "request-promise"; import * as crypto from 'crypto' import { BANTU_VID_ADDR, BANTU_VID_APP_KEY } from '../consts'; +/** + * 在线报告 + * @param userCode 账号 + * @param packageName 包名 + */ +export async function reportOnline ( userCode: string, packageName: string) { + if(!packageName || packageName==''){ + packageName = 'com.bantu.nfsg' + } + + let result = await vidHttpRequest(BANTU_VID_ADDR.REPORT_ONLINE, { + account: userCode, + package: packageName + }); + if(result && result.code !== 1) { + console.error(result.msg); + } + + return result; +} + /** * 实名认证 * @param name 真实姓名 * @param idNum 身份证号 - * @param roleId 账号 + * @param userCode 账号 * @param packageName 包名 */ -export async function authenticate (name: string, idNum: string, roleId: string, packageName: string) { +export async function authenticate (name: string, idNum: string, userCode: string, packageName: string) { if(!packageName || packageName==''){ packageName = 'com.bantu.nfsg' } let result = await vidHttpRequest(BANTU_VID_ADDR.IDCARD, { - account: roleId, + account: userCode, cardno: idNum, name, appkey: BANTU_VID_APP_KEY, diff --git a/web-server/app/controller/account.ts b/web-server/app/controller/account.ts index 30317ec1f..e31b01653 100644 --- a/web-server/app/controller/account.ts +++ b/web-server/app/controller/account.ts @@ -46,8 +46,8 @@ export default class AccountController extends Controller { public async bind() { const { ctx } = this; - const { tel, code, password } = ctx.request.body; - ctx.body = await ctx.service.auth.bind(tel, code, password); + const { tel, code } = ctx.request.body; + ctx.body = await ctx.service.auth.bind(tel, code); } public async authentication() { diff --git a/web-server/app/service/Auth.ts b/web-server/app/service/Auth.ts index c164aca06..f5345e2b9 100644 --- a/web-server/app/service/Auth.ts +++ b/web-server/app/service/Auth.ts @@ -85,7 +85,7 @@ export default class Auth extends Service { let age = getAge(user.birthday); let isAdult = age >= ADULT_AGE; let todayPlayTime = user.todayPlayTime; - if(shouldRefresh(user.refDaily, new Date(), 0)) { + if(shouldRefresh(user.reportTime, new Date(), 0)) { todayPlayTime = 0; } return { @@ -322,9 +322,10 @@ export default class Auth extends Service { /** * 绑定账号 - * @param password 密码 + * @param tel 手机号 + * @param code 验证码 */ - public async bind(tel: string, code: string, password: string) { + public async bind(tel: string, code: string) { const ctx = this.ctx; // 参数检查 const telVerify = this.checkTelNo(tel); @@ -332,7 +333,7 @@ export default class Auth extends Service { return telVerify.resResult; } - if (!isString(code) || code.length !== 6 || !password) { + if (!isString(code) || code.length !== 6) { return ctx.service.utils.resResult(STATUS.WRONG_PARMS); } @@ -354,7 +355,7 @@ export default class Auth extends Service { return ctx.service.utils.resResult(STATUS.TEL_HAS_USED); } - let user = await UserModel.bindTel(ctx.uid, tel, password); + let user = await UserModel.bindTel(ctx.uid, tel); if(!user) return ctx.service.utils.resResult(STATUS.ACCOUNT_NOT_GUEST); let param = this.getReturnParam(user); return ctx.service.utils.resResult(STATUS.SUCCESS, param);