Upgrade APNS to use HTTP/2

- uses universal certificate
- removes tests logs
- standardized returned promises from APNS and GCM to something usable in _PushStatus
This commit is contained in:
Florent Vilmart
2016-03-13 18:15:15 -04:00
parent a392c088d8
commit dad50d12f5
13 changed files with 316 additions and 463 deletions

View File

@@ -21,9 +21,30 @@ function GCM(args) {
* @param {Array} devices A array of devices
* @returns {Object} A promise which is resolved after we get results from gcm
*/
GCM.prototype.send = function(data, devices, callback) {
let pushId = cryptoUtils.newObjectId();
let timeStamp = Date.now();
GCM.prototype.send = function(data, devices) {
// Make a new array
devices = new Array(...devices);
let timestamp = Date.now();
// For android, we can only have 1000 recepients per send, so we need to slice devices to
// chunk if necessary
let slices = sliceDevices(devices, GCMRegistrationTokensMax);
if (slices.length > 1) {
// Make 1 send per slice
let promises = slices.reduce((memo, slice) => {
let promise = this.send(data, slice, timestamp);
memo.push(promise);
return memo;
}, [])
return Parse.Promise.when(promises).then((results) => {
let allResults = results.reduce((memo, result) => {
return memo.concat(result);
}, []);
return Parse.Promise.as(allResults);
});
}
// get the devices back...
devices = slices[0];
let expirationTime;
// We handle the expiration_time convertion in push.js, so expiration_time is a valid date
// in Unix epoch time in milliseconds here
@@ -31,38 +52,51 @@ GCM.prototype.send = function(data, devices, callback) {
expirationTime = data['expiration_time'];
}
// Generate gcm payload
let gcmPayload = generateGCMPayload(data.data, pushId, timeStamp, expirationTime);
let gcmPayload = generateGCMPayload(data.data, timestamp, expirationTime);
// Make and send gcm request
let message = new gcm.Message(gcmPayload);
let sendPromises = [];
// For android, we can only have 1000 recepients per send, so we need to slice devices to
// chunk if necessary
let chunkDevices = sliceDevices(devices, GCMRegistrationTokensMax);
for (let chunkDevice of chunkDevices) {
let sendPromise = new Parse.Promise();
let registrationTokens = []
for (let device of chunkDevice) {
registrationTokens.push(device.deviceToken);
}
this.sender.send(message, { registrationTokens: registrationTokens }, 5, (error, response) => {
// TODO: Use the response from gcm to generate and save push report
// TODO: If gcm returns some deviceTokens are invalid, set tombstone for the installation
console.log('GCM request and response %j', {
request: message,
response: response
});
sendPromise.resolve({
error: error,
response: response,
payload: message,
deviceType: 'android'
});
});
sendPromises.push(sendPromise);
}
// Build a device map
let devicesMap = devices.reduce((memo, device) => {
memo[device.deviceToken] = device;
return memo;
}, {});
return Parse.Promise.when(sendPromises);
let deviceTokens = Object.keys(devicesMap);
let promises = deviceTokens.map(() => new Parse.Promise());
let registrationTokens = deviceTokens;
this.sender.send(message, { registrationTokens: registrationTokens }, 5, (error, response) => {
// example response:
/*
{ "multicast_id":7680139367771848000,
"success":0,
"failure":4,
"canonical_ids":0,
"results":[ {"error":"InvalidRegistration"},
{"error":"InvalidRegistration"},
{"error":"InvalidRegistration"},
{"error":"InvalidRegistration"}] }
*/
let { results, multicast_id } = response || {};
registrationTokens.forEach((token, index) => {
let promise = promises[index];
let result = results ? results[index] : undefined;
let device = devicesMap[token];
let resolution = {
device,
multicast_id,
response: error || result,
};
if (!result || result.error) {
resolution.transmitted = false;
} else {
resolution.transmitted = true;
}
promise.resolve(resolution);
});
});
return Parse.Promise.when(promises);
}
/**
@@ -73,10 +107,9 @@ GCM.prototype.send = function(data, devices, callback) {
* @param {Number|undefined} expirationTime A number whose format is the Unix Epoch or undefined
* @returns {Object} A promise which is resolved after we get results from gcm
*/
function generateGCMPayload(coreData, pushId, timeStamp, expirationTime) {
function generateGCMPayload(coreData, timeStamp, expirationTime) {
let payloadData = {
'time': new Date(timeStamp).toISOString(),
'push_id': pushId,
'data': JSON.stringify(coreData)
}
let payload = {