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.
Related
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,
})
})
})
I am having a difficulty understanding Javascript-style function definitions.
I have a Websocket server:
var WebSocketServer = require('ws').Server,
wss = new WebSocketServer();
wss.on('connection', function (ws) {
ws.on('message', function (message) {
console.log('received: %s from client', message);
})
ws.send('hello client');
})
And I want to send a message to the connected clients when another function importantEvent() is called.
function importantEvent(message) {
//send message to the connected client
ws.send('hello client');
}
What is the good way of calling ws.send() inside importantEvent()?
I use EventEmitter to similar things to avoid a strong module strength.
// eventManager.js
const EventEmitter = require('events');
class EventManager extends EventEmitter {}
const eventManager = new EventManager();
module.exports = eventManager;
// websocket.js
var eventManager = require('eventManager');
var WebSocketServer = require('ws').Server,
wss = new WebSocketServer();
wss.on('connection', function (ws) {
...
})
function broadcast(data, filter) {
wss.clients.forEach( ... // depends on library using to web-socket
}
eventManager.on('my-event', function (arg1, arg2) {
broadcast({arg1, arg2})
});
// in any other files
var eventManager = require('eventManager');
eventManager.emit('my-event', 'hello', 'world');
It's a matter of what clients you want to reach. In wss.on('connection'... event, the ws received by the function is the client that is connecting to the server in this event.
As you want send a message to all the clients connected, you need to use the broadcast method
var WebSocketServer = require('ws').Server,
wss = new WebSocketServer();
function importantEvent(message) {
// Broadcast to all.
wss.broadcast = function broadcast(data) {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send('hello client');
}
});
};
}
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)
);
});
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();
});
});
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);
...
}
});