jpush-sdk
Version:
JPush's officially supported Node.js client library.
714 lines (635 loc) • 19.6 kB
JavaScript
/* eslint-disable camelcase */
var JError = require('./JPushError')
var JUtil = require('./util')
function PushPayload (client) {
this.client = client
this.payload = {}
this.trigger = {}
}
function setPlatform () {
if (arguments.length < 1) {
throw new JError.InvalidArgumentError("platform's args cannot all be null")
}
var platform, i
if (arguments.length === 1 && arguments[0] === ALL) {
platform = ALL
} else if (arguments.length === 1 && typeof arguments[0] === 'object') {
platform = []
for (i = 0; i < arguments[0].length; i++) {
if (VALID_DEVICE_TYPES.indexOf(arguments[0][i]) !== -1) {
if (platform.indexOf(arguments[0][i]) === -1) {
platform.push(arguments[0][i])
}
} else {
throw new JError.InvalidArgumentError("Invalid device type '" + arguments[0][i] +
"', platform can only be set to 'android', 'ios' or 'winPhone'")
}
}
} else {
platform = []
for (i = 0; i < arguments.length; i++) {
if (VALID_DEVICE_TYPES.indexOf(arguments[i]) !== -1) {
if (platform.indexOf(arguments[i]) === -1) {
platform.push(arguments[i])
}
} else {
throw new JError.InvalidArgumentError("Invalid device type '" + arguments[i] +
"', platform can only be set to 'android', 'ios' or 'winPhone'")
}
}
}
this.payload = JUtil.extend(this.payload, {
'platform': platform
})
return this
}
function buildAudience (args, title) {
if (args.length < 1) {
throw new JError.InvalidArgumentError('Should be set at least one ' + title)
}
var payload = []
var i
if (args.length === 1 && typeof args[0] === 'string') {
var tags_t = args[0].split(',')
for (i = 0; i < tags_t.length; i++) {
if (tags_t[i].trim().length > 0) {
payload.push(tags_t[i].trim())
}
}
if (payload.length < 1) {
throw new JError.InvalidArgumentError('Should be set at least one ' + title)
}
} else if (args.length === 1 && Array.isArray(args[0])) {
for (i = 0; i < args[0].length; i++) {
if (typeof args[0][i] !== 'string') {
throw new JError.InvalidArgumentError('Invalid ' + title + ' at index ' + i + ', ' +
title + ' can only be set to the String')
}
payload.push(args[0][i])
}
} else {
for (i = 0; i < args.length; i++) {
if (typeof args[i] !== 'string') {
throw new JError.InvalidArgumentError('Invalid ' + title + ' at argument ' + i + ', ' +
title + ' can only be set to the String')
}
payload.push(args[i])
}
}
return payload
}
function alias () {
return {
'alias': buildAudience(arguments, 'alias')
}
}
function tag () {
return {
'tag': buildAudience(arguments, 'tag')
}
}
function tag_and () {
return {
'tag_and': buildAudience(arguments, 'tag_and')
}
}
function tag_not() {
return {
'tag_not': buildAudience(arguments, 'tag_not')
}
}
function registration_id () {
return {
'registration_id': buildAudience(arguments, 'registration_id')
}
}
function segment() {
return {
'segment': buildAudience(arguments, 'segment')
}
}
function abtest() {
return {
'abtest': buildAudience(arguments, 'abtest')
}
}
function setAudience () {
if (arguments.length < 1) {
throw new JError.InvalidArgumentError('audience must be set')
}
var audience
if (arguments.length === 1 && arguments[0] === ALL) {
audience = ALL
} else {
audience = {}
for (var i = 0; i < arguments.length; i++) {
audience = JUtil.extend(audience, arguments[i])
}
}
this.payload = JUtil.extend(this.payload, {
'audience': audience
})
return this
}
function android (alert, title, builder_id, extras, priority, category, style, value, alertType, uriActivity) {
if (alert != null) {
if (typeof alert !== 'string') {
throw new JError.InvalidArgumentError('android.alert is require and only can be set to the string')
}
}
var android = {
'alert': alert
}
if (title != null) {
if (typeof title !== 'string') {
throw new JError.InvalidArgumentError('Invalid android.title, it only can be set to the string')
}
android['title'] = title
}
if (builder_id != null) {
if (typeof builder_id !== 'number') {
throw new JError.InvalidArgumentError('Invalid android.builder_id, it only can be set to the number')
}
android['builder_id'] = builder_id
}
if (extras != null) {
if (typeof extras !== 'object') {
throw new JError.InvalidArgumentError('Invalid android.extras')
}
android['extras'] = extras
}
if (priority != null) {
if (typeof priority !== 'number') {
throw new JError.InvalidArgumentError('Invalid android.priority, it only can be set to the number.')
}
android['priority'] = priority
}
if (category != null) {
if (typeof category !== 'string') {
throw new JError.InvalidArgumentError('Invalid android.category, it only can be set to the number.')
}
android['category'] = category
}
if (style != null) {
if (typeof style !== 'number') {
throw new JError.InvalidArgumentError('Invalid android.style, it only can be set to the number.')
}
if (style === 1) {
android['big_text'] = value
} else if (style === 2) {
android['inbox'] = value
} else if (style === 3) {
android['big_pic_path'] = value
}
}
if (alertType != null) {
if (typeof alertType !== 'number') {
throw new JError.InvalidArgumentError('Invalid android.alertType, it only can be set to the number.')
}
android['alert_type'] = alertType
}
if (uriActivity != null) {
android['uri_activity'] = uriActivity
}
return {
'android': android
}
}
function ios (alert, sound, badge, contentAvailable, extras, category, mutableContent) {
if (alert != null) {
if (typeof alert !== 'string' && typeof alert !== 'object') {
throw new JError.InvalidArgumentError('ios.alert is require and can only be set to the String or object')
}
}
var ios = {
'alert': alert
}
if (sound != null) {
if (typeof sound !== 'string') {
throw new JError.InvalidArgumentError('Invalid ios.sound, it can only be set to the String')
}
ios['sound'] = sound
}
if (badge != null) {
ios['badge'] = badge
}
if (contentAvailable != null) {
if (typeof contentAvailable !== 'boolean') {
throw new JError.InvalidArgumentError('Invalid ios.contentAvailable, it can only be set to the Boolean')
}
ios['content-available'] = contentAvailable
}
if (extras != null) {
if (typeof extras !== 'object') {
throw new JError.InvalidArgumentError('Invalid ios.extras')
}
ios['extras'] = extras
}
if (category != null) {
ios['category'] = category
}
if (mutableContent != null) {
if (typeof mutableContent !== 'boolean') {
throw new JError.InvalidArgumentError('Invalid ios.mutable-content, it can only be set to the boolean.')
}
ios['mutable-content'] = mutableContent
}
return {
'ios': ios
}
}
function winphone (alert, title, openPage, extras) {
if (alert != null) {
if (typeof alert !== 'string') {
throw new JError.InvalidArgumentError('winphone.alert is require and can only be set to the String')
}
}
var winphone = {
'alert': alert
}
if (title != null) {
if (typeof title !== 'string') {
throw new JError.InvalidArgumentError('Invalid winphone.title, it can only be set to the String')
}
winphone['title'] = title
}
if (openPage != null) {
if (typeof openPage !== 'string') {
throw new JError.InvalidArgumentError('Invalid winphone.openPage, it can only be set to the String')
}
winphone['_open_page'] = openPage
}
if (extras != null) {
if (typeof extras !== 'object') {
throw new JError.InvalidArgumentError('Invalid winphone.extras')
}
winphone['extras'] = extras
}
return {
'winphone': winphone
}
}
function setNotification () {
if (arguments.length < 1) {
throw new JError.InvalidArgumentError('Invalid notification')
}
var notification = {}
var offset = 0
if (typeof arguments[0] === 'string') {
notification['alert'] = arguments[0]
offset = 1
}
for (; offset < arguments.length; offset++) {
if (typeof arguments[offset] !== 'object') {
throw new JError.InvalidArgumentError('Invalid notification argument at index ' + offset)
}
notification = JUtil.extend(notification, arguments[offset])
}
this.payload = JUtil.extend(this.payload, {
'notification': notification
})
return this
}
function setMessage (msg_content, title, content_type, extras) {
if (msg_content == null || typeof msg_content !== 'string') {
throw new JError.InvalidArgumentError('message.msg_content is require and can only be set to the String')
}
var message = {
'msg_content': msg_content
}
if (title != null) {
if (typeof title !== 'string') {
throw new JError.InvalidArgumentError('Invalid message.title, it can only be set to the String')
}
message['title'] = title
}
if (content_type != null) {
if (typeof content_type !== 'string') {
throw new JError.InvalidArgumentError('Invalid message.content_type, it can only be set to the String')
}
message['content_type'] = content_type
}
if (extras != null) {
if (typeof extras !== 'object') {
throw new JError.InvalidArgumentError('Invalid message.extras')
}
message['extras'] = extras
}
this.payload = JUtil.extend(this.payload, {
'message': message
})
return this
}
// ##### 已弃用 ####
function setSmsMessage (content, delayTime) {
var smsMessage = {}
if (content != null) {
if (typeof content !== 'string') {
throw new JError.InvalidArgumentError('Invalid content, it can only be set to a string')
}
smsMessage['content'] = content
}
if (delayTime != null) {
if (typeof delayTime !== 'number') {
throw new JError.InvalidArgumentError('Invalid delayTime, it can only be set to a int')
}
smsMessage['delay_time'] = delayTime
}
this.payload = JUtil.extend(this.payload, {
'sms_message': smsMessage
})
return this
}
function setSms (delayTime, tempId, tempPara) {
var sms = {}
if (delayTime != null) {
if (typeof delayTime !== 'number') {
throw new JError.InvalidArgumentError('Invalid delayTime, it can only be set to a int')
}
sms['delay_time'] = delayTime
}
if (tempId != null) {
sms['temp_id'] = tempId
}
if (tempPara != null) {
sms['temp_para'] = tempPara
}
this.payload = JUtil.extend(this.payload, {
'sms_message': sms
})
return this
}
function generateSendno () {
return (MIN_SENDNO + Math.round(Math.random() * (MAX_SENDNO - MIN_SENDNO)))
}
function setOptions (sendno, time_to_live, override_msg_id, apns_production, big_push_duration, apns_collapse_id) {
if (sendno == null && time_to_live == null && override_msg_id == null && apns_production == null &&
big_push_duration == null) {
throw new JError.InvalidArgumentError("option's args cannot all be null.")
}
var options = {}
if (sendno != null) {
if (typeof sendno !== 'number') {
throw new JError.InvalidArgumentError('Invalid options.sendno, it can only be set to the Number')
}
options['sendno'] = sendno
} else {
options['sendno'] = generateSendno()
}
if (time_to_live != null) {
if (typeof time_to_live !== 'number') {
throw new JError.InvalidArgumentError('Invalid options.time_to_live, it can only be set to the Number')
}
options['time_to_live'] = time_to_live
}
if (override_msg_id != null) {
if (typeof override_msg_id !== 'number') {
throw new JError.InvalidArgumentError('Invalid options.override_msg_id, it can only be set to the Number')
}
options['override_msg_id'] = override_msg_id
}
// true: 推送生产环境;false: 推送开发环境。
if (apns_production != null) {
if (typeof apns_production !== 'boolean') {
throw new JError.InvalidArgumentError('Invalid options.apns_production, it can only be set to the Boolean')
}
options['apns_production'] = apns_production
} else {
options['apns_production'] = true // 如果不指定,默认推送生产环境。
}
if (big_push_duration != null) { // 又叫缓慢推送,设置后将在给定的 n 分钟内,匀速的向用户发送推送,最大值为 1400。
if (typeof big_push_duration !== 'number') {
throw new JError.InvalidArgumentError('Invalid options.big_push_duration, it can only be set to the Number')
}
if (big_push_duration > 1400 || big_push_duration <= 0) {
throw new JError.InvalidArgumentError('Invalid options.big_push_duration, it should bigger than 0 and less than 1400')
}
options['big_push_duration'] = big_push_duration
}
if (apns_collapse_id != null) {
options['apns_collapse_id'] = apns_collapse_id
}
this.payload = JUtil.extend(this.payload, {
'options': options
})
return this
}
function toJSON () {
this.payload.options = JUtil.extend({
'sendno': generateSendno(),
'apns_production': false
}, this.payload.options)
return JSON.stringify(this.payload)
}
function send (callback) {
validate(this.payload)
var body = this.toJSON()
return this.client.sendPush(body, callback)
}
function sendValidate (callback) {
validate(this.payload)
var body = this.toJSON()
return this.client.validate(body, callback)
}
// 定时任务 start
// date: 必须为 YYYY-MM-DD HH:MM:SS 格式,如:"2014-02-15 12:00:00"
function setSingleSchedule (date) {
if (typeof date !== 'string') {
throw new JError.InvalidArgumentError('date must be set to the string.')
}
var single = {
'time': date
}
this.trigger = JUtil.extend(this.trigger, {
'single': single
})
return this
}
// 具体参数格式参照:http://docs.jiguang.cn/server/rest_api_push_schedule/#_4
function setPeriodicalSchedule (start, end, time, timeUnit, frequency, point) {
var periodical = {
'start': start,
'end': end,
'time': time,
'time_unit': timeUnit,
'frequency': frequency,
'point': point
}
this.trigger = JUtil.extend(this.trigger, {
'periodical': periodical
})
return this
}
function setSchedule (name, enabled, callback) {
if (typeof name !== 'string') {
throw new JError.InvalidArgumentError('name must be set to string.')
}
if (typeof enabled !== 'boolean') {
throw new JError.InvalidArgumentError('enabled must be set to boolean.')
}
validate(this.payload)
this.payload.options = JUtil.extend({
'sendno': generateSendno(),
'apns_production': false
},
this.payload.options)
var body = {
'name': name,
'enabled': enabled,
'trigger': this.trigger,
'push': this.payload
}
return this.client.setSchedule(JSON.stringify(body), callback)
}
// scheduleId: 必填。
// name, enabled 如果为 null,则代表不更新。
function updateSchedule (scheduleId, name, enabled, callback) {
if (typeof scheduleId !== 'string') {
throw new JError.InvalidArgumentError('Schedule ID must be set to string.')
}
var body = {}
if (name != null) {
if (typeof name !== 'string') {
throw new JError.InvalidArgumentError('name must be set to string.')
}
body = JUtil.extend(body, {
'name': name
})
}
if (enabled != null) {
if (typeof enabled !== 'boolean') {
throw new JError.InvalidArgumentError('enabled must be set to boolean.')
}
body = JUtil.extend(body, {
'enabled': enabled
})
}
if (!JUtil.isEmptyObject(this.trigger)) {
body = JUtil.extend(body, {
'trigger': this.trigger
})
}
if (!JUtil.isEmptyObject(this.payload)) {
validate(this.payload)
this.payload.options = JUtil.extend({
'sendno': generateSendno(),
'apns_production': false
},
this.payload.options)
body = JUtil.extend(body, {
'push': this.payload
})
}
return this.client.updateSchedule(scheduleId, JSON.stringify(body), callback)
}
// 定时任务 end.
/**
* Verify the payload legitimacy, it will call by this.send()
* @param payload
*/
function validate (payload) {
var notification = payload.notification
var message = payload.message
if (!notification && !message) {
throw new JError.InvalidArgumentError('Either or both notification and message must be set.')
}
}
function calculateLength (str) {
var ch = []
var st = []
var re = []
for (var i = 0; i < str.length; i++) {
ch = str.charCodeAt(i)
st = []
do {
st.push(ch & 0xFF)
ch = ch >> 8
} while (ch)
re = re.concat(st.reverse())
}
// return an array of bytes.
return re.length
}
function isIosExceedLength () {
var ios
var notification = this.payload.notification
var message = this.payload.message
var alert = notification.alert ? notification.alert : ''
ios = calculateLength(JSON.stringify(JUtil.extend({
'alert': alert
}, notification.ios)))
if (message != null) {
var msgLen = calculateLength(JSON.stringify(message))
return msgLen >= 1000
}
return ios >= 2000
}
function isGlobalExceedLength () {
var android = 0
var winphone = 0
var ios = false
var notification = this.payload.notification
var message = this.payload.message
var platform = this.payload.platform
var hasIOS = true
if (platform !== ALL) {
hasIOS = false
for (var i = 0; i < platform.length; i++) {
if (platform[i] === 'ios') {
hasIOS = true
break
}
}
}
if (hasIOS) {
ios = this.isIosExceedLength()
}
if (notification != null) {
var alert = notification.alert ? notification.alert : ''
winphone = calculateLength(JSON.stringify(JUtil.extend({
'alert': alert
}, notification.winphone)))
android = calculateLength(JSON.stringify(JUtil.extend({
'alert': alert
}, notification.android)))
}
if (message != null) {
var msg_length = calculateLength(JSON.stringify(message))
winphone += msg_length
android += msg_length
}
return ios || winphone > 1000 || android > 1000
}
// ------ PushPayload prototype
PushPayload.prototype.setPlatform = setPlatform
PushPayload.prototype.setAudience = setAudience
PushPayload.prototype.setNotification = setNotification
PushPayload.prototype.setMessage = setMessage
PushPayload.prototype.setOptions = setOptions
PushPayload.prototype.toJSON = toJSON
PushPayload.prototype.send = send
PushPayload.prototype.sendValidate = sendValidate
PushPayload.prototype.setSingleSchedule = setSingleSchedule
PushPayload.prototype.setPeriodicalSchedule = setPeriodicalSchedule
PushPayload.prototype.setSchedule = setSchedule
PushPayload.prototype.updateSchedule = updateSchedule
PushPayload.prototype.isIosExceedLength = isIosExceedLength
PushPayload.prototype.isGlobalExceedLength = isGlobalExceedLength
PushPayload.prototype.setSmsMessage = setSmsMessage
// ------ private constant define ------
var VALID_DEVICE_TYPES = ['ios', 'android', 'winphone']
var MIN_SENDNO = 100000
var MAX_SENDNO = 4294967294
var ALL = 'all'
// ------ exports constants and methods -------
exports.ALL = ALL
exports.tag = tag
exports.tag_and = tag_and
exports.alias = alias
exports.registration_id = registration_id
exports.ios = ios
exports.android = android
exports.winphone = winphone
exports.setSchedule = setSchedule
// class
exports.PushPayload = PushPayload