Added ability to ensure that every push is delivered to Apple
If you send many push notifications (10k) and 10th will have invalid token, there is chance that 2k push notifications will be broken before broken pipe exception. This commit adds checking for every push message and fix bug with close event listener.
This commit is contained in:
Родитель
516aba71dd
Коммит
47519f5f5c
77
lib/apn.js
77
lib/apn.js
|
@ -31,6 +31,7 @@ var Connection = function (optionArgs) {
|
|||
, enhanced: true /* enable enhanced format */
|
||||
, errorCallback: undefined /* Callback when error occurs */
|
||||
, cacheLength: 5 /* Number of notifications to cache for error purposes */
|
||||
, writeTimeout: 10 /* Timeout to wait for empty buffer */
|
||||
};
|
||||
|
||||
if (optionArgs) {
|
||||
|
@ -50,15 +51,28 @@ var Connection = function (optionArgs) {
|
|||
callback = function() {
|
||||
if(!self.socket.authorized) {
|
||||
throw self.socket.authorizationError
|
||||
}
|
||||
while(offlineCache.length) {
|
||||
self.socket.write(offlineCache.shift());
|
||||
}
|
||||
|
||||
self.scheduleOfflineCacheChecking();
|
||||
});
|
||||
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.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 (!self.socket) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.socket.removeAllListeners();
|
||||
self.socket = undefined;
|
||||
});
|
||||
}
|
||||
|
||||
var connect = invoke_after(function() { startSocket(); });
|
||||
|
@ -79,6 +93,42 @@ var Connection = function (optionArgs) {
|
|||
hasKey = true;
|
||||
}));
|
||||
|
||||
this.writeNotificationToSocket = function(data) {
|
||||
if (self.socket === undefined || self.socket.readyState != 'open') {
|
||||
if ((self.socket === undefined || self.socket.readyState == 'closed') && readyToConnect()) {
|
||||
startSocket();
|
||||
}
|
||||
|
||||
offlineCache.push(data);
|
||||
} else {
|
||||
if (self.socket.socket.bufferSize > 0) {
|
||||
offlineCache.push(data);
|
||||
self.scheduleOfflineCacheChecking();
|
||||
} else {
|
||||
self.socket.write(data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.recheckOfflineCache = function() {
|
||||
console.log("RECHECK");
|
||||
if (offlineCache.length) {
|
||||
self.writeNotificationToSocket(offlineCache.pop());
|
||||
}
|
||||
|
||||
self.offlineCacheScheduler = undefined;
|
||||
|
||||
if (offlineCache.length) {
|
||||
self.scheduleOfflineCacheChecking();
|
||||
}
|
||||
};
|
||||
|
||||
this.scheduleOfflineCacheChecking = function() {
|
||||
if (!self.offlineCacheScheduler) {
|
||||
self.offlineCacheScheduler = setTimeout(self.recheckOfflineCache.bind(self), options.writeTimeout);
|
||||
}
|
||||
};
|
||||
|
||||
this.sendNotification = function (note) {
|
||||
var token = note.device.token;
|
||||
var message = JSON.stringify(note);
|
||||
|
@ -119,17 +169,8 @@ var Connection = function (optionArgs) {
|
|||
pos += token.copy(data, pos, 0);
|
||||
pos += int2buf(messageLength, data, pos, 2);
|
||||
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);
|
||||
}
|
||||
|
||||
this.writeNotificationToSocket(data);
|
||||
}
|
||||
|
||||
var tidyCachedNotes = function() {
|
||||
|
|
Загрузка…
Ссылка в новой задаче