推送:接入个推推送接口
This commit is contained in:
@@ -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,);
|
||||
|
||||
|
||||
183
game-server/app/services/getui/getuiService.ts
Normal file
183
game-server/app/services/getui/getuiService.ts
Normal file
@@ -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;
|
||||
};
|
||||
@@ -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', // 实名认证
|
||||
|
||||
43
shared/db/GetuiMessages.ts
Normal file
43
shared/db/GetuiMessages.ts
Normal file
@@ -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<DocumentType<Getui_Messages>, keyof Getui_Messages> { }
|
||||
export type GetuiMessagesModelTypeParam = Partial<GetuiMessagesModelType>; // 将所有字段变成可选项
|
||||
55
shared/db/GetuiTags.ts
Normal file
55
shared/db/GetuiTags.ts
Normal file
@@ -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<DocumentType<Getui_Tags>, keyof Getui_Tags> { }
|
||||
export type GetuiTagsModelTypeParam = Partial<GetuiTagsModelType>; // 将所有字段变成可选项
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -25,7 +25,6 @@ export class NewHeroGiftItem {
|
||||
// 新将礼包数据
|
||||
export class NewHeroGiftData extends ActivityBase {
|
||||
name: string = '';//活动名称
|
||||
title: string = '';//客户端用说明文字
|
||||
list: Array<NewHeroGiftItem> = [];//礼包列表
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user