Socket.io - Sending data from a pusher stream to the client - javascript

I am struggling to send a stream of data being consumed via pusher-client-node to the client using Socket.IO.
I am receiving my data in Node.JS like this:
var API_KEY = 'cb65d0a7a72cd94adf1f';
var pusher = new Pusher(API_KEY, {
encrypted: true
});
var channel = pusher.subscribe("ticker.160");
channel.bind("message", function (data) {
//console.log(data);
});
My data, which comes in continuously, looks like that:
{ channel: 'ticker.160',
trade:
{ timestamp: 1420031543,
datetime: '2014-12-31 08:12:23 EST',
marketid: '160',
topsell: { price: '0.00007650', quantity: '106.26697381' }}
My Socket.IO code looks like this:
/**
* Socket.io
*/
var io = require("socket.io").listen(server, {log: true});
var users = [];
var stream = channel.bind("message", function (data) {
console.log(data);
});
io.on("connection", function (socket) {
// The user it's added to the array if it doesn't exist
if(users.indexOf(socket.id) === -1) {
users.push(socket.id);
}
// Log
logConnectedUsers();
socket.emit('someevent', { attr: 'value' } )
stream.on("newdata", function(data) {
// only broadcast when users are online
if(users.length > 0) {
// This emits the signal to the user that started
// the stream
socket.emit('someevent', { attr: 'value' } )
}
else {
// If there are no users connected we destroy the stream.
// Why would we keep it running for nobody?
stream.destroy();
stream = null;
}
});
// This handles when a user is disconnected
socket.on("disconnect", function(o) {
// find the user in the array
var index = users.indexOf(socket.id);
if(index != -1) {
// Eliminates the user from the array
users.splice(index, 1);
}
logConnectedUsers();
});
});
// A log function for debugging purposes
function logConnectedUsers() {
console.log("============= CONNECTED USERS ==============");
console.log("== :: " + users.length);
console.log("============================================");
}
I am quite new to Node.JS and Socket.IO and struggle to use my pusher stream in Node.JS. Therefore my question: How to connect my Socket.IO code with my Pusher code?

You need to use socket/io rooms ...
server:
var channel = pusher.subscribe("ticker.160"); //subscribe to pusher
//pass messages from pusher to the matching room in socket.io
channel.bind("message", function (data) {
io.to('ticker.160').emit('room-message', {room:'ticker.160', data:data});
});
...
io.on("connection", function (socket) {
...
socket.on('join', function(room){
socket.join(room);
});
socket.on('leave', function(room){
socket.leave(room);
});
});
client:
io.emit('join','ticker.160');
io.on('room-message', function(message){
switch(message.room) {
case 'ticker.160': return doSomething(message.data);
...
}
});

Related

Node.js + Socket.io: Client not receiving message

I am building a very basic chat system between two clients. While the server can receive a message from the client, it cannot send the message to the client (the receiveMessage event is not triggered when the server sends the message to the client). Below is my code client-side:
$("#send-msg").submit(function(e) {
e.preventDefault();
socket.emit("sendMsg", [$("#msg-text").val(), chattingWith]);
});
socket.on("receiveMessage", receiveMsg);
function receiveMsg(data) {
console.log("received msg"); // NOT OUTPUTTED
}
Below is my code server-side:
var socket = io.connect();
var io = socket(server, { pingTimeout: 63000 });
io.sockets.on("connection", userConnect);
function userConnect(user) {
user.on("sendMsg", sendMsg);
function sendMsg(msgData) {
var msgContent = msgData[0];
var receiverId = msgData[1];
console.log("received message from " + receiverId); // ACTIVATED
io.to(receiverId).emit("receiveMessage", [msgContent, receiverId]);
}
}
I think you should change a little your code:
Client side (I assume that chattingWith is a unique room or chat id):
$("#send-msg").submit(function(e) {
e.preventDefault();
socket.emit("send message", $("#msg-text").val(), chattingWith);
});
socket.on("send Message", receiveMsg);
function receiveMsg(data) {
console.log(data); //An array should be an output
}
Server side code:
io.on('connection', function(socket){
socket.on('send message', function(data, id){
socket.join(id)
io.sockets.in(id).emit('sendMessage', {
data: data,
})
})
})

Managing subscription of push notification on client and server sides

I erase all my previous questions on how to use the code give into the documentation of workbox push notification to show you the solution I found more clearly.
before to show you the code, I will explain that I took long time to understand. You use normaly three files that work with service worker. In my case server.js, index.js and sw.js. When the browser get all the files it need to display your site, I also get the index.js file. This file start the service worker with navigator.serviceWorker.register('sw.js'). Then, it test if the user has already accepted to receive notification. At the end, it check if subscription exist or not and manage its.
The subscription part is very important and difficult to manage. With swRegistration.pushManager.subscribe() we will get an sub object. This object contains the endpoint, the auth and the p256th. Those informations are very important and we need to send to our server to store it into our database. the fetch() element do it. By this way, we will be able to send a notification to our tagerted user in the futur.
The last thing you need to know and how to create private and public Vapid keys. To generate it, display into your terminal the console.log that are below my privateVapidKey variable inside server.js. Then copy-paste both results into variable as I did server.js and alse copy-paste publicsVapidKey into index.js file.
server.js :
var express = require('express');
var app = express();
var https = require('https');
var fs = require('fs');
var webPush = require('web-push');
var bodyParser = require('body-parser');
https.createServer({
key: fs.readFileSync('key_localhost2.pem'),
cert: fs.readFileSync('cert_localhost2.pem'),
passphrase: 'localhost',
}, app).listen(8080);
//*****************************************************************
//-------------------------- TEMPLATES --------------------------
//*****************************************************************
//moteur de modèles ou de templates
app.set('view engine', 'ejs');
//*****************************************************************
//-------------------------- MIDDLEWARE --------------------------
//*****************************************************************
app
.use('/static', express.static(__dirname + '/public'))
.use(express.static(__dirname + '/public/js'))
.use(bodyParser.json());
//*****************************************************************
//--------------------------- ROUTES ------------------------------
//*****************************************************************
app.get('/', function (request, response) {
response.render('./pages/index.ejs');
});
var publicVapidKey = "BKwLqQWMQpLfSNGb-VXCsAPE1H5o7Oh3VxDiEIqWWOm2OdAoFPqr9K9WI7dKKtjYYHLTKm7tjJO04091pDXZiJs"
var privateVapidKey = "483sZs2cZUxSQegGKKOZXLl_b7_ywBF_qJO77gXFsHE"
//console.log('Publics keys : ' + vapidKeys.publicKey)
//console.log('Private key : ' + vapidKeys.privateKey)
webPush.setVapidDetails(
'mailto:localhost:8080',
publicVapidKey,
privateVapidKey
);
var pushSubscription;
app.post('/subscription_push_notification', function (req, resp) {
pushSubscription = req.body;
console.log(pushSubscription)
//I'm able to save this information into my database
endpointVal = req.body.endpoint;
authVal = req.body.keys.auth;
p256dhVal = req.body.keys.p256dh;
setTimeout(function () {
if (endpointVal) {
var payload = 'Here is a payload!';
webPush.sendNotification(
pushSubscription,
payload
).catch(function (err) {
console.log(err);
});
}
}, 2000)
resp.json({});
});
index.js :
window.addEventListener('load', function () {
//*********************************************************
// Start SW, permission notification, register subscribe
//*********************************************************
if ('serviceWorker' in navigator) {
//+++++++++++++++++++++++++++++
//Register Service worker
navigator.serviceWorker.register('sw.js')
.then(function (swRegistration) {
//Ask to notification permission
displayNotification();
var publicVapidKey = "BKwLqQWMQpLfSNGb-VXCsAPE1H5o7Oh3VxDiEIqWWOm2OdAoFPqr9K9WI7dKKtjYYHLTKm7tjJO04091pDXZiJs";
var applicationServerKey = urlBase64ToUint8Array(publicVapidKey);
//Manage push notifiaction
swRegistration.pushManager.getSubscription().then(function (sub) {
if (sub === null) {
// Update UI to ask user to register for Push
console.log('Not subscribed to push service!');
swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
}).then(function (sub) {
// We have a subscription, update the database
console.log('Endpoint URL: ', sub.endpoint);
fetch('/subscription_push_notification', {
method: 'POST',
body : JSON.stringify(sub),
headers: {
'content-type':'application/json'
}
});
}).catch(function (e) {
if (Notification.permission === 'denied') {
console.warn('Permission for notifications was denied');
} else {
console.error('Unable to subscribe to push', e);
}
});
} else {
// We have a subscription, update the database
console.log('Subscription object: ', sub);
fetch('/subscription_push_notification', {
method: 'POST',
body : JSON.stringify(sub),
headers: {
'content-type':'application/json'
}
});
}
});
})
.catch(function (err) {
console.log('Service Worker registration failed: ', err);
})
}
//*********************************************************
// Function ask to notification permission
//*********************************************************
function displayNotification() {
if (Notification.permission === 'granted') {
//Mean, the notification is accepted.
console.log('Notification accepted...');
} else if (Notification.permission === "blocked" || Notification.permission === "denied") {
// the user has previously denied notification. Can't reprompt.
console.log('Notification blocked...');
} else {
// show a prompt to the user
console.log('Prompt to accept notification');
Notification.requestPermission();
}
}
//*********************************************************
// Transform public Vapid key
//*********************************************************
function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
});
sw.js :
importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.4.1/workbox-sw.js');
if (workbox) {
console.log(`Yay! Workbox is loaded 🎉`);
} else {
console.log(`Boo! Workbox didn't load 😬`);
}
//*********************************************************
// Save file from site to work in offline mode
//*********************************************************
workbox.precaching.precacheAndRoute([
{ url: '/', revision: '383676' },
{ url: '/static/css/style.css', revision: '383677' },
{ url: '/static/js/index.js', revision: '383678' },
]);
//*********************************************************
// The notification click event
//*********************************************************
//Inform when the notification close/hide from the window
self.addEventListener('notificationclick', function (e) {
console.log('notification was clicked')
var notification = e.notification;
var action = e.action;
if (action === 'close') {
notification.close();
} else {
clients.openWindow('https://www.google.fr');
};
});
//*********************************************************
// Handling the push event in the service worker
//*********************************************************
self.addEventListener('push', function (e) {
console.log('Hi man !!!')
var options = {
body: e.data.text(),
icon: '/static/img/logo_menu.png',
vibrate: [100, 50, 100],
data: {
dateOfArrival: Date.now(),
primaryKey: '2'
},
};
e.waitUntil(
self.registration.showNotification('Hello world!', options)
);
});

Unsubscribe from Rethink DB Outside function in Node.JS

Im using Socket.io and Rethink DB to push realtime data on Node.js.
Subscribing to the stream works but when the user disconnects I can figure out how to unsubscribe to the rethink db.
Here's my code:
Part of app.js:
// Adding socket.io
app.io = require('socket.io')();
var feed;
// On connection to the socket, just invoking the function.
app.io.on('connection',function(socket) {
console.log('Client connected...');
feed = require('./feed')(socket);
socket.on('disconnect', function() {
console.log('Got disconnect!');
# Here I'd like to unsubscribe
});
});
feed.js:
var r = require('rethinkdb');
var dbConfig = require('./config/database');
module.exports = function(socket) {
var connection = r.connect(dbConfig)
.then(function (connection) {
r.db('Minicall').table('Message').changes().run(connection,function(err,cursor) {
if(err) {
console.log(err);
}
cursor.each(function(err,row) {
console.log(JSON.stringify(row));
if(Object.keys(row).length > 0) {
console.log("send");
socket.emit("msgFeed",{"timestamp" : row.new_val.timestamp, "message" : row.new_val.message ,"ric" : row.new_val.ric});
}
});
});
});
};
So, how can I stop the subscribing (connection.stop()) when socket.on('disconnect') gets called? Probably a easy solution since I'm totally new to node and js.
You can have more than one event listener to an event, so in your cursor you'll add a disconnect event listener that can call cursor.close():
r.db('Minicall')
.table('Message')
.changes()
.run(connection, function(err, cursor) {
if(err) {
console.log(err);
}
cursor.each(function(err,row) {
console.log(JSON.stringify(row));
if(Object.keys(row).length > 0) {
console.log("send");
socket.emit("msgFeed",{"timestamp" : row.new_val.timestamp, "message" : row.new_val.message ,"ric" : row.new_val.ric});
}
});
socket.on('disconnect', function() {
cursor.close();
});
});

nodejs does not emit data to client

I have simple nodejs app with sockets and I've faced an error where I can't find any solution. So I'm emiting from app to client and nothing happens there. Or client can't receive it - I don't know, because I can't check if it was successfully emited to client. This is the error I got when I tried to debug callback of emit:
Error: Callbacks are not supported when broadcasting
This my app code:
http.listen(6060, function () {
console.log("Listening on *: 6060");
});
io.set('authorization', function (handshakeData, accept) {
var domain = handshakeData.headers.referer.replace('http://', '').replace('https://', '').split(/[/?#]/)[0];
if ('***' == domain) {
accept(null, true);
} else {
return accept('You must be logged in to take an action in this site!', false);
}
});
io.use(function (sock, next) {
var handshakeData = sock.request;
var userToken = handshakeData._query.key;
if (typeof userToken !== null && userToken !== 0 && userToken !== '0' && userToken.length > 0) {
connection.query('***',
[xssfilter.filter(validator.escape(userToken))],
function (error, data) {
if (error) {
debug('Cant receive user data from database by token');
next(new Error('Failed to parse user data! Please login!'));
} else {
// load data to this user.
_updateUsers(xssfilter.filter(validator.escape(userToken)), 'add', data[0], sock.id);
_loadPreData();
next(null, true);
}
});
} else {
debug('Cant receive user token');
next(new Error('Failed to parse user data! Please login!'));
}
sock.on("disconnect", function () {
_updateUsers(false, 'remove', false, sock.id);
});
});
// we need to show people online count
io.emit('online-count', {
count: Object.keys(connectedUsers).length
});
And the function used above:
function _updateUsers(userToken, action, userData, sockedID) {
switch (action) {
case 'add':
connectedUsers[sockedID] = {...};
io.emit('online-count', io.emit('online-count', {
count: Object.keys(connectedUsers).length
}););
break;
case 'remove':
delete connectedUsers[sockedID];
io.emit('online-count', io.emit('online-count', {
count: Object.keys(connectedUsers).length
}););
break;
}
}
so after emiting online-count I should accept it on the client side as I'm doing it:
var socket;
socket = io(globalData.socketConn, {query: "key=" + globalData.userData.token});
socket.on('connect', function (data) {
console.log('Client side successfully connected with APP.');
});
socket.on('error', function (err) {
error('danger', 'top', err);
});
socket.on('online-count', function (data) {
console.log('Got online count: ' + data.count);
$('#online_count').html(data.count);
});
but the problem is with this online-count.. Nothing happens and it seems that it's not was even sent from node app. Any suggestions?
The problem was with my logic - I was sending online count only if new user were connecting/disconnecting. Problem were solved by adding function to repeat itself every few seconds and send online count to client side.

Socket io multiplayer game infrastructure

var connectionHandler = function(socket) {
var player = null;
socket.on('login', function(data) {
player = {
data: okeyServer.playerJoin(data),
socket: socket
};
socket.emit('welcome');
});
socket.on('info server', function(data) {
var info = okeyServer.Info();
socket.emit('info server', info);
});
socket.on('join game', function (data) {
var gameid = data.gameid;
var side = data.side;
okeyServer.playerJoinGame(player, gameid, side);
});
socket.on('disconnect', function () {
okeyServer.playerLeave(player);
io.sockets.emit('player leave', player);
});
}
I am trying to do a multiplayer game app with socket.io. When player connects, i want a 'login' message to be sent first. and i initialize the player variable for further use.
Other messages uses the player variable later.
How can i make sure client sent a 'login' message before making other requests.
I can check if player is null on every request where i need player but that seems ugly.
You could install the other listeners from within the login listener:
var connectionHandler = function(socket) {
var player = null;
socket.on('login', function(data) {
// If we already have a player, just return a `welcome` message.
if (player !== null) {
return socket.emit('welcome');
}
// Store player.
player = {
data: okeyServer.playerJoin(data),
socket: socket
};
// Emit welcome message.
socket.emit('welcome');
// Set up the rest of the listeners.
socket.on('info server', function(data) {
var info = okeyServer.Info();
socket.emit('info server', info);
});
socket.on('join game', function (data) {
var gameid = data.gameid;
var side = data.side;
okeyServer.playerJoinGame(player, gameid, side);
});
socket.on('disconnect', function () {
okeyServer.playerLeave(player);
io.sockets.emit('player leave', player);
});
});
};
This assumes that a login message is only ever emitted once by the client during the lifetime of the connection. If that's not the case, you need to make some changes.

Categories