Receive GCM push notification in node.js app - node.js

I'm building a command-line application in node.js and would like to receive GCM push notifications (the command-line app will be interacting with the same set of services that iOS/Android apps use, hence wanted to use the same notification service).
Given that GCM can be used on iOS (and thus is not Android-specific) I am hoping it can be used from node.js as well.
I've seen many articles about sending push notifications from node.js, but haven't been able to find anything about using node.js on the receiving end.

i think if you have to send push notification ,to ios and andriod then fcm is better then gcm use this
router.post('/pushmessage', function (req, res) {
var serverKey = '';//put server key here
var fcm = new FCM(serverKey);
var token = "";// put token here which user you have to send push notification
var message = {
to: token,
collapse_key: 'your_collapse_key',
notification: {title: 'hello', body: 'test'},
data: {my_key: 'my value', contents: "abcv/"}
};
fcm.send(message, function (err, response) {
if (err) {
res.json({status: 0, message: err});
} else {
res.json({status: 1, message: response});
}
});
});

I believe you can using service workers.
Push is based on service workers because service workers operate in the background. This means the only time code is run for a push notification (in other words, the only time the battery is used) is when the user interacts with a notification by clicking it or closing it. If you're not familiar with them, check out the service worker introduction. We will use service worker code in later sections when we show you how to implement pushes and notifications.
So basically there is a background service that waits for push and thats what you are going to build.
Two technologies
Push and notification use different, but complementary, APIs: push is invoked when a server supplies information to a service worker; a notification is the action of a service worker or web page script showing information to a user.
self.addEventListener('push', function(event) {
const promiseChain = getData(event.data)
.then(data => {
return self.registration.getNotifications({tag: data.tag});
})
.then(notifications => {
//Do something with the notifications.
});
event.waitUntil(promiseChain);
});
https://developers.google.com/web/fundamentals/engage-and-retain/push-notifications/handling-messages

I don't think it possible (in a simple way)...
Android/iOS has an OS behind with a service that communicates with GCM...
If you are trying to run a CLI tool, you'll need to implement a service on top of the OS (Linux, Windows Mac) so it can receive notifications.

GCM sends the notifications against the device tokens which are generated from iOS/Android devices when they are registered with push notification servers. If you are thinking of receiving the notifications without devices tokens it is fundamentally incorrect.

It's not mandatory to depend only on GCM, today there are many packages are available for sending pushNotification.
Two node packages are listed below.
fcm-call - you can find documentation from https://www.npmjs.com/package/fcm-call
fcm-node
fcm-call is used - you can find documentation from https://www.npmjs.com/package/fcm-node/
let FCM = require('fcm-call');
const serverKey = '<Your Server Key>';
const referenceKey = '<Your reference key>'; //Device Key
let title = '<Your notification title here.>';
let message = '<Your message here>';
FCM.FCM(serverKey, referenceKey, title, message);
And Your notification will be sent within 2-3 seconds.
Happy Notification.

Related

how does users.watch (in gmail google api) listen for notifications?

I am confused as to how should the watch feature in the gmail API be implemented to recieve the push notificatons inside a node.js script. Should I call the method inside an infinite loop or something so that it doesn't stop listening for notifications for email once after the call is made?
Here's the sample code that I've written in node.js:
const getEmailNotification = () => {
return new Promise(async (resolve, reject) => {
try{
let auth = await authenticate();
const gmail = google.gmail({version: 'v1', auth});
await gmail.users.stop({
userId: '<email id>'
});
let watchResponse = await gmail.users.watch({
userId: '<email id>',
labelIds: ['INBOX'],
topicName: 'projects/<projectName>/topics/<topicName>'
})
return resolve(watchResponse);
} catch(err){
return reject(`Some error occurred`);
}
})
Thank you!
Summary
To receive push notifications through PUB/SUB you need to create a web-hook to receive them. What does this mean? You need a WEB application or any kind of service that exposes a URL where notifications can be received.
As stated in the Push subscription documentation:
The Pub/Sub server sends each message as an HTTPS request to the subscriber application at a pre-configured endpoint.
The endpoint acknowledges the message by returning an HTTP success status code. A non-success response indicates that the message should be resent.
Setup a channel for watch the notifications could be summarized in the following steps (the documentation you refer to indicates them):
Select/Create a project within the Google Cloud Console.
Create a new PUB/SUB topic
Create a subscription (PUSH) for that topic.
Add the necessary permissions, in this case add gmail-api-push#system.gserviceaccount.com as Pub/Sub Publisher.
Indicate what types of mail you want it to listen for via Users.watch() method (which is what you are doing in your script).
Example
I give you an example using Apps Script (it is an easy way to visualize it, but this could be achieved from any kind of WEB application, as you are using Node.js I suppose that you are familiarized with Express.js or related frameworks).
First I created a new Google Apps Script project, this will be my web-hook. Basically I want it to make a log of all HTTP/POST requests inside a Google Doc that I have previously created. For it I use the doPost() equal to app.post() in Express. If you want to know more about how Apps Script works, you can visit this link), but this is not the main topic.
Code.gs
const doPost = (e) => {
const doc = DocumentApp.openById(<DOC_ID>)
doc.getBody().appendParagraph(JSON.stringify(e, null, 2))
}
Later I made a new implementation as a Web App where I say that it is accessible by anyone, I write down the URL for later. This will be similar to deploying your Node.js application to the internet.
I select a project in the Cloud Console, as indicated in the Prerequisites of Cloud Pub/Sub.
Inside this project, I create a new topic that I call GmailAPIPush. After, click in Add Main (in the right bar of the Topics section ) and add gmail-api-push#system.gserviceaccount.com with the Pub/Sub Publisher role. This is a requirement that grants Gmail privileges to publish notification.
In the same project, I create a Subscription. I tell it to be of the Push type and add the URL of the Web App that I have previously created.
This is the most critical part and makes the difference of how you want your application to work. If you want to know which type of subscription best suits your needs (PUSH or PULL), you have a detailed documentation that will help you choose between these two types.
Finally we are left with the simplest part, configuring the Gmail account to send updates on the mailbox. I am going to do this from Apps Script, but it is exactly the same as with Node.
const watchUserGmail = () => {
const request = {
'labelIds': ['INBOX'],
'topicName': 'projects/my_project_name/topics/GmailAPIPush'
}
Gmail.Users.watch(request, 'me')
}
Once the function is executed, I send a test message, and voila, the notification appears in my document.
Returning to the case that you expose, I am going to try to explain it with a metaphor. Imagine you have a mailbox, and you are waiting for a very important letter. As you are nervous, you go every 5 minutes to check if the letter has arrived (similar to what you propose with setInterval), that makes that most of the times that you go to check your mailbox, there is nothing new. However, you train your dog to bark (push notification) every time the mailman comes, so you only go to check your mailbox when you know you have new letters.

How to catch Facebook messaging_optins with Azure Bot Channels Registration + Botbuilder SDK?

I've got a chatbot up and running, built using Node.JS Microsoft Bot Framework, and deployed to an Azure server as a Web App, with a Bot Channels Registration resource as the frontend endpoint.
This Bot Channels Registration is connected to Facebook Messenger (via a FB App) - meaning, the webhook for the Facebook App points to https://facebook.botframework.com/api/v1/bots/<BOT_CHANNELS_REGISTRATION_RESOURCE_NAME>.
This all works well for normal chat functionality.
However, I'd now like to add an opt-in checkbox to a separate web page I have. This checkbox works by pinging FB, which then sends a very specific payload to the already configured bot webhook.
{
"recipient":{
"id":"<PAGE_ID>"
},
"timestamp":<UNIX_TIMESTAMP>,
"optin":{
"ref":"<PASS_THROUGH_PARAM>",
"user_ref":"<UNIQUE_REF_PARAM>"
}
}
My question is this:
How does the Bot Channels Registration receive and handle the above payload? Will it just automatically forward it to the Messaging Endpoint I have configured in the Bot Channels Registration settings? Or will it get stuck, and never reach my actual bot Web App?
Finally, if it does reach my normal messages endpoint, how can I handle the specific payload with my botbuilder.ChatConnector() listener? Given that my web app code looks like (in essence)
var restify = require('restify');
var builder = require('botbuilder');
var dialogues = require('./dialogues');
var chatbot = function (config) {
var bot = {};
chatbot.listen = function () {
var stateStorage = new builder.MemoryBotStorage();
var connector = new builder.ChatConnector({
appId: process.env.APP_ID,
appPassword: process.env.APP_PASSWORD
});
bot = new builder.UniversalBot(connector, function (session) {
session.beginDialog(dialogues.base(bot).name);
}).set('storage', stateStorage);
return connector.listen();
};
return chatbot;
}
var server = restify.createServer();
// Listen for messages from users
server.post('/api/messages', chatbot.listen());
server.listen(process.env.port, function () {
console.log('%s listening to %s', server.name, server.url);
});
Thanks!
EDIT: I've figured out how to handle the above payload within my messaging endpoint - by adding a server.pre() handler to my server, e.g.
server.pre(function (req, res, next) {
if (req.body && req.body.optin_payload_specific_field){
// handle opt-in payload
} else {
return next();
}
});
However, via extra logging lines, it seems the opt-in payload isn't even making it to this endpoint. It seems to be stopped within the Bot Channels Registration. Currently looking for a way to resolve that major roadblock.
So, per #JJ_Wailes investigation, it seems like this is not a supported feature (in fact, it's a current feature request). See his comments on the original post for more details.
However, I did find a half-workaround to capture the user_ref identifier generated by the checkbox_plugin, for those interested:
1) From your external site, follow the steps from the documentation here for sending the initial user_ref to FB. FB will then make a callout to your bot, but per the above, that gets blocked by the Bot Channels Registration piece, so it's ignored.
2) From that same external site, use the user_ref to send a message to the user (just using the normal requests library). A successful send means that the user_ref was properly registered in FB by that step #1 call - a failure means you'll need to repeat step #1 (or use some other error handling flow).
3) After that, the next time the user responds to your bot in FB (as long as you don't send any other messages to them), the message your bot will receive will contain this as part of the payload:
{ ...
channelData:
{ ...
prior_message:
{ source: 'checkbox_plugin',
identifier: <user_ref> }
}
}
So I've currently added a check within my bot.use(), where if that section is present in the incoming message payload (session.message.sourceEvent.prior_message) and the source is "checkbox_plugin", I store the corresponding user_ref in the session.userData, and can work from there.
I would love to see this feature added into the supported Azure bot stack, but in the meantime hopefully this helps anyone else encountering this (admittedly niche) hurdle.

How to send notifications from node.js server to android client.

What technologies do I need to use to send notification from the node.js server to the android client.For example, user A adds user B to friends, at this time user B should receive a notification to his android device that user A wants to add it to friends. I'm new to node.js, could you help me what exactly should I use to implement sending such notifications.
You could use MQTT or AMQP messaging, these are very flexible technologies, well suited to push messages to clients.
https://en.wikipedia.org/wiki/MQTT
https://en.wikipedia.org/wiki/Advanced_Message_Queuing_Protocol
Node.js has very good support for both.
Android has an MQTT client available with an example here: http://androidkt.com/android-mqtt/.
Essentially you can push messages to clients with something like:
client.publish (topic, message).
And clients would subscribe like:
client.on('message', function (topic, message) {
// Messages are Buffer objects.
console.log(message.toString())
client.end()
})
Clients would received this using either a callback or by polling.
Both technologies use a Broker that acts as a go between for the messages.
There are free online Brokers you can use to test messaging, e.g. mqtt://test.mosquitto.org
In Express, once you have your messaging client initialised, you can message on new events, POSTS, PUTS, etc.
app.post("/addFriend", function(req, res, next){
console.log("Friend request added");
// Write to db.
// Send a message
mqttClient.publish('friends-topic', JSON.stringify({event: 'newfriend', id: '10122', name: 'Mark' }))
res.end('ok', 200);
});
On the server side you need something to work with Google's Cloud Messaging service, for instance the node-gcm module
https://github.com/ToothlessGear/node-gcm

Google Cloud Pub/Sub API - Push E-mail

I'm using node.js to create an app that gets a PUSH from Gmail each time an email is received, checks it against a third party database in a CRM and creates a new field in the CRM if the e-mail is contained there. I'm having trouble using Google's new Cloud Pub/Sub, which seems to be the only way to get push from Gmail without constant polling.
I've gone through the instructions here: https://cloud.google.com/pubsub/prereqs but I don't understand how exactly this is supposed to work from an app on my desktop. It seems that pub/sub can connect to a verified domain, but I can't get it to connect directly toto the .js script that I have on my computer. I've saved the api key in a json file and use the following:
var gcloud = require('gcloud');
var pubsub;
// From Google Compute Engine:
pubsub = gcloud.pubsub({
projectId: 'my-project',
});
// Or from elsewhere:
pubsub = gcloud.pubsub({
projectId: 'my-project',
keyFilename: '/path/to/keyfile.json'
});
// Create a new topic.
pubsub.createTopic('my-new-topic', function(err, topic) {});
// Reference an existing topic.
var topic = pubsub.topic('my-existing-topic');
// Publish a message to the topic.
topic.publish('New message!', function(err) {});
// Subscribe to the topic.
topic.subscribe('new-subscription', function(err, subscription) {
// Register listeners to start pulling for messages.
function onError(err) {}
function onMessage(message) {}
subscription.on('error', onError);
subscription.on('message', onMessage);
// Remove listeners to stop pulling for messages.
subscription.removeListener('message', onMessage);
subscription.removeListener('error', onError);
});
However, I get errors as if it isn't connecting to server and on the API list I see only errors, no actual successes. I'm clearly doing something wrong, any idea what it might be?
Thank you in advance!
TL;DR
Your cannot subscribe to push notifications from the client side.
Set up an HTTPS server to handle the messages. Messages will be sent
to the URL endpoint that you configure, representing that server's
location. Your server must be reachable via a DNS name and must
present a signed SSL certificate. (App Engine applications are
preconfigured with SSL certificates.)
Just subscribe to the push notifications on your server, and when you get the notification, you can figure out who it concerns. The data you will get from the notifications is what user that it concerns, and the relevant historyId, like so:
// This is all the data the notifications will give you.
{"emailAddress": "user#example.com", "historyId": "9876543210"}
Then you could e.g. emit an event through Socket.io to the relevant user if he is online, and have him do a sync with the supplied historyId on the client side.

nodejs push notification that subscribes to redis

For logged in users only, I want to somehow notify them if they have any e.g. new notifications.
For example, say a member has sent them a private message, I want to tell the user that they have a new message to view (assuming they have not refreshed the page).
With Nodejs and redis, how would I go about doing this?
Note: I only need nodejs to send a small json to the user saying they have a new message.
The workflow is as follows that I was thinking:
1. user is logged in, a new message is sent to them.
2. somehow using nodejs and redis and long-polling, nodejs communicates back to the logged in users browser they have a pending message.
3. when nodejs sends this push notification, I then call another javascript function that will call a rest service to pull down additional json with the message.
I am integrating nodejs into an existing application, so I want to keep it as simple as possible with nodejs responsible for only notifying and not doing any additional logic.
Can someone outline how I should get going with this?
Should I be using redis http://redis.io/topics/pubsub somehow?
I'm not really sure how that works even after reading the page about it.
If you are integrating your node service into an existing application I would rather use some sort of messaging system to communicate messages from that application to node instead of a DB, even an in-memory DB. For clarity, I will assume you can use rabbitmq. If you do need to use redis, you will just need to find a way to use its publishing instead of rabbitmq publishing and corresponding node-side subscription, but I would imagine that the overall solution would be identical.
You need the following modules:
rabbitmq server (installation complexity about the same as for redis)
rabbitmq library in your external application to send messages, most languages are supported
rabit.js module for node to subscribe to messages or to communicate back to the external application
socket.io module for node to establish real-time connection between the node server and clients
I will also assume that both your external application and your node server have access to some shared DB (which can be redis), where node client session information is stored (e.g. redis-session-store for node). This would allow to use sessionId to validate who the message is for, if the user in the session is logged in and if certain users need to be sent notifications at all (by an external app).
This is how your stack might look like (unpolished):
Define a publisher in node to notify your external application that it needs to start/stop sending messages for a given sessionId. I will assume that for a given sessionId the user information can be recovered on either side (node or external application) from the shared DB and the user can be validated (here for simplicity by checking session.authenticated_user). Also define a subscriber to listen to incoming messages for the users:
var context = require('rabbit.js').createContext();
var pub = context.socket('PUB');
var sub = context.socket('SUB');
Define a socket.io connection(s) from your node server to the clients. As soon the client's web page is (re)loaded and io.connect() is called the below code will be executed (see clinet side at the end of the answer). As a new connection is established, validate the user is logged in (meaning its credentials are in the session), register the socket handler and publish a notification to the external application to start sending messages for this sessionId. The code here assumes a page reload on login/logout (and thus new socket.io session). If this is not the case, just emit a corresponding socket.io message from the client to node and register a handler in the method below in the same way as it is done for a new connection (this is beyond the scope of this example):
var sessionStore = undefined; // out-of-scope: define redis-session-store or any other store
var cookie = require("cookie"),
parseSignedCookie = require('connect').utils.parseSignedCookie;
// will store a map of all active sessionIds to sockets
var sockets = {};
// bind socket.io to the node http server
var io = require('socket.io').listen(httpServer);
// assumes some config object with session secrect and cookie sid
io.sockets.on("connection", function(socket) {
if (socket.handshake.headers.cookie) {
var cks = cookie.parse(socket.handshake.headers.cookie);
var sessionId = parseSignedCookie(cks[config.connectSid], config.sessionSecret);
// retrieve session from session store for sessionId
sessionStore.get(sessionId, function(err, session) {
// check if user of this session is logged in,
// define your elaborate method here
if (!err && session.authenticated_user) {
// define cleanup first for the case when user leaves the page
socket.on("disconnect", function() {
delete sockets[sessionId];
// notify external app that it should STOP publishing
pub.connect('user_exchange', function() {
pub.write(JSON.stringify({sessionId: sessionId, action: 'stop', reason: 'user disconnected'}), 'utf8');
});
});
// store client-specific socket for emits to the client
sockets[sessionId] = socket;
// notify external app that it should START publishing
pub.connect('user_exchange', function() {
pub.write(JSON.stringify({sessionId: sessionId, action: 'start'}), 'utf8');
});
}
});
}
});
Connect subscriber to the rabbitmq exchange to catch messages and emit them to clients:
sub.connect('messages_exchange', function() {
sub.on("readable", function() {
// parse incoming message, we need at least sessionId
var data = JSON.parse(sub.read());
// get socket to emit for this sessionId
var socket = sockets[data.sessionId];
if (socket) {
socket.emit("message", data.message);
} else {
// notify external app that it should STOP publishing
pub.connect('user_exchange', function() {
pub.write(JSON.stringify({sessionId: sessionId, action: 'stop', reason: 'user disconnected'}), 'utf8');
});
// further error handling if no socket found
}
});
});
Finally your client will look roughly like this (here in Jade, but that's just because I already have this whole stack along these lines):
script(src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js")
script(src="/socket.io/socket.io.js")
script(type='text/javascript').
$(function(){
var iosocket = io.connect();
iosocket.on('connect', function () {
// do whatever you like on connect (re-loading the page)
iosocket.on('message', function(message) {
// this is where your client finally gets the message
// do whatever you like with your new message
});
});
// if you want to communicate back to node, e.g. that user was logged in,
// do it roughly like this
$('#btnSend').click(function(event) {
iosocket.send('a message back to the node server if you need one');
});
});
Here is also a really nice explanation from Flickr on how they created a highly available and scalable push notification system with NodeJS and Redis.
http://code.flickr.net/2012/12/12/highly-available-real-time-notifications/

Resources