diff --git a/game-server/app/servers/role/remote/roleRemote.ts b/game-server/app/servers/role/remote/roleRemote.ts index eb705dfe4..81458eea2 100644 --- a/game-server/app/servers/role/remote/roleRemote.ts +++ b/game-server/app/servers/role/remote/roleRemote.ts @@ -7,7 +7,7 @@ import { SkinUpdate } from '../../../db/Skin'; import { RankFirstModel, RankFirstType } from '../../../db/RankFirst'; import { Figure } from '../../../domain/dbGeneral'; import { PVPConfigModel, PVPConfigType } from '../../../db/SystemConfig'; -import { treatRoleName, taflush } from '../../../services/sdkService'; +import { treatRoleName, taflush, sendSurveyMail } from '../../../services/sdkService'; import { getServerMainten, setServerMainten, stopServerMainten } from '../../../services/gmService'; import { errlogger } from '../../../util/logger'; @@ -132,4 +132,13 @@ export class RoleRemote { errlogger.error(`remote ${__filename} \n ${e.stack}`); } } + + public async sendSurveyMail(code: string) { + try { + await sendSurveyMail(code); + } catch(e) { + errlogger.error(`remote ${__filename} \n ${e.stack}`); + } + } + } diff --git a/game-server/app/services/redisService.ts b/game-server/app/services/redisService.ts index 66b11677c..1aeba36eb 100644 --- a/game-server/app/services/redisService.ts +++ b/game-server/app/services/redisService.ts @@ -545,7 +545,8 @@ export async function redisSubScribe() { let refundChannel = getRedisSubChannel(REDIS_KEY.REFUND_CHANNEL, env); let treatRoleChannel = getRedisSubChannel(REDIS_KEY.TREAT_ROLE_CHANNEL, env); let treatGuildChannel = getRedisSubChannel(REDIS_KEY.TREAT_GUILD_CHANNEL, env); - await redisClientPub().subscribeAsync(payChannel, treatRoleChannel, treatGuildChannel, refundChannel); + let surveyChannel = getRedisSubChannel(REDIS_KEY.SURVEY_CHANNEL, env); + await redisClientPub().subscribeAsync(payChannel, treatRoleChannel, treatGuildChannel, refundChannel, surveyChannel); redisClientPub().on('message', (channel, message) => { console.log('**********redisSubScribe*******') console.log('channel: ', channel, payChannel); @@ -566,7 +567,10 @@ export async function redisSubScribe() { let servers = pinus.app.getServersByType('order'); let server = getRandSingleEelm(servers); pinus.app.rpc.order.orderRemote.refundOrderFromRedisPub.toServer(server.id, message); - + } else if (channel == surveyChannel) { + let servers = pinus.app.getServersByType('role'); + let server = getRandSingleEelm(servers); + pinus.app.rpc.role.roleRemote.sendSurveyMail.toServer(server.id, message); } }); } diff --git a/game-server/app/services/sdkService.ts b/game-server/app/services/sdkService.ts index 3716c4440..304be21c2 100644 --- a/game-server/app/services/sdkService.ts +++ b/game-server/app/services/sdkService.ts @@ -11,11 +11,13 @@ import { GuildModel } from "../db/Guild"; import { getRoleOnlineInfo, updateUserInfo } from "./redisService"; import { Application, pinus } from "pinus"; import { getGuildChannelSid } from "./chatService"; -import { getRandSingleEelm, readWordTxt, resResult, writeWordTxt } from "../pubUtils/util"; +import { getRandSingleEelm, parseGoodStr, readWordTxt, resResult, writeWordTxt } from "../pubUtils/util"; const ThinkingAnalytics = require("thinkingdata-node"); import Trie from '../pubUtils/trie'; import _ = require("underscore"); import { getGoldObject } from "./role/rewardService"; +import { SurveyRecModel } from "../db/SurveyRec"; +import { SurveyModel } from "../db/Survery"; // 检查私聊是否合法 @@ -283,4 +285,17 @@ export async function checkFilterWords(word: string) { let server = getRandSingleEelm(servers); return await pinus.app.rpc.chat.chatRemote.checkFilterWords.toServer(server.id, word); } +} + +export async function sendSurveyMail(code: string) { + let rec = await SurveyRecModel.findByCode(code); + if(!rec || rec.hasSentMail) return false; + + let survey = await SurveyModel.findBySurveyId(rec.surveyId); + if(!survey) return false; + + let reward = parseGoodStr(survey.reward); + + await sendMailByContent(MAIL_TYPE.SEND_MAIL, rec.roleId, { goods: reward, params: [survey.mailContent] }); + rec = await SurveyRecModel.send(rec.code); } \ No newline at end of file diff --git a/shared/consts/constModules/httpConst.ts b/shared/consts/constModules/httpConst.ts index bd5e30598..afa460338 100644 --- a/shared/consts/constModules/httpConst.ts +++ b/shared/consts/constModules/httpConst.ts @@ -34,4 +34,6 @@ export enum SDK_TA_CONST { APPID = '74120ffc6f2945448cc60bf1540c5ad4', SERVER_URL = 'https://shushu.xyplay.cn', LOG_PATH = '/root/zyz/game-server/logs/ta', -} \ No newline at end of file +} + +export const WJX_KEY = "f98551ef-4c7a-4ae2-abda-b7cca2684fe6" \ No newline at end of file diff --git a/shared/consts/constModules/sysConst.ts b/shared/consts/constModules/sysConst.ts index 6ba6723cc..bd1bf6fb8 100644 --- a/shared/consts/constModules/sysConst.ts +++ b/shared/consts/constModules/sysConst.ts @@ -242,6 +242,7 @@ export enum REDIS_KEY { TREAT_GUILD_CHANNEL = 'treatGuild', // 处理公会账号名频道 GUILD_FUND = 'guildFund', // 限时排行 SUM_CE_SNAPSHOT = "sumCeTL", // 限时战力排行榜 + SURVEY_CHANNEL = 'survey', // 文件频道 } // 各排行榜对应hash的key diff --git a/shared/db/Survery.ts b/shared/db/Survery.ts new file mode 100644 index 000000000..80ecb1661 --- /dev/null +++ b/shared/db/Survery.ts @@ -0,0 +1,32 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; + +@index({ id: 1 }) +@index({ seasonNum: 1 }) +export default class Survey extends BaseModel { + + @prop({ required: true }) + surveyId: string; // 问卷id + + @prop({ required: true }) + surveyName: string; // 问卷id + + @prop({ required: true }) + roleIndex: number; // 问卷id + + @prop({ required: true }) + reward: string; // 奖励 + + @prop({ required: true }) + mailContent: string; // 邮件文字 + + public static async findBySurveyId(surveyId: string) { + let rec: SurveyType = await SurveyModel.findOne({ surveyId }).lean(); + return rec; + } +} + +export const SurveyModel = getModelForClass(Survey); + +export interface SurveyType extends Pick, keyof Survey> {}; +export type SurveyUpdate = Partial; // 将所有字段变成可选项 diff --git a/shared/db/SurveyRec.ts b/shared/db/SurveyRec.ts new file mode 100644 index 000000000..c0a850d38 --- /dev/null +++ b/shared/db/SurveyRec.ts @@ -0,0 +1,52 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; +import { genCode } from '../pubUtils/util'; + +@index({ id: 1 }) +@index({ seasonNum: 1 }) +export default class SurveyRec extends BaseModel { + + @prop({ required: true, default: 1 }) + code: string; // 编码 + + @prop({ required: true, default: 1 }) + roleId: string; // 玩家id + + @prop({ required: true }) + surveyId: string; // 问卷id + + @prop({ required: true }) + index: string; // 有没有发邮件 + + @prop({ required: true }) + hasSentMail: boolean; // 有没有发邮件 + + @prop({ required: true }) + json: string; // 整个回调 + + public static async findByRoleIdAndId(roleId: string, surveyId: string) { + let rec: SurveyRecType = await SurveyRecModel.findOne({ roleId, surveyId }).lean(); + return rec; + } + + public static async findByCode(code: string) { + let rec: SurveyRecType = await SurveyRecModel.findOne({ code }).lean(); + return rec; + } + + public static async createSurveyRec(roleId: string, surveyId: string, index: string, json: string) { + let code = genCode(8); + let rec: SurveyRecType = await SurveyRecModel.findOneAndUpdate({ roleId, surveyId }, { $set: { hasSentMail: false, json, index, code } }, { upsert: true, new: true }).lean(); + return rec; + } + + public static async send(code: string) { + let rec: SurveyRecType = await SurveyRecModel.findOneAndUpdate({ code }, { $set: { hasSentMail: true } }).lean(); + return rec; + } +} + +export const SurveyRecModel = getModelForClass(SurveyRec); + +export interface SurveyRecType extends Pick, keyof SurveyRec> {}; +export type SurveyRecUpdate = Partial; // 将所有字段变成可选项 diff --git a/shared/pubUtils/sdkUtil.ts b/shared/pubUtils/sdkUtil.ts index 0260a9fae..7718cf89c 100644 --- a/shared/pubUtils/sdkUtil.ts +++ b/shared/pubUtils/sdkUtil.ts @@ -1,4 +1,4 @@ -import { REDIS_KEY, SDK_37_ADDR, SDK_37_CONST } from '../consts'; +import { REDIS_KEY, SDK_37_ADDR, SDK_37_CONST, WJX_KEY } from '../consts'; import { request37 } from './httpUtil'; import { nowSeconds } from './timeUtil'; import { LoginValidataReturn37, Chat37Params, GetServerListParam } from '../domain/sdk'; @@ -12,6 +12,12 @@ export function md5(str: string, treatStr?: (str: string) => string) { return crypto.createHash('md5').update(str, 'utf8').digest("hex"); }; +export function sha1(str: string, treatStr?: (str: string) => string) { + if(treatStr) str = treatStr(str); + // console.log('*****str', str) + return crypto.createHash('sha1').update(str, 'utf8').digest("hex"); +} + export function getMd5ObjSign(obj: any, joinMark: string, treatStr?: (str: string) => string) { const str = []; Object.keys(obj).sort().forEach((key) => { @@ -36,7 +42,6 @@ export async function checkMd5Sign(obj: any, treatStr?: (str: string) => string) return false; } - /************** 37sdk **************/ export function get37Md5SignA(body: any, key: string) { @@ -123,4 +128,14 @@ function treatVid(str) { export function getRedisSubChannel(key: REDIS_KEY, env: string) { return `${key}:${env}`; +} + +/********* 问卷星加密 *********/ + +export function checkWjxSign(activity: string, index: string, sign: string) { + const str = `${activity}${index}${WJX_KEY}`; + let signResult = sha1(str); + console.log('##### checkWjxSign', str, signResult, sign); + if(signResult != sign) return false; + return true; } \ No newline at end of file diff --git a/web-server/app/controller/sdk.ts b/web-server/app/controller/sdk.ts index 9fcd2104b..41f76a7ed 100644 --- a/web-server/app/controller/sdk.ts +++ b/web-server/app/controller/sdk.ts @@ -54,4 +54,11 @@ export default class SdkController extends Controller { ctx.body = await ctx.service.sdk.getServerList(params); return; } + + public async wjxCallback() { + const { ctx } = this; + + ctx.body = await ctx.service.wjx.wjxCallback(ctx.request.body); + return; + } } diff --git a/web-server/app/router.ts b/web-server/app/router.ts index 92ef51770..73e36f3da 100644 --- a/web-server/app/router.ts +++ b/web-server/app/router.ts @@ -35,4 +35,7 @@ export default (app: Application) => { router.get('/cb/getserverlist', controller.sdk.getServerList); router.post('/cb/getserverlist', controller.sdk.getServerList); router.post('/cb/refundioscallback', controller.sdk.refundIOSCallback); + + // 问卷星回调 + router.post('/cb/wjx', controller.sdk.wjxCallback) }; diff --git a/web-server/app/service/Wjx.ts b/web-server/app/service/Wjx.ts new file mode 100644 index 000000000..6711ad1af --- /dev/null +++ b/web-server/app/service/Wjx.ts @@ -0,0 +1,46 @@ + +import { SurveyRecModel } from '@db/SurveyRec'; +import { SurveyModel } from '@db/Survery'; +import { checkWjxSign, getRedisSubChannel } from 'app/pubUtils/sdkUtil'; +import { Service } from 'egg'; +import { RedisClient } from 'redis'; +import { REDIS_KEY } from '@consts'; +import { RoleModel } from '@db/Role'; + +/** + * Test Service + */ +export default class Sdk extends Service { + + public async wjxCallback(params: any) { + // 1. 检查sign + if(!checkWjxSign(params.activity, params.index, params.sign)) { + return 0 + } + // 2. 查询配置 + let curConfig = await SurveyModel.findBySurveyId(params.activity); + if(!curConfig) return 0; + + let roleId = params[`q${curConfig.roleIndex}`]; + if(!roleId) return 0; + + let role = await RoleModel.findByRoleId(roleId); + if(!role) return 0; + + let rec = await SurveyRecModel.findByRoleIdAndId(roleId, params.activity); + if(rec) return 0; + + rec = await SurveyRecModel.createSurveyRec(roleId, params.activity, params.index, JSON.stringify(params)); + + // 3. 发邮件 + let redisClient: RedisClient = this.app.context.redisClient; + let name = getRedisSubChannel(REDIS_KEY.SURVEY_CHANNEL, this.app.config.env); + let result = await redisClient.publishAsync(name, rec.code); + if(result == 0) { + console.error('用户名违规处理, 未发布到订阅频道'); + return 0 + } + return 1 + } + +}