Last active
February 12, 2016 05:08
-
-
Save h-mikisato/80083da7427d994c924a to your computer and use it in GitHub Desktop.
APNs Provider API in NodeJS
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
var fs = require('fs'); | |
var path = require('path'); | |
var http2 = require('http2'); | |
var uuid = require('node-uuid'); | |
var logger = require("log4js").getLogger(); | |
var argparse = require('argparse'); | |
/*! | |
* From Countly Team fork | |
* https://github.com/Countly/node-http2/tree/custom | |
*/ | |
http2.Agent.prototype.destroy = function(error) { | |
if (this._httpsAgent) { | |
this._httpsAgent.destroy(); | |
} | |
for (var key in this.endpoints) { | |
this.endpoints[key].close(error); | |
} | |
}; | |
/*! | |
End quotation | |
*/ | |
/* Parse Arguments */ | |
var parser = new argparse.ArgumentParser({ | |
version: '0.0.2', | |
addHelp:true, | |
description: 'HTTP/2 APNs Provider API Sender' | |
}); | |
parser.addArgument(['device_tokens'], { | |
nargs: '+', | |
help: "Device Tokens" | |
}); | |
parser.addArgument(['-m', '--message'], { | |
required: true, | |
help: "Push Message" | |
}); | |
parser.addArgument(['-c', '--cert'], { | |
required: true, | |
help: "Certification File Path" | |
}); | |
parser.addArgument(['-p', '--prod'], { | |
action: 'storeTrue', | |
help: "Send Production" | |
}); | |
var args = parser.parseArgs(); | |
/* Main Routine */ | |
var apn_cert = fs.readFileSync(args.cert); | |
var agent = new http2.Agent({ | |
key: apn_cert, | |
cert: apn_cert, | |
}); | |
var apn_host = args.prod ? "api.push.apple.com" : "api.development.push.apple.com"; | |
var tokens_num = args.device_tokens.length; | |
var recv_count = 0; | |
function buildPayload(message) { | |
return JSON.stringify({"apn": message}); | |
} | |
var push_map = {}; | |
var retry_counter = {}; | |
function deal_response(res) { | |
res.setEncoding('utf8'); | |
var response_uuid = res.headers["apns-id"]; | |
var device_token = push_map[response_uuid][0]; | |
var payload_str = push_map[response_uuid][1]; | |
delete push_map[response_uuid]; | |
if (res.statusCode == 200) { | |
logger.info("Notification is successfully sent: " + response_uuid + " " + device_token); | |
cleanup(response_uuid); | |
return; | |
} | |
var bufs = []; | |
res.on("error", function (err) { | |
logger.error("Response Error: " + err.message + " " + response_uuid); | |
}); | |
res.on('data', function(d) { | |
bufs.push(d); | |
}); | |
res.on('end', function() { | |
var res_json = JSON.parse(bufs.join("")); | |
logger.info("Error Code: " + res.statusCode + " Reason: " + res_json.reason + " " + response_uuid + " " + device_token); | |
if (res.statusCode == 410) { | |
logger.info("This device token must be inactive: " + device_token); | |
} else if (res.statusCode == 500) { | |
if (!retry_counter[response_uuid]) { | |
retry_counter[response_uuid] = 0; | |
} | |
if (++retry_counter[response_uuid] < retryMax) { | |
logger.error("Retry Sending...: " + response_uuid + " " + device_token); | |
setTimeout( | |
send(response_uuid, device_token, payload_str), | |
1000 * Math.pow(2, retry_counter[response_uuid] - 1) | |
); | |
return; | |
} | |
} | |
cleanup(response_uuid); | |
}); | |
} | |
function send(request_uuid, device_token, payload_str) { | |
push_map[request_uuid] = [device_token, payload_str]; | |
logger.info("Next Request: " + request_uuid + " " + device_token); | |
var options = { | |
'host': apn_host, | |
'method': 'POST', | |
'path': '/3/device/' + device_token, | |
'headers': { | |
'apns-id': request_uuid, | |
'content-type': "application/json", | |
} | |
}; | |
var req = agent.request(options, deal_response); | |
req.on("error", function (err) { | |
logger.error("Request Error: " + err.message + " " + request_uuid); | |
}); | |
req.write(payload_str); | |
req.end(); | |
} | |
function cleanup(apns_id) { | |
if (retry_counter[apns_id]) { | |
delete retry_counter[apns_id]; | |
} | |
if (++recv_count >= tokens_num) { | |
logger.info("Process Exit"); | |
agent.destroy(); | |
process.exit(); | |
} | |
} | |
for (var i = 0; i < tokens_num; i++) { | |
var request_uuid = uuid.v4(); | |
send(request_uuid, args.device_tokens[i], buildPayload(args.message)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment