Firebase push notifications - node worker - javascript

I need to send iOS push notifications to user whenever a certain child is added to a Firebase path.
I was thinking, that the best way to do that, would be to make a Node.js worker on Heroku, that would listen for changes and send a notification using Urban Airship.
I'm not sure what the best way is to listen for changes on Firebase from a Node.js worker on Heroku is. I'm not that familiar with heroku workers and Node.js.
Can anyone give me some pointers? Examples?

Sending push notifications with Firebase and node-apn is easy:
var apn = require("apn");
var Firebase = require("firebase");
// true for production pipeline
var service = new apn.connection({ production: false });
// Create a reference to the push notification queue
var pushRef = new Firebase("<your-firebase>.firebaseio.com/notificationQueue");
// listen for items added to the queue
pushRef.on("child_added", function(snapshot) {
// This location expects a JSON object of:
// {
// "token": String - A user's device token
// "message": String - The message to send to the user
// }
var notificationData = snapshot.val();
sendNotification(notificationData);
snapshot.ref().remove();
});
function sendNotification(notificationData) {
var notification = new apn.notification();
// The default ping sound
notification.sound = "ping.aiff";
// Your custom message
notification.alert = notificationData.message;
// Send the notification to the specific device token
service.pushNotification(notification, [notificationData.token]);
// Clean up the connection
service.shutdown();
}
For hosting this script, you won't be able to use a PaaS like Heroku. They tend to kill idle sockets. Instead you'll have to use a virtual machine.
Google Cloud Platform has a Node.js launcher that works well.

Related

multiple browser instances with websocket capabilities in node?

Let's say I am building a social app. I want to log into multiple accounts (one per browser instance) without an user interface (all via node), and by calling all respective endpoints to log in and start chatting.
The important part is to test when an user closed the tab or logs out or leaves the group and therefore the websocket's connection closes.
If I understand you correctly.
You would like to make a server-side event happen whenever a client connects or disconnects, without any html,css.... or any other user interface.
You can do it like this in node :
For connection you use :
Server.on("connection,function(ws){some stuff...})
The function that is called on connection will get the websocket that connected as parameter by default. I just use a lambda function here you can also call one that will then get the websocket as parameter.
For disconnection you put a function in the Server.on function to monitor when the client disconnected. Like this :
Server.on("connection,function(ws){
ws.onclose = function (ws) {
some stuff...
}
})
You can again replace the lambda function by another one.
Server is in my case equal to this :
const wsserver = require("ws").Server
const server = new wsserver({ port: someport })
But it can vary.
All you need to do apart from that is connect the client.
I do it like this but it can vary as well.
const ws = new WebSocket("ws://localhost:someport");
I hope this is helpful.

How to create sockets that particular to user and disposable on Socket.Io

I write a Node.Js app and I use Socket.Io as the data transfer system, so requests should be particular to per user. How can I make this?
My actual code;
node:
io.on('connection', (socket) => {
socket.on('loginP', data => {
console.log(data);
})
})
js:
var socket = io('',{forceNew : false});
$("#loginbutton").click(function() {
var sessionInfo = {
name : $("#login input[name='username']").val(),
pass : $("#login input[name='pass']").val()
}
socket.emit("loginP", sessionInfo)
})
It returns one more data for per request and this is a problem for me. Can I make this on Socket.Io or should I use another module, and If I should, which module?
If I understand your question correctly (It's possible I don't), you want to have just one connection from each user's browser to your nodejs program.
On the nodejs side, your io.on('connection'...) event fires with each new incoming user connection, and gives you the socket for that specific connection. So, keep track of your sockets; you'll have one socket per user.
On the browser side, you should build your code to ensure it only calls
var socket = io(path, ...);
once for each path (your path is ''). TheforceNew option is for situations where you have multiple paths from one program.

Cannot connect to CosmosDb from Azure Bot using Node

Can someone please take a look at this code and tell me why I am getting the below error message. I have looked at this every which way and can't understand why or where it's breaking.
The below code shows hard values for docDbClient, but I have also used the "process.env.Document..." system variables to no effect. This is largely taken from the Node Botbuilder samples found online. It is supposed to connect to a CosmosDb database. This should just power up. Using the Bot Framework Emulator, produces the error message at the command prompt where the server is running. Trying via published web page, it just breaks with no error message.
Thank you, in advance!
var restify = require('restify');
var builder = require('botbuilder');
var botbuilder_azure = require("botbuilder-azure");
var builder_cognitiveservices = require('botbuilder-cognitiveservices');
// Setup Restify Server
var server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function() {
console.log('%s listening to %s', server.name, server.url);
});
// Create chat connector for communicating with the Bot Framework Service
var connector = new builder.ChatConnector({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword,
openIdMetadata: process.env.BotOpenIdMetadata
});
// Listen for messages from users
server.post('/api/messages', connector.listen());
var docDbClient = new botbuilder_azure.DocumentDbClient({
host: 'https://xxxxx.table.cosmosdb.azure.com:443',
masterKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxx',
database: 'TablesDB',
collection: 'botdata'
});
var tableStorage = new botbuilder_azure.AzureBotStorage({ gzipData: false }, docDbClient);
// Create your bot with a function to receive messages from the user
var bot = new builder.UniversalBot(connector, function(session) {
session.send('You said: %s', session.message.text);
session.endDialog();
}).set('storage', tableStorage); // Register in Azure Storage
Error:
Error: Failed to initialize azure table client. Error: Error: Error Code:
400 Error Body: {"odata.error":{"code":"BadRequest","message":{"lang":"en-
us","value":"One of the input values is invalid.\r\nActivityId: 676a8f3c-
f287-490c-9062-021cb29ff78a, documentdb-dotnet-sdk/1.20.0 Host/64-bit
MicrosoftWindowsNT/6.2.9200.0\nRequestID:676a8f3c-f287-490c-9062-
021cb29ff78a\n"}}}
at C:\...\Coffee-Bot\node_modules\botbuilder-azure\lib\AzureBotStorage.js:177:32
at C:\...\Coffee-Bot\node_modules\botbuilder-azure\lib\DocumentDbClient.js:15:17
at C:\...\Coffee-Bot\node_modules\botbuilder-azure\lib\DocumentDbClient.js:76:17
at C:\...\Coffee-Bot\node_modules\documentdb\lib\queryIterator.js:141:28
at C:\...\Coffee-Bot\node_modules\documentdb\lib\queryExecutionContext\proxyQueryExecutionContext.js:71:32
at C:\...\Coffee-Bot\node_modules\documentdb\lib\queryExecutionContext\defaultQueryExecutionContext.js:62:17
at C:\...\Coffee-Bot\node_modules\documentdb\lib\queryExecutionContext\defaultQueryExecutionContext.js:81:32
at C:\...\Coffee-Bot\node_modules\documentdb\lib\queryExecutionContext\defaultQueryExecutionContext.js:136:28
at successCallback (C:\...\Coffee-Bot\node_modules\documentdb\lib\documentclient.js:2360:33)
at C:\...\Coffee-Bot\node_modules\documentdb\lib\documentclient.js:2410:25
You seem to be mixing a Cosmos DB Table endpoint and a DocumentDB client instance, which explains the 400 Bad Request.
For DocumentDB API (note host has .documents. not .table.):
var docDbClient = new botbuilder_azure.DocumentDbClient({
host: 'https://xxxxx.documents.cosmosdb.azure.com:443',
masterKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxx',
database: 'botdocs',
collection: 'botdata'
});
var tableStorage = new botbuilder_azure.AzureBotStorage({ gzipData: false }, docDbClient);
To use Azure Table storage for bot state (this is regular Table storage, as in storage account, not Cosmos DB Table API):
var azureTableClient = new azure.AzureTableClient(tableName, storageName, storageKey);
var tableStorage = new azure.AzureBotStorage({gzipData: false}, azureTableClient);
In theory, if you pass a Cosmos DB Table endpoint to azure.AzureTableClient() you can use Cosmos as Table storage, the Table APIs are compatible between Azure Storage and Cosmos. I don't see any immediate benefit over standard DocumentDB type.
Ref:
https://learn.microsoft.com/en-us/bot-framework/nodejs/bot-builder-nodejs-state-azure-cosmosdb
https://learn.microsoft.com/en-us/bot-framework/nodejs/bot-builder-nodejs-state-azure-table-storage

APNSwork on apn provider but not through nodeJS - Production

I have a nodeJS script set up to send APNs. When in development it always works but when i go to production they never get through. I tried taking the same notification Id it's sending and sending something using my production certificate in Easy Apn Provider and and it goes through. Im not sure why i could be failing. If my profile or certificates were wrong the easy apn wouldnt go through either?
apn config
var options = {
token: {
cert: "certificate.pem",
pfx: "Certificate.p12",
key: "AuthKey_XCVK62CSQF.p8",
keyId: "3Z6SEF7GE5",
teamId: "ASQJ3L7765"
},
production: true,
gateway: 'gateway.push.apple.com', // gateway address
port: 2195
};
var apnProvider = new apn.Provider(options);
Result of:
//IOS notif function
function SendIOSNotification(token, message, sound, payload, badge){
var deviceToken = token; //phone notification id
var notification = new apn.Notification(); //prepare notif
notification.topic = 'com.GL.Greek-Life'; // Specify your iOS app's Bundle ID (accessible within the project editor)
notification.expiry = Math.floor(Date.now() / 1000) + 3600; // Set expiration to 1 hour from now (in case device is offline)
notification.badge = badge; //selected badge
notification.sound = sound; //sound is configurable
notification.alert = message; //supports emoticon codes
notification.payload = {id: payload}; // Send any extra payload data with the notification which will be accessible to your app in didReceiveRemoteNotification
apnProvider.send(notification, deviceToken).then(function(result) { //send actual notifcation
// Check the result for any failed devices
var subToken = token.substring(0, 6);
console.log("Succesfully sent message to ", subToken);
}).catch( function (error) {
console.log("Faled to send message to ", subToken);
})
}
is successfully sent message to 5D..
Edit:
When displaying my response i see that the notification actually failed with a 403 error (id doesnt exist however it works just fine with easy apn).
I assume its because im generating a non production id but i dont understand how thats possible. I signed my build and have it on testflight and ive removed all signes of development profiles and only have production profiles and certificates. Not sure how thiis is happening
The issue was that when i changed to production and it wasnt working I tried creating a new .p8 key. It was likely working at that point but i only changed the reference to .p8 and not the key parameter to the key of the .p8 found on my developer account. Once i updated that key all my problems were solved

Real time notifications node.js

I'm developing a calendar application with Node.js, express.js and Sequelize.
The application is simple, you can create tasks in your calendar, but you can also assign some tasks to others users of the system
I need to create a notification system with socket.io, but I don't have experience with websockets. My big doubt is how can I make my server send a notification to the user that you assign the task?
My ports configurations is on a folder called bin/www, my express routes are defined on a file called server.js
Any Idea?
I want to introduce you to ready to use backend system that enables you to easily build modern web applications with cool functionalities:
Persisted data: store your data and perform advanced searches on it.
Real-time notifications: subscribe to fine-grained subsets of data.
User Management: login, logout and security rules are no more a burden.
With this, you can focus to your main application development.
You can look at Kuzzle, wich is one project I working on:
First, start the service:
http://docs.kuzzle.io/guide/getting-started/#running-kuzzle-automagically
Then in your calendar application you can the javascript sdk
At this point you can create a document:
const
Kuzzle = require('kuzzle-sdk'),
kuzzle = new Kuzzle('http://localhost:7512');
const filter = {
equals: {
user: 'username'
}
}
// Subscribe every changes in calendar collection containing a field `user` equals to `username`
kuzzle
.collection('calendar', 'myproject')
.subscribe(filter, function(error, result) {
// triggered each time a document is updated/created !
// Here you can display a message in your application for instance
console.log('message received from kuzzle:', result)
})
// Each time you have to create a new task in your calendar, you can create a document that represent your task and persist it with kuzzle
const task = {
date: '2017-07-19T16:07:21.520Z',
title: 'my new task',
user: 'username'
}
// Creating a document from another app will notify all subscribers
kuzzle
.collection('calendar', 'myproject')
.createDocument(task)
I think this can help you :)
Documents are served though socket.io or native websockets when available
Don't hesitate to ask question ;)
As far as I can understand you need to pass your socket.io instance to other files, right ?
var sio = require('socket.io');
var io = sio();
app.io = io;
And you simply attach it to your server in your bin/www file
var io = app.io
io.attach(server);
Or what else I like to do, is adding socket.io middleware for express
// Socket.io middleware
app.use((req, res, next) => {
req.io = io;
next();
});
So you can access it in some of your router files
req.io.emit('newMsg', {
success: true
});

Categories