-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
123ac5f
commit 681809f
Showing
8 changed files
with
448 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
// ParsePushAdapter is the default implementation of | ||
// PushAdapter, it uses GCM for android push and APNS | ||
// for ios push. | ||
var Parse = require('parse/node').Parse, | ||
GCM = require('./GCM'), | ||
APNS = require('./APNS'); | ||
|
||
function ParsePushAdapter() { | ||
this.validPushTypes = ['ios', 'android']; | ||
this.senders = {}; | ||
} | ||
|
||
ParsePushAdapter.prototype.registerPushSenders = function(pushConfig) { | ||
// Initialize senders | ||
for (var i = 0; i < this.validPushTypes.length; i++) { | ||
this.senders[this.validPushTypes[i]] = []; | ||
} | ||
|
||
pushConfig = pushConfig || {}; | ||
var pushTypes = Object.keys(pushConfig); | ||
for (var i = 0; i < pushTypes.length; i++) { | ||
var pushType = pushTypes[i]; | ||
if (this.validPushTypes.indexOf(pushType) < 0) { | ||
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED, | ||
'Push to ' + pushTypes + ' is not supported'); | ||
} | ||
|
||
var typePushConfig = pushConfig[pushType]; | ||
var senderArgs = []; | ||
// Since for ios, there maybe multiple cert/key pairs, | ||
// typePushConfig can be an array. | ||
if (Array.isArray(typePushConfig)) { | ||
senderArgs = senderArgs.concat(typePushConfig); | ||
} else if (typeof typePushConfig === 'object') { | ||
senderArgs.push(typePushConfig); | ||
} else { | ||
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED, | ||
'Push Configuration is invalid'); | ||
} | ||
for (var j = 0; j < senderArgs.length; j++) { | ||
var senderArg = senderArgs[j]; | ||
var sender; | ||
switch (pushType) { | ||
case 'ios': | ||
sender = new APNS(senderArg); | ||
break; | ||
case 'android': | ||
sender = new GCM(senderArg); | ||
break; | ||
} | ||
this.senders[pushType].push(sender); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Get an array of push senders based on the push type. | ||
* @param {String} The push type | ||
* @returns {Array|Undefined} An array of push senders | ||
*/ | ||
ParsePushAdapter.prototype.getPushSenders = function(pushType) { | ||
if (!this.senders[pushType]) { | ||
console.log('No push sender for push type %s', pushType); | ||
return []; | ||
} | ||
return this.senders[pushType]; | ||
} | ||
|
||
/** | ||
* Get an array of valid push types. | ||
* @returns {Array} An array of valid push types | ||
*/ | ||
ParsePushAdapter.prototype.getValidPushTypes = function() { | ||
return this.validPushTypes; | ||
} | ||
|
||
ParsePushAdapter.prototype.send = function(data, installations) { | ||
var deviceTokenMap = classifyDeviceTokens(installations, this.validPushTypes); | ||
var sendPromises = []; | ||
for (var pushType in deviceTokenMap) { | ||
var senders = this.getPushSenders(pushType); | ||
// Since ios have dev/prod cert, a push type may have multiple senders | ||
for (var i = 0; i < senders.length; i++) { | ||
var sender = senders[i]; | ||
var deviceTokens = deviceTokenMap[pushType]; | ||
if (!sender || deviceTokens.length == 0) { | ||
continue; | ||
} | ||
// For android, we can only have 1000 recepients per send | ||
var chunkDeviceTokens = sliceDeviceTokens(pushType, deviceTokens, GCM.GCMRegistrationTokensMax); | ||
for (var j = 0; j < chunkDeviceTokens.length; j++) { | ||
sendPromises.push(sender.send(data, chunkDeviceTokens[j])); | ||
} | ||
} | ||
} | ||
return Parse.Promise.when(sendPromises); | ||
} | ||
|
||
/** | ||
* Classify the device token of installations based on its device type. | ||
* @param {Object} installations An array of installations | ||
* @param {Array} validPushTypes An array of valid push types(string) | ||
* @returns {Object} A map whose key is device type and value is an array of device tokens | ||
*/ | ||
function classifyDeviceTokens(installations, validPushTypes) { | ||
// Init deviceTokenMap, create a empty array for each valid pushType | ||
var deviceTokenMap = {}; | ||
for (var i = 0; i < validPushTypes.length; i++) { | ||
deviceTokenMap[validPushTypes[i]] = []; | ||
} | ||
for (var i = 0; i < installations.length; i++) { | ||
var installation = installations[i]; | ||
// No deviceToken, ignore | ||
if (!installation.deviceToken) { | ||
continue; | ||
} | ||
var pushType = installation.deviceType; | ||
if (deviceTokenMap[pushType]) { | ||
deviceTokenMap[pushType].push(installation.deviceToken); | ||
} else { | ||
console.log('Unknown push type from installation %j', installation); | ||
} | ||
} | ||
return deviceTokenMap; | ||
} | ||
|
||
/** | ||
* Slice a list of device tokens to several list of device tokens with fixed chunk size. | ||
* @param {String} pushType The push type of the given device tokens | ||
* @param {Array} deviceTokens An array of device tokens(string) | ||
* @param {Number} chunkSize The size of the a chunk | ||
* @returns {Array} An array which contaisn several arries of device tokens with fixed chunk size | ||
*/ | ||
function sliceDeviceTokens(pushType, deviceTokens, chunkSize) { | ||
if (pushType !== 'android') { | ||
return [deviceTokens]; | ||
} | ||
var chunkDeviceTokens = []; | ||
while (deviceTokens.length > 0) { | ||
chunkDeviceTokens.push(deviceTokens.splice(0, chunkSize)); | ||
} | ||
return chunkDeviceTokens; | ||
} | ||
|
||
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') { | ||
ParsePushAdapter.classifyDeviceTokens = classifyDeviceTokens; | ||
ParsePushAdapter.sliceDeviceTokens = sliceDeviceTokens; | ||
} | ||
module.exports = ParsePushAdapter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Push Adapter | ||
// | ||
// Allows you to change the push notification mechanism. | ||
// | ||
// Adapter classes must implement the following functions: | ||
// * registerPushSenders(parseConfig) | ||
// * getPushSenders(parseConfig) | ||
// * getValidPushTypes(parseConfig) | ||
// * send(data, installations) | ||
// | ||
// Default is ParsePushAdapter, which uses GCM for | ||
// android push and APNS for ios push. | ||
|
||
var ParsePushAdapter = require('./ParsePushAdapter'); | ||
|
||
var adapter = new ParsePushAdapter(); | ||
|
||
function setAdapter(pushAdapter) { | ||
adapter = pushAdapter; | ||
} | ||
|
||
function getAdapter() { | ||
return adapter; | ||
} | ||
|
||
module.exports = { | ||
getAdapter: getAdapter, | ||
setAdapter: setAdapter | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.