Comparing version 1.1.2 to 1.1.3
138
lib/apn.js
@@ -19,4 +19,4 @@ var tls = require('tls'); | ||
var Connection = function (optionArgs) { | ||
this.currentId = 0; | ||
this.cachedNotes = []; | ||
var currentId = 0; | ||
var cachedNotes = []; | ||
@@ -26,3 +26,4 @@ var self = this; | ||
var socketOptions = {}; | ||
var offlineCache = []; | ||
var openingSocket = false; | ||
var writeBuffer = []; | ||
@@ -49,17 +50,47 @@ var options = { cert: 'cert.pem' /* Certificate file */ | ||
} | ||
var startSocket = function () { | ||
self.socket = tls.connect(options['port'], options['gateway'], socketOptions, | ||
callback = function() { | ||
if(!self.socket.authorized) { | ||
throw self.socket.authorizationError | ||
} | ||
while(offlineCache.length) { | ||
self.socket.write(offlineCache.shift()); | ||
} | ||
var onDrain = function() { | ||
if (writeBuffer.length) { | ||
writeNotificationToSocket(writeBuffer.shift()); | ||
} | ||
}; | ||
var startSocket = function () { | ||
if(!self.openingSocket) { | ||
process.nextTick(function() { | ||
self.socket = tls.connect(options['port'], options['gateway'], socketOptions, | ||
callback = function() { | ||
if(!self.socket.authorized) { | ||
throw self.socket.authorizationError | ||
} | ||
onDrain(); | ||
self.openingSocket=false; | ||
}); | ||
self.socket.on('data', function(data) { | ||
handleTransmissionError(data); | ||
}); | ||
self.socket.on('error', function(data) { | ||
self.socket.removeAllListeners(); | ||
self.socket = undefined; | ||
}); | ||
self.socket.once('close', function () { | ||
if(writeBuffer.length && readyToConnect()) { | ||
startSocket(); | ||
} | ||
if (!self.socket) { | ||
return; | ||
} | ||
self.socket.removeAllListeners(); | ||
self.socket = undefined; | ||
}); | ||
self.socket.on("drain", onDrain); | ||
}); | ||
self.socket.on('data', function(data) { handleTransmissionError(data); }); | ||
self.socket.on('error', function(data) {self.socket.removeAllListeners(); self.socket = undefined; }); | ||
self.socket.once('end', function () { }); | ||
self.socket.once('close', function () { self.socket.removeAllListeners(); self.socket = undefined; }); | ||
self.openingSocket = true; | ||
} | ||
} | ||
@@ -85,2 +116,21 @@ | ||
var writeNotificationToSocket = function(data) { | ||
if (self.socket === undefined || self.socket.readyState != 'open') { | ||
if ((self.socket === undefined || self.socket.readyState == 'closed') && readyToConnect()) { | ||
startSocket(); | ||
} | ||
bufferDataForWrite(data); | ||
} else { | ||
if (self.socket.socket.bufferSize > 0) { | ||
bufferDataForWrite(data); | ||
} else { | ||
self.socket.write(data); | ||
} | ||
} | ||
}; | ||
var bufferDataForWrite = function(data) { | ||
writeBuffer.push(data); | ||
} | ||
this.sendNotification = function (note) { | ||
@@ -99,4 +149,3 @@ var token = note.device.token; | ||
note._uid = this.currentId++; | ||
note._uid = currentId++; | ||
if(options.enhanced) { | ||
@@ -114,3 +163,3 @@ var data = new Buffer(1 + 4 + 4 + 2 + token.length + 2 + messageLength); | ||
self.cachedNotes.push(note); | ||
cachedNotes.push(note); | ||
tidyCachedNotes(); | ||
@@ -128,13 +177,4 @@ } | ||
pos += data.write(message, pos); | ||
// If error occurs then slice array and resend all stored notes. | ||
if(self.socket === undefined || self.socket.readyState != 'open') { | ||
if((self.socket === undefined || self.socket.readyState == 'closed') && readyToConnect()) { | ||
startSocket(); | ||
} | ||
offlineCache.push(data); | ||
} | ||
else { | ||
self.socket.write(data); | ||
} | ||
writeNotificationToSocket(data); | ||
} | ||
@@ -144,4 +184,4 @@ | ||
// Maybe a timestamp should be stored for each note and kept for a duration? | ||
if(self.cachedNotes.length > options.cacheLength) { | ||
self.cachedNotes.shift(); | ||
if(cachedNotes.length > options.cacheLength) { | ||
cachedNotes.shift(); | ||
} | ||
@@ -152,8 +192,14 @@ } | ||
// Need to check message that errors | ||
// return failed notification to owner | ||
// resend all following notifications | ||
if(data[0] == 8) { | ||
var currentCache = self.cachedNotes; | ||
self.cachedNotes = []; | ||
// return failed notification to owner | ||
// purge writeBuffer and start again with cachedNotes | ||
// perhaps we should keep an identifier with each writeBuffer | ||
// entry to know where to stop when cycling through cachedNotes | ||
if (data[0] == 8) { | ||
self.socket.end(); | ||
if (!options.enhanced) { | ||
cachedNotes = []; | ||
return; | ||
} | ||
// This is an error condition | ||
@@ -163,4 +209,5 @@ var errorCode = data[1]; | ||
var note = undefined; | ||
while(currentCache.length) { | ||
note = currentCache.shift(); | ||
while(cachedNotes.length) { | ||
note = cachedNotes.shift(); | ||
if(note['_uid'] == identifier) { | ||
@@ -170,2 +217,3 @@ break; | ||
} | ||
// Notify callback of failed notification | ||
@@ -175,7 +223,7 @@ if(typeof options.errorCallback == 'function') { | ||
} | ||
while(currentCache.length) { | ||
note = currentCache.shift(); | ||
process.nextTick(function() { | ||
writeBuffer = []; | ||
var count = cachedNotes.length; | ||
for(var i=0; i<count; i++) { | ||
note = cachedNotes.shift(); | ||
self.sendNotification(note); | ||
}); | ||
} | ||
@@ -295,3 +343,3 @@ } | ||
self.socket.on('data', function(data) { processData(data); }); | ||
self.socket.on('error', function(data) {self.socket.removeAllListeners(); self.socket = undefined; }); | ||
self.socket.once('error', function(data) {self.socket.removeAllListeners(); self.socket = undefined; }); | ||
self.socket.once('end', function () { }); | ||
@@ -298,0 +346,0 @@ self.socket.once('close', function () { self.socket.removeAllListeners(); self.socket = undefined; }); |
{ | ||
"name": "apn", | ||
"description": "An interface to the Apple Push Notification service for Node.js", | ||
"version": "1.1.2", | ||
"version": "1.1.3", | ||
"author": "Andrew Naylor <argon@mkbot.net>", | ||
@@ -6,0 +6,0 @@ "contributors": [ |
@@ -102,2 +102,4 @@ #node-apn | ||
Contributors: [Ian Babrou][bobrik], [dgthistle][dgthistle] | ||
Special thanks to [Ben Noordhuis][bnoordhuis] for `invoke_after` code. | ||
@@ -127,5 +129,11 @@ | ||
[npm]: http://github.com/isaacs/npm | ||
[bobrik]: http://bobrik.name | ||
[dgthistle]: https://github.com/dgthistle | ||
## Changelog | ||
1.1.3: | ||
* Fixes #11,#12,#13,#14: Ensure delivery of notifications to Apple even under heavy load. | ||
1.1.2: | ||
@@ -132,0 +140,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Non-existent author
Supply chain riskThe package was published by an npm account that no longer exists.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
20044
382
172
0
7