薛定谔的猫
获取推送令牌 get-token
import cloud from '@lafjs/cloud'
import * as crypto from 'crypto'
const config = cloud.shared.get('unipush.config')
import * as axios from 'axios'
const { baseUrl, appKey, masterSecret } = config
exports.main = async function (ctx: FunctionContext) {
const hashParam = appKey + Date.now() + masterSecret
const param = {
"appkey": appKey,
"timestamp": Date.now(),
"sign": hashSign(hashParam)
}
const instance = axios.default.create({
baseURL: baseUrl
})
const res = await instance.post('/auth', param)
return res.data
}
/**
* @param {string} content
* @return {string}
*/
function hashSign(content: string): string {
return crypto
.createHash('sha256')
.update(content)
.digest('hex')
}
个推 push-single
import cloud from '@lafjs/cloud'
import * as axios from 'axios'
const config = cloud.shared.get('unipush.config')
const { baseUrl } = config
/**
* 入参:
* cid: 通过用户id查询到的cid
* title: 标题 长度<= 50
* body: 通知内容 长度 <= 256
* click_type: url/none/startapp/payload(自定义消息内容启动应用)/intent(打开应用内特定页面)
* url: 当click_type为url时必填
* intent: 当click_type为intent时必填
* channel_level: 设置通知渠道重要性(可以控制响铃,震动,浮动,闪灯等等) 0/1/2/3/4
*
* const body:any = {
cid: 'c190325c12369d231bd5264c6b4de01f',
title: '123',
body: '222',
click_type: 'none',
channel_level:4
}
*/
exports.main = async function (ctx: FunctionContext) {
const { data: { token } } = await cloud.invoke('get-token', {})
if (!token) return { error: '获取token失败', code: -1 }
const requestParam: any = {
"request_id": getRnd32(),
"settings": {
"ttl": -1,
// "speed": 100, // 个推控制下发速度在100条/秒左右
/**
1: 表示该消息在用户在线时推送个推通道,用户离线时推送厂商通道;
2: 表示该消息只通过厂商通道策略下发,不考虑用户是否在线;
3: 表示该消息只通过个推通道下发,不考虑用户是否在线;
4: 表示该消息优先从厂商通道下发,若消息内容在厂商通道代发失败后会从个推通道下发。
*/
"strategy": { // 通过strategy控制是推送个推通道的消息还是厂商通道的消息
"default": 3
}
},
"audience": {
"cid": [
body.cid
]
},
"push_message": { // 个推通道消息类容
"notification": {
"title": body.title,
"body": body.body,
"click_type": body.click_type,
"channel_level": body.channel_level
}
},
"push_channel": { // 厂商通道内容
"android": {
"ups": {
"notification": {
"title": body.title,
"body": body.body,
"click_type": body.click_type,
"channel_level": body.channel_level
}
}
}
}
}
if (body.click_type == 'url') {
requestParam.push_message.url = body.url
requestParam.push_channel.android.ups.url = body.url
}
if (body.click_type == 'intent') {
requestParam.push_message.intent = body.intent
requestParam.push_channel.android.ups.intent = body.intent
}
if (body.payload) {
requestParam.push_message.notification.payload = body.payload
requestParam.push_channel.android.ups.notification.payload = body.payload
}
let data;
await axios.default.post(`${baseUrl}/push/single/cid`, requestParam, {
headers: {
token: token,
},
})
.then(value => {
console.log(value, 'value')
data = {
code: 0, message: 'success'
}
})
.catch(err => {
console.log(err, 'error')
data = {
code: -1, error: statusCodeMap(err.response.data.code)
}
})
return data
}
/**
* 状态码相关
*/
function statusCodeMap(code) {
switch (code) {
case 10001:
return "token错误/失效";
case 30019:
return '系统繁忙,请稍后重试';
case 30009:
return '推送次数超过每日推送总数限制';
case 20001:
return '参数不合法';
case 10005:
return '每分钟调用频率超限';
case 30015:
return 'list推送 频率超过每分钟频率限制';
case 30002:
return '没有推送定时任务的权限';
case 22002:
return '任务无效或定时任务时间不合法';
case 10003:
return '每分钟鉴权频率超限';
default:
return 0
}
}
// 生成随机32位字符串
function getRnd32() {
let str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
let s = ''
for (let i = 0; i < 32; i++) {
s += str[Math.floor(Math.random() * 32)]
}
return s
}
批量推 push-batch
import cloud from '@lafjs/cloud'
import * as axios from 'axios'
const config = cloud.shared.get('unipush.config')
const { baseUrl } = config
/**
* 入参:
* cid: 通过用户id查询到的cid 数组,长度不大于1000
* title: 标题 长度<= 50
* body: 通知内容 长度 <= 256
* click_type: url/none/startapp/payload(自定义消息内容启动应用)/intent(打开应用内特定页面)
* url: 当click_type为url时必填
* intent: 当click_type为intent时必填
* channel_level: 设置通知渠道重要性(可以控制响铃,震动,浮动,闪灯等等) 0/1/2/3/4
* // const body:any = {
// cid: ['ad043d41d7942e985b48fdba3052ac12'],
// title: '123',
// body: '222',
// click_type: 'none',
// channel_level:0
// }
*/
exports.main = async function (ctx: FunctionContext) {
const { auth, body, query } = ctx
let taskId;
const { code, data: { token } } = await cloud.invoke('get-token', {})
const tokenResult = statusCodeMap(code)
if (tokenResult) return { error: tokenResult, code: -1 }
const createResult = await createMessageBody(body, token)
const codeResult = statusCodeMap(createResult.code)
if (codeResult) {
return { error: createResult.msg, code: -1 }
} else {
taskId = createResult.data.taskid
}
const pusResult = await multiPushToList(token, taskId, body.cid)
const pushCodeResult = statusCodeMap(pusResult)
if (pushCodeResult) {
return { error: pushCodeResult, code: -1 }
}
return { code: 0, message: 'success', taskId }
}
/**
* 创建消息体,批量推送前置
*/
async function createMessageBody(body, token) {
const id = getRnd32()
const pushInfo: any = {
"request_id": id,
"group_name": id,
"settings": {
"ttl": -1, // 设置离线时间 单位ms 这个时间内的多次推送可以重复利用taskid
"strategy": {
"default": 3, // 表示该消息只通过厂商通道策略下发,不考虑用户是否在线;
},
"speed": 100,
// "schedule_time": '' //定时推送时间戳
},
"push_message": { // 个推通道消息类容
"notification": {
"title": body.title,
"body": body.body,
"click_type": body.click_type,
"channel_level": body.channel_level
}
},
"push_channel": { // 厂商通道内容
"android": {
"ups": {
"notification": {
"title": body.title,
"body": body.body,
"click_type": body.click_type,
"channel_level": body.channel_level
}
}
}
}
}
if (body.payload) {
pushInfo.push_message.notification.payload = body.payload
pushInfo.push_channel.android.ups.notification.payload = body.payload
}
let r;
await axios.default.post(`${baseUrl}/push/list/message`, pushInfo, {
headers: {
token: token,
}
}).then(value => {
r = value.data
}).catch(err => {
r = err.response.data
})
return r
}
async function multiPushToList(token, taskid, cids) {
const multiPushParam = {
"audience": {
"cid": cids // cid数组,数组长度不大于1000
},
"taskid": taskid,
"is_async": true
}
let code;
await axios.default.post(`${baseUrl}/push/list/cid`, multiPushParam, {
headers: {
token: token,
}
})
.then(value => {
code = value.data.code
})
.catch(err => {
code = err.response.data.code
})
return code
}
/**
* 状态码相关
*/
function statusCodeMap(code) {
switch (code) {
case 30019:
return '系统繁忙,请稍后重试';
case 30009:
return '推送次数超过每日推送总数限制';
case 20001:
return '参数不合法';
case 10005:
return '每分钟调用频率超限';
case 30015:
return 'list推送 频率超过每分钟频率限制';
case 30002:
return '没有推送定时任务的权限';
case 22002:
return '任务无效或定时任务时间不合法';
case 10003:
return '每分钟鉴权频率超限';
default:
return 0
}
}
// 生成随机32位字符串
function getRnd32() {
let str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
let s = ''
for (let i = 0; i < 32; i++) {
s += str[Math.floor(Math.random() * 32)]
}
return s
}