diff --git a/game-server/app/servers/activity/handler/activityHandler.ts b/game-server/app/servers/activity/handler/activityHandler.ts index 32ce7e1a1..4f07ac0d6 100644 --- a/game-server/app/servers/activity/handler/activityHandler.ts +++ b/game-server/app/servers/activity/handler/activityHandler.ts @@ -6,6 +6,7 @@ import { ActivityGroupModel } from '../../../db/ActivityGroup'; import { ServerlistModel } from '../../../db/Serverlist'; import { getActivity } from '../../../services/activity/activityService'; import { ActivityModel } from '../../../db/Activity'; +import { GTPushSingleCidMessage, GTCreateListMessage, GTPushListCidMessage } from '../../../services/getui/getuiService'; export default function (app: Application) { return new ActivityHandler(app); @@ -72,9 +73,17 @@ export class ActivityHandler { // await checkActivityTask(serverId, sid, funcs, roleId, TASK_TYPE.PVP, 1) // await checkActivityTask(serverId, sid, funcs, roleId, TASK_TYPE.BATTLE_TOWER_LV, 1, { towerLv: lv }) - await checkActivityTask(serverId, sid, funcs, roleId, TASK_TYPE.GASHA, 1) - + // await checkActivityTask(serverId, sid, funcs, roleId, TASK_TYPE.GASHA, 1) + if (lv == 2) { + await GTCreateListMessage('批量推送测试11', 259200000, '哈哈哈哈哈11', '噢噢噢噢噢噢噢噢11') + } + if (lv == 3) { + await GTPushListCidMessage('RASL_0630_da707a0c484d4ee39f2d462d5f52984', ['ba64ee9a9d516bbd341267d685baceb4'], true); + } + if (lv == 1) { + await GTPushSingleCidMessage('ba64ee9a9d516bbd341267d685baceb4', 259200000, '哈哈哈哈哈', '噢噢噢噢噢噢噢噢'); + } return resResult(STATUS.SUCCESS,); diff --git a/game-server/app/services/getui/getuiService.ts b/game-server/app/services/getui/getuiService.ts new file mode 100644 index 000000000..0ad41fd47 --- /dev/null +++ b/game-server/app/services/getui/getuiService.ts @@ -0,0 +1,183 @@ +import { ACTIVITY_TYPE, HTTP_METHOD } from '../../consts'; +import { httpRequest } from '../../pubUtils/httpUtil'; +import { ServerTempModel } from '../../db/ServerTemp'; +import { GetuiMessagesModel } from '../../db/GetuiMessages'; + +const crypto = require('crypto'); +const APP_ID = "T5QiUVuzjw5nNT2kwjZpD2" +const APP_KEY = "IoP3lJYAgO63UWKSx6JyV2" +const APP_SECRET = "K9tGNJBnOt7iUBjXZ13hd4" +const PACKAGE_NAME = "com.getui.demo" +const MASTER_SECRET = "VVVRlJDaog7RWbLffpHzAA" +const BASE_URL = `https://restapi.getui.com/v2/${APP_ID}` + + +/** + * 获取token + * + * + */ +export async function GTAuth() { + let url = `${BASE_URL}/auth`; + let headers = { + 'content-type': 'application/json;charset=utf-8', + }; + const timestamp = new Date().getTime(); + let body = { + sign: getSign(timestamp), + timestamp, + appkey: APP_KEY, + }; + let result = await httpRequest(url, HTTP_METHOD.POST, headers, body) + if (result.code == 0) { + console.log('GETUI_TOKEN', result.data.token) + return await ServerTempModel.updateGetuiData(result.data.token, result.data.expire_time); + } + return null; +} + +/** + * 执行cid单推 + * + * @param {number} ttl 离线时间1-3天,单位毫秒 + * @param {string} cid 玩家cid + * @param {string} title 信息标题 + * @param {string} bodyStr 信息内容 + * + */ +export async function GTPushSingleCidMessage(cid: string, ttl: number, title: string, bodyStr: string,) { + let url = `${BASE_URL}/push/single/cid`; + let body = { + "request_id": uuid(),//唯一标识 + "settings": { + "ttl": ttl,//259200000//1-3天,单位毫秒 + }, + "audience": { + "cid": [ + cid + ] + }, + "push_message": {//个推通道消息内容 + "notification": {//仅支持安卓系统,iOS系统不展示个推通道下发的通知消息 + "title": title, + "body": bodyStr, + "click_type": "none", + "url": "" + } + } + } + let result = await request(url, HTTP_METHOD.POST, {}, body) + //{"msg":"success","code":0,"data":{"RASS_0630_a35e791ba3f04c84b741b9e5f17963ae":{"ba64ee9a9d516bbd341267d685baceb4":"successed_online"}}} + //successed_online在线 successed_offline离线 + if (result.code == 0) { + await GetuiMessagesModel.insertSingleMessage(body.request_id, JSON.stringify(body), 'GTPushSingleCidMessage', true) + return true; + } + return false; +} + +/** + * 执行cid批量推 + * + * @param {string} taskid 任务id + * @param {string[]} cid cid数组 + * @param {boolean} isAsync 是否异步 + * + */ +export async function GTPushListCidMessage(taskid: string, cid: string[], isAsync: boolean = true) { + let url = `${BASE_URL}/push/list/cid`; + let body = { + "taskid": taskid, + "audience": { + "cid": cid, + }, + "is_async": isAsync,//是否异步 + } + let result = await request(url, HTTP_METHOD.POST, {}, body) + if (result.code == 0) { + await GetuiMessagesModel.pushMessageSuccess(taskid, true); + return true; + } + return false; +} + +/** + * 创建消息,此接口用来创建消息体,并返回taskid,为批量推的前置步骤 + * + * @param {number} ttl 离线时间1-3天,单位毫秒 + * @param {string} group_name 任务组名 + * @param {string} title 信息标题 + * @param {string} bodyStr 信息内容 + * + */ +export async function GTCreateListMessage(group_name: string, ttl: number, title: string, bodyStr: string,) { + let url = `${BASE_URL}/push/list/message`; + let body = { + "request_id": uuid(),//唯一标识 + "group_name": group_name,//"请填写任务组名", + "settings": { + "ttl": ttl,//259200000//1-3天,单位毫秒 + }, + "push_message": {//个推通道消息内容 + "notification": {//仅支持安卓系统,iOS系统不展示个推通道下发的通知消息 + "title": title, + "body": bodyStr, + "click_type": "none", + "url": "" + } + } + } + let result = await request(url, HTTP_METHOD.POST, {}, body) + //{"msg":"success","code":0,"data":{"taskid":"RASL_0630_da707a0c484d4ee39f2d462d5f52984c"}} + //taskid 任务编号,用于执行cid批量推和执行别名批量推,此taskid可以多次使用,有效期为用户设置的离线时间 + if (result.code == 0) { + await GetuiMessagesModel.insertListMessage(body.request_id, result.data.taskid, JSON.stringify(body), 'GTCreateListMessage', false) + return result.data.taskid; + } + return false; +} + +export async function request(url: string, method: string, headers: any, body: any) { + const timestamp = new Date().getTime(); + let tokenData = await ServerTempModel.findGetuiData(); + + if (!tokenData || (!tokenData.getuiTokenExpireTime) || timestamp > tokenData.getuiTokenExpireTime) { + tokenData = await GTAuth() + if (tokenData) { + console.log('token success') + } else { + console.log('token fail......') + } + } + + headers = { ...headers, 'content-type': 'application/json;charset=utf-8', 'token': tokenData.getuiToken }; + let result = await httpRequest(url, method, headers, body) + if (result.code == 10001) { + if (await GTAuth()) { + console.log('token success11') + } else { + console.log('token fail......') + } + } + return result; +} + + +/** + * 获取签名 + * @param timestamp 时间戳 + */ +function getSign(timestamp: number) { + let stringToSign = `${APP_KEY}${timestamp}${MASTER_SECRET}`; + return crypto.createHash('sha256').update(stringToSign).digest('hex'); +} + +function uuid() { + var d = new Date().getTime(); + var uuid = d + '-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = (d + Math.random() * 16) % 16 | 0; + d = Math.floor(d / 16); + return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16); + }); + return uuid; +}; \ No newline at end of file diff --git a/shared/consts/constModules/httpConst.ts b/shared/consts/constModules/httpConst.ts index 6fac35c26..a4ed1c756 100644 --- a/shared/consts/constModules/httpConst.ts +++ b/shared/consts/constModules/httpConst.ts @@ -1,3 +1,10 @@ +export enum HTTP_METHOD { + POST = 'POST', + GET = 'GET', + PUT = 'PUT', + DELETE = 'DELETE', +} + export enum BANTU_VID_ADDR { HOST = 'https://sdks.trgame.cn', IDCARD = '/vid/idcard', // 实名认证 diff --git a/shared/db/GetuiMessages.ts b/shared/db/GetuiMessages.ts new file mode 100644 index 000000000..f91b0d782 --- /dev/null +++ b/shared/db/GetuiMessages.ts @@ -0,0 +1,43 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; + +/** + * 个推推送消息记录 +*/ +@index({ roleId: 1 }) + +export default class Getui_Messages extends BaseModel { + @prop({ required: true }) + requestId: string; // 消息标识,唯一 + @prop({ required: false }) + taskId: string; // 群发消息id + @prop({ required: true }) + body: string; // 消息内容 + @prop({ required: true }) + des: string; // 描述 + @prop({ required: true }) + isPush: boolean; // 是否推送出去 + + //推送消息成功 + public static async pushMessageSuccess(taskId: string, isPush: boolean) { + await GetuiMessagesModel.findOneAndUpdate({ taskId }, { $set: { isPush } }, { new: true }).lean(true); + } + + //添加个人信息 + public static async insertSingleMessage(requestId: string, body: string, des: string, isPush: boolean) { + let data = { requestId, body, des, isPush }; + await GetuiMessagesModel.insertMany(data); + } + + //添加群信息 + public static async insertListMessage(requestId: string, taskId: string, body: string, des: string, isPush: boolean) { + let data = { requestId, taskId, body, des, isPush }; + await GetuiMessagesModel.insertMany(data); + } + +} + +export const GetuiMessagesModel = getModelForClass(Getui_Messages); + +export interface GetuiMessagesModelType extends Pick, keyof Getui_Messages> { } +export type GetuiMessagesModelTypeParam = Partial; // 将所有字段变成可选项 \ No newline at end of file diff --git a/shared/db/GetuiTags.ts b/shared/db/GetuiTags.ts new file mode 100644 index 000000000..081a4a456 --- /dev/null +++ b/shared/db/GetuiTags.ts @@ -0,0 +1,55 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; + +/** + * 角色的个推标签数据 +*/ +@index({ roleId: 1 }) + +export default class Getui_Tags extends BaseModel { + @prop({ required: true }) + roleId: string; // 角色id + @prop({ required: true }) + cid: string; // 个推标识 + @prop({ required: true }) + tags: string[]; // 标签 + + + //查询用户信息 + public static async findRole(roleId: string) { + let result: GetuiTagsModelType = await GetuiTagsModel.findOne( + { roleId }).lean(true); + return result; + } + + //查询用户信息 + public static async findRoles(roleIds: string[]) { + let result: GetuiTagsModelType[] = await GetuiTagsModel.find( + { roleId: { $in: roleIds } }).lean(true); + return result; + } + + //更新个推标签 + public static async updateTags(roleId: string, tags: string[]) { + let result: GetuiTagsModelType = await GetuiTagsModel.findOneAndUpdate( + { roleId }, { $set: { tags: tags } }, { new: true }).lean(true); + return result; + } + + //添加个推信息 + public static async insertRole(roleId: string, cid: string, tags: string[]) { + let result: GetuiTagsModelType = await GetuiTagsModel.findOneAndUpdate( + { roleId, cid }, { $set: { tags: tags } }, { upsert: true, new: true }).lean(true); + return result; + } + + //删除角色个推信息 + public static async delectRole(roleId: string) { + await GetuiTagsModel.deleteOne({ roleId }); + } +} + +export const GetuiTagsModel = getModelForClass(Getui_Tags); + +export interface GetuiTagsModelType extends Pick, keyof Getui_Tags> { } +export type GetuiTagsModelTypeParam = Partial; // 将所有字段变成可选项 \ No newline at end of file diff --git a/shared/db/ServerTemp.ts b/shared/db/ServerTemp.ts index 94ddc222a..2589416a3 100644 --- a/shared/db/ServerTemp.ts +++ b/shared/db/ServerTemp.ts @@ -19,6 +19,12 @@ export default class ServerTemp extends BaseModel { @prop({ required: true }) huntRoundIndex: number; // 寻宝骑兵-周期数 + + @prop({ required: true }) + getuiToken: string; // 个推token + @prop({ required: true }) + getuiTokenExpireTime: number; // 个推token过期时间 + //更新寻宝猎人活动数据 public static async updateTreasureHuntData(serverId: number, huntActivityId: number, huntBeginTime: Date, huntEndTime: Date, huntRoundIndex: number) { let result: ServerTempModelType = await ServerTempModel.findOneAndUpdate({ serverId }, @@ -37,6 +43,19 @@ export default class ServerTemp extends BaseModel { let result = await ServerTempModel.deleteMany({ serverId }); return result; } + + //更新个推token数据 + public static async updateGetuiData(getuiToken: string, getuiTokenExpireTime: number) { + let result: ServerTempModelType = await ServerTempModel.findOneAndUpdate({ serverId: 0 }, + { $set: { getuiToken, getuiTokenExpireTime } }, { upsert: true, new: true }).lean(true); + return result; + } + + //查询个推token数据 + public static async findGetuiData() { + let result: ServerTempModelType = await ServerTempModel.findOne({ serverId: 0 }).lean(true); + return result; + } } export const ServerTempModel = getModelForClass(ServerTemp); diff --git a/shared/domain/activityField/newHeroGKField.ts b/shared/domain/activityField/newHeroGKField.ts index 30051eed9..7b6b8827e 100644 --- a/shared/domain/activityField/newHeroGKField.ts +++ b/shared/domain/activityField/newHeroGKField.ts @@ -34,11 +34,13 @@ export class NewHeroGKPage { pageIndex: number; // 页码 name: string; // 名称 hid: number; //武将id + title: string = '';//客户端用说明文字 constructor(data: any) { this.pageIndex = data.pageIndex; this.name = data.name; this.hid = data.hid; + this.title = data.title; this.items = []; for (let obj of data.items) { this.items.push(new NewHeroGKItem(obj, this.pageIndex)) diff --git a/shared/domain/activityField/newHeroGiftField.ts b/shared/domain/activityField/newHeroGiftField.ts index be3a0efa5..b3c2a937c 100644 --- a/shared/domain/activityField/newHeroGiftField.ts +++ b/shared/domain/activityField/newHeroGiftField.ts @@ -25,7 +25,6 @@ export class NewHeroGiftItem { // 新将礼包数据 export class NewHeroGiftData extends ActivityBase { name: string = '';//活动名称 - title: string = '';//客户端用说明文字 list: Array = [];//礼包列表 totalPoint: number = 0;//获得总点数 consumeTotalPoint: number = 0;//消耗总点数 @@ -56,7 +55,6 @@ export class NewHeroGiftData extends ActivityBase { public initData(data: string) { let dataObj = JSON.parse(data); this.name = dataObj.name; - this.title = dataObj.title; this.totalPoint = 0; this.consumeTotalPoint = 0; this.explain = dataObj.explain; diff --git a/shared/pubUtils/httpUtil.ts b/shared/pubUtils/httpUtil.ts index 1935a6fa0..13140ca5f 100644 --- a/shared/pubUtils/httpUtil.ts +++ b/shared/pubUtils/httpUtil.ts @@ -7,8 +7,8 @@ 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==''){ +export async function reportOnline(userCode: string, packageName: string) { + if (!packageName || packageName == '') { packageName = 'com.bantu.nfsg' } @@ -16,7 +16,7 @@ export async function reportOnline ( userCode: string, packageName: string) { account: userCode, package: packageName }); - if(result && result.code !== 1) { + if (result && result.code !== 1) { console.error(result.msg); } @@ -30,8 +30,8 @@ export async function reportOnline ( userCode: string, packageName: string) { * @param userCode 账号 * @param packageName 包名 */ -export async function authenticate (name: string, idNum: string, userCode: string, packageName: string) { - if(!packageName || packageName==''){ +export async function authenticate(name: string, idNum: string, userCode: string, packageName: string) { + if (!packageName || packageName == '') { packageName = 'com.bantu.nfsg' } @@ -42,7 +42,7 @@ export async function authenticate (name: string, idNum: string, userCode: strin appkey: BANTU_VID_APP_KEY, package: packageName }); - if(result && result.code !== 1) { + if (result && result.code !== 1) { console.error(result.msg); } @@ -56,29 +56,52 @@ export async function vidHttpRequest(addr: string, body: any) { let options = { url: BANTU_VID_ADDR.HOST + addr, method: 'POST', - body:body, + body: body, json: true } try { let res = await request(options); let check = checkSign(res); - if(!check) return false; + if (!check) return false; // console.log('*****request result*****'); // console.log(JSON.stringify(res)); return res; - } catch(e) { + } catch (e) { console.error(e); return false } } -export function md5Vid (str: string) { + +export async function httpRequest(url: string, method: string, headers: any, body: any) { + console.log(`httpRequest*********: ${url}, ${method}, ${JSON.stringify(headers)}, ${JSON.stringify(body)}`) + + let options = { + url, + method, + headers, + body, + json: true + } + + try { + let res = await request(options); + console.log('*****request result*****'); + console.log(JSON.stringify(res)); + return res; + } catch (e) { + console.error(e); + return false + } +} + +export function md5Vid(str: string) { str = 'vId' + str; return crypto.createHash('md5').update(str, 'utf8').digest("hex"); }; -export function getObjSign (obj: any) { +export function getObjSign(obj: any) { const str = []; Object.keys(obj).sort().forEach((key) => { if (key == 'sign') { @@ -94,7 +117,7 @@ export function getObjSign (obj: any) { return md5Vid(strs); } -export async function checkSign (obj: any) { +export async function checkSign(obj: any) { if (getObjSign(obj) === obj.sign) { return true; }