Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ios push notification, correction to readme.md #5

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@ Supported now:
* [Mandrill](https://github.com/jimrubenstein/node-mandrill)
* [Twillio](https://github.com/twilio/twilio-node)
* [Android push notification](https://github.com/ToothlessGear/node-gcm)
* [iOS push notification](https://github.com/argon/node-apn)

Will be added soon:
* [Mailgun](https://github.com/jimrubenstein/node-mandrill)
* [iOS push notification](https://github.com/argon/node-apn)

If you want to extend transport support:

Expand Down Expand Up @@ -146,7 +146,7 @@ notifier
.execute('created-action', function () { /* ... */ });

// start the server
notifier.listen(process.env.PORT);
notifier.start(process.env.PORT);
```

Update `development.config.js` and `production.config.js` configuration. For now, configuration requires connection string to MongoDB, accessToken (shared secret) to access service, mandrill and logentries tokens.
Expand All @@ -167,7 +167,7 @@ $ curl http://notifier.likeastore.com/
Send first notification,

```bash
$ echo '{"event": "incoming-event"}' | curl -d @- http://notifier.likeastore.com/api/events?access_token=ACCESS_TOKEN
$ echo '{"event": "incoming-event"}' | curl -H "Content-Type:application/json" -d @- http://notifier.likeastore.com/api/events?access_token=ACCESS_TOKEN
```

## Getting started
Expand Down
4 changes: 4 additions & 0 deletions config/development.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ var config = {
},
gcm : {
serverApiKey: 'fake-google-server-api-key'
},
apn : {
cert: 'fake-cert-path',
key: 'fake-key-path'
}
},

Expand Down
4 changes: 4 additions & 0 deletions config/production.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ var config = {
},
gcm : {
serverApiKey: process.env.GOOGLE_SERVER_API_KEY
},
apn : {
cert: process.env.APPLE_CERT,
key: process.env.APPLE_KEY
}
},

Expand Down
4 changes: 4 additions & 0 deletions config/staging.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ var config = {
},
gcm : {
serverApiKey: process.env.GOOGLE_SERVER_API_KEY
},
apn : {
cert: process.env.APPLE_CERT,
key: process.env.APPLE_KEY
}
},

Expand Down
4 changes: 4 additions & 0 deletions config/test.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ var config = {
},
gcm : {
serverApiKey: 'fake-google-server-api-key'
},
apn : {
cert: 'fake-cert-path',
key: 'fake-key-path'
}
},

Expand Down
40 changes: 32 additions & 8 deletions example/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,40 @@ notifier
});
})
.execute('send-android-push-notification', function (a, transport, callback) {
var registrationIds = [];
registrationIds.push(a.data.deviceId);
var tokens = [];
tokens.push(a.data.token);

var message = transport.android.message;
message.addDataWithObject({
key1: 'message1',
key2: 'message2'
transport.android.push({
message: {key1: 'value1', key2: 'value2'},
tokens: tokens,
retries: 3
}, callback);
});

notifier
.receive('user-completed-action', function (e, actions, callback) {
actions.create('send-ios-push-notification', {user: e.user}, callback);
})
.resolve('send-ios-push-notification', function (a, actions, callback) {
asyncRequestForUser(actions.user, function (err, user) {
if (err) {
return callback(err);
}

actions.resolved(a, {deviceId: user.deviceId}, callback);
});
})
.execute('send-ios-push-notification', function (a, transport, callback) {
var tokens = [];
tokens.push(a.data.token);

transport.android.push.send(message, registrationIds, 4, callback);
transport.ios.push({
production: false, // use specific gateway based on 'production' property.
passphrase: 'secretPhrase',
alert: { "body" : "Your turn!", "action-loc-key" : "Play" , "launch-image" : "mysplash.png"},
badge: 1,
tokens: tokens
}, callback);
});

notifier.start(process.env.NODE_PORT || 3031);
Expand All @@ -87,7 +111,7 @@ function asyncRequestForUser(userId, callback) {
email: 'example@likeastore.com',
name: 'alexander.beletsky',
phone: '+3805554455',
deviceId: 'regId123'
token: 'regId123'
};

process.nextTick(function () {
Expand Down
123 changes: 118 additions & 5 deletions source/transport.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
var mandrill = require('node-mandrill');
var twilio = require('twilio');
var gcm = require('node-gcm');
var apn = require('apn');
var logger = require('./utils/logger');
var config = require('../config');

var setupMandrill = function () {
if (!validConfig()) {
throw new Error('missing mandrill token, please update config.transport.mandrill section');
var errorMsg = 'missing mandrill token, please update config.transport.mandrill section';
logger.error(errorMsg);
throw new Error(errorMsg);
}

return mandrill(config.transport.mandrill.token);
Expand All @@ -17,7 +21,9 @@ var setupMandrill = function () {

var setupTwillio = function () {
if (!validConfig()) {
throw new Error('missing twilio account SID or auth Token, please update config.transport.twilio section');
var errorMsg = 'missing twilio account SID or auth Token, please update config.transport.twilio section';
logger.error(errorMsg);
throw new Error(errorMsg);
}

return twilio(config.transport.twilio.accountSid, config.transport.twilio.authToken);
Expand All @@ -33,19 +39,126 @@ var setupAndroidPushNotification = function () {
}

return {
push: new gcm.Sender(config.transport.gcm.serverApiKey),
message: new gcm.Message()
push: push
};

function push(options, callback) {
if(!validOptions()) {
var errorMsg = "missing 'options' or required required fields, please make sure you have provided 'options'";
logger.error(errorMsg);
throw new Error(errorMsg);
}

var service = new gcm.Sender(config.transport.gcm.serverApiKey);
var message = new gcm.Message();

message.addDataWithObject(options.message);
service.send(message, options.tokens, options.retries, callback);

function validOptions() {
return options.message && options.tokens && options.retries;
}
}

function validConfig() {
return config.transport.gcm && config.transport.gcm.serverApiKey;
}
};

var setupIOSPushNotification = function () {

if(!validConfig()) {
var errorMsg = "missing 'cert.pem' or 'key.pem', please update 'config.transport.apn section'";
logger.error(errorMsg);
throw new Error(errorMsg);
}

return {
push: push
};

function validConfig() {
return config.transport.apn && (config.transport.apn.cert && config.transport.apn.key);
}

function push(options, callback) {
var service, note;
var productionGateway = 'gateway.push.apple.com',
developmentGateway = 'gateway.sandbox.push.apple.com';

if(!validOptions()) {
var errorMsg = "missing 'options' or required , please make sure you have provided";
logger.error(errorMsg);
throw new Error(errorMsg);
}

initConnection();
initNotification();

service.pushNotification(note, options.tokens);

function validOptions() {
return options && options.alert && options.production && (options.tokens && options.tokens.length > 0);
}

function initConnection() {
service = new apn.connection({
production: options.production,
gateway: options.production ? productionGateway : developmentGateway,
port: options.port || 2195,
enhanced: options.enhanced || true,
cacheLength: options.cacheLength || 100,
// errorCallback: callback,
cert: config.transport.apn.cert,
key: config.transport.apn.key,
passphrase: options.passphrase
});

service.on('connected', function() {
logger.info('APN Connected.');
});

service.on('transmitted', function(notification, device) {
return callback(null, "Notification transmitted to:" + device.token.toString('hex'));
});

service.on('transmissionError', function(errCode, notification, device) {
if(errCode === 8) {
var errorMsg = 'A error code of 8 indicates that the device token is invalid. This could be for a number of reasons - are you using the correct environment? i.e. Production vs. Sandbox';
logger.error(errorMsg);
return callback(errorMsg);
}

return callback('Notification caused error: ' + errCode + ' for device ', device, notification);
});

service.on('timeout', function() {
var errorMsg = 'APNS connection timeout';
logger.warning(errorMsg);
return callback(errorMsg);
});

service.on('socketError', function() {
var errorMsg = 'APNS socket error';
logger.error(errorMsg);
});
}

function initNotification() {
note = new apn.notification();
note.sound = options.sound || 'notification-beep.wav';
note.alert = options.alert || { "body" : "Your turn!", "action-loc-key" : "Play" , "launch-image" : "mysplash.png"};
note.payload = options.payload || {'messageFrom': 'Notifier'};
note.badge = options.badge;
}
}
};

var transport = {
mandrill: setupMandrill(),
twillio: setupTwillio(),
android: setupAndroidPushNotification()
android: setupAndroidPushNotification(),
ios: setupIOSPushNotification()
};

module.exports = transport;