Skip to content

Commit

Permalink
Merge pull request #248 from ToothlessGear/v1-no-send-no-retry
Browse files Browse the repository at this point in the history
V1 no send no retry
  • Loading branch information
hypesystem committed Jun 9, 2016
2 parents 2048582 + 7e55699 commit 7286a4b
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 302 deletions.
225 changes: 109 additions & 116 deletions lib/sender.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,15 @@ function Sender(key, options) {
return new Sender(key, options);
}

this.key = key;
this.options = options || {};
this.requestOptions = defaultsDeep({
method: 'POST',
headers: {
'Authorization': 'key=' + key
},
uri: Constants.GCM_SEND_URI
}, options, {
timeout: Constants.SOCKET_TIMEOUT
});
}

Sender.prototype.send = function(message, recipient, options, callback) {
Expand All @@ -23,42 +30,15 @@ Sender.prototype.send = function(message, recipient, options, callback) {
}
options = cleanOptions(options);

if(options.retries == 0) {
return this.sendNoRetry(message, recipient, callback);
}

var self = this;

this.sendNoRetry(message, recipient, function(err, response, attemptedRegTokens) {
if (err) {
if (typeof err === 'number' && err > 399 && err < 500) {
debug("Error 4xx -- no use retrying. Something is wrong with the request (probably authentication?)");
return callback(err);
}
return retry(self, message, recipient, options, callback);
getRequestBody(message, recipient, function(err, body) {
if(err) {
return callback(err);
}
if(!response.results) {
return callback(null, response);
if(options.retries == 0) {
return sendMessage(this.requestOptions, body, callback);
}
checkForBadTokens(response.results, attemptedRegTokens, function(err, unsentRegTokens, regTokenPositionMap) {
if(err) {
return callback(err);
}
if (unsentRegTokens.length == 0) {
return callback(null, response);
}

debug("Retrying " + unsentRegTokens.length + " unsent registration tokens");

retry(self, message, unsentRegTokens, options, function(err, retriedResponse) {
if(err) {
return callback(null, response);
}
response = updateResponse(response, retriedResponse, regTokenPositionMap, unsentRegTokens);
callback(null, response);
});
});
});
sendMessageWithRetries(this.requestOptions, body, options, callback);
}.bind(this));
};

function cleanOptions(options) {
Expand Down Expand Up @@ -86,13 +66,86 @@ function cleanOptions(options) {
return options;
}

function retry(self, message, recipient, options, callback) {
return setTimeout(function() {
self.send(message, recipient, {
retries: options.retries - 1,
backoff: options.backoff * 2
function getRequestBody(message, recipient, callback) {
var body = cleanParams(message);

if(typeof recipient == "string") {
body.to = recipient;
return nextTick(callback, null, body);
}
if(Array.isArray(recipient)) {
if(recipient.length < 1) {
return nextTick(callback, new Error('Empty recipient array passed!'));
}
body.registration_ids = recipient;
return nextTick(callback, null, body);
}
return nextTick(callback, new Error('Invalid recipient (' + recipient + ', type ' + typeof recipient + ') provided (must be array or string)!'));
}

function cleanParams(raw) {
var params = {};
Object.keys(raw).forEach(function(param) {
var paramOptions = messageOptions[param];
if(!paramOptions) {
return console.warn("node-gcm ignored unknown message parameter " + param);
}
if(paramOptions.__argType != typeof raw[param]) {
return console.warn("node-gcm ignored wrongly typed message parameter " + param + " (was " + typeof raw[param] + ", expected " + paramOptions.__argType + ")");
}
params[param] = raw[param];
});
return params;
}

function nextTick(func) {
var args = Array.prototype.slice.call(arguments, 1);
process.nextTick(function() {
func.apply(this, args);
}.bind(this));
}

function sendMessageWithRetries(requestOptions, body, messageOptions, callback) {
sendMessage(requestOptions, body, function(err, response, attemptedRegTokens) {
if (err) {
if (typeof err === 'number' && err > 399 && err < 500) {
debug("Error 4xx -- no use retrying. Something is wrong with the request (probably authentication?)");
return callback(err);
}
return retry(requestOptions, body, messageOptions, callback);
}
checkForBadTokens(response.results, attemptedRegTokens, function(err, unsentRegTokens, regTokenPositionMap) {
if(err) {
return callback(err);
}
if (unsentRegTokens.length == 0) {
return callback(null, response);
}

debug("Retrying " + unsentRegTokens.length + " unsent registration tokens");

body.registration_ids = unsentRegTokens;
retry(requestOptions, body, messageOptions, function(err, retriedResponse) {
if(err) {
return callback(null, response);
}
response = updateResponse(response, retriedResponse, regTokenPositionMap, unsentRegTokens);
callback(null, response);
});
});
});
}

function retry(requestOptions, body, messageOptions, callback) {
setTimeout(function() {
if(messageOptions.retries <= 1) {
return sendMessage(requestOptions, body, callback);
}
sendMessageWithRetries(requestOptions, body, {
retries: messageOptions.retries - 1,
backoff: messageOptions.backoff * 2
}, callback);
}, options.backoff);
}, messageOptions.backoff);
}

function checkForBadTokens(results, originalRecipients, callback) {
Expand Down Expand Up @@ -125,86 +178,26 @@ function updateResponseMetaData(response, retriedResponse, unsentRegTokens) {
response.failure -= unsentRegTokens.length - retriedResponse.failure;
}

Sender.prototype.sendNoRetry = function(message, recipient, callback) {
if(!callback) {
callback = function() {};
}

getRequestBody(message, recipient, function(err, body) {
if(err) {
function sendMessage(requestOptions, body, callback) {
requestOptions.json = body;
request(requestOptions, function (err, res, resBodyJSON) {
if (err) {
return callback(err);
}

//Build request options, allowing some to be overridden
var request_options = defaultsDeep({
method: 'POST',
headers: {
'Authorization': 'key=' + this.key
},
uri: Constants.GCM_SEND_URI,
json: body
}, this.options, {
timeout: Constants.SOCKET_TIMEOUT
});

request(request_options, function (err, res, resBodyJSON) {
if (err) {
return callback(err);
}
if (res.statusCode >= 500) {
debug('GCM service is unavailable (500)');
return callback(res.statusCode);
}
if (res.statusCode === 401) {
debug('Unauthorized (401). Check that your API token is correct.');
return callback(res.statusCode);
}
if (res.statusCode !== 200) {
debug('Invalid request (' + res.statusCode + '): ' + resBodyJSON);
return callback(res.statusCode);
}
callback(null, resBodyJSON, body.registration_ids || [ body.to ]);
});
}.bind(this));
};

function getRequestBody(message, recipient, callback) {
var body = cleanParams(message);

if(typeof recipient == "string") {
body.to = recipient;
return nextTick(callback, null, body);
}
if(Array.isArray(recipient)) {
if(recipient.length < 1) {
return nextTick(callback, new Error('Empty recipient array passed!'));
if (res.statusCode >= 500) {
debug('GCM service is unavailable (500)');
return callback(res.statusCode);
}
body.registration_ids = recipient;
return nextTick(callback, null, body);
}
return nextTick(callback, new Error('Invalid recipient (' + recipient + ', type ' + typeof recipient + ') provided (must be array or string)!'));
}

function cleanParams(raw) {
var params = {};
Object.keys(raw).forEach(function(param) {
var paramOptions = messageOptions[param];
if(!paramOptions) {
return console.warn("node-gcm ignored unknown message parameter " + param);
if (res.statusCode === 401) {
debug('Unauthorized (401). Check that your API token is correct.');
return callback(res.statusCode);
}
if(paramOptions.__argType != typeof raw[param]) {
return console.warn("node-gcm ignored wrongly typed message parameter " + param + " (was " + typeof raw[param] + ", expected " + paramOptions.__argType + ")");
if (res.statusCode !== 200) {
debug('Invalid request (' + res.statusCode + '): ' + resBodyJSON);
return callback(res.statusCode);
}
params[param] = raw[param];
callback(null, resBodyJSON, body.registration_ids || [ body.to ]);
});
return params;
}

function nextTick(func) {
var args = Array.prototype.slice.call(arguments, 1);
process.nextTick(function() {
func.apply(this, args);
}.bind(this));
}

module.exports = Sender;
Loading

0 comments on commit 7286a4b

Please sign in to comment.