unable to get data from socket.io-redis with nodejs - node.js

Hope you are doing well,
As I am creating a multiplayer games, so i need to store all user details from socket, after some time I need to make a group from the Users list.
So I tried to implement https://github.com/socketio/socket.io-redis library and trying to get all connected users but it's not working, I have developed according to this example Example to use socket.io-redis, but it'not work for me and my redis server is working well.
Thanks
Example :
index.js
var express = require('express');
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));
var your_namespace_socket = io.of('/');
app.get('/', function(req, res) {
res.sendfile('index.html');
});
your_namespace_socket.on('connection', function(socket) {
console.log(socket.id);
socket.on('join', function(room) {
socket.join(room);
console.log(room);
//log other socket.io-id's in the room
your_namespace_socket.adapter.clients([room], (err, clients) => {
console.log(clients);
});
});
});
server.listen(3000, function() {
console.log('listening on *:3000');
});
index.html
<html>
<head>
<title>Hello world</title>
</head>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io('/');
socket.emit('join', 'testingroom');
</script>
<body></body>
</html>
Output
User has joined session in a room with cannot fetch data from redis, as you can see in screenshot
Output of Above Code

I tested your code and it works for me, it might be an error with redis, do you have any error in the callback :
your_namespace_socket.adapter.clients([room], (err, clients) => {
if(err) console.log(err)
console.log(clients);
});

Related

How to use socket.io to reflect one api changes in another api without loading?

I've a node api(POST)in which the sensor keep on pushing the data to the MongoDB. Now I've an api(GET) which fetches the data from the database and displays on the dashboard. To get the continuous stream of data, I want to use SOCKET.IO module. But the problem is, how could I get the recently saved record from the db and show that on dashboard without reloading the page. Please have a look at my code.
SERVER.JS
var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http);
// and manything like router, middleware, etc...
io.on('connection', function(socket){
console.log('a user connected');
});
http.listen(3000, function(){
console.log('listening on port:3000');
});
ROUTES FILE
var router = require("express").Router();
router.post("/upload/device/data/:tempId", TemplateController.AddDeviceData); //To insert the data to the DB
router.get("/view/template/device/logs/:tempUniqID", TemplateController.deviceLogs); //To get the data from DB
TEMPLATE CONTROLLER FILE
module.exports={
AddDeviceData:async function(req, res){ //Controller to post data
let err, deviceLog;
[err, deviceLog]=await
to(TemplateService.AddDeviceLogs(req.params.tempId, req.body));
if(err) return res.serverError(err.message);
if(deviceLog&&deviceLog!==false){
return res.ok(deviceLog);
}else{
res.badRequest("Sorry cannot add Device log data");
}
},
deviceLogs: async function(req, res){ //Controller to fetch data
let err, logs;
let deviceId = req.query.device;
[err, logs]=await to(TemplateService.displayLogs(req.params.tempUniqID, deviceId));
if(err) return res.serverError(err.message);
if(logs&&logs!==false){
return res.ok(logs);
}else{
res.badRequest("Sorry cannot add Device log data");
}
}
}
TEMPLATE SERVICE FILE
module.exports={
//Service to post data
AddDeviceLogs:async function(templateId, payload){
let err, deviceData;
payload.template=templateId;
const myCollection=templateId;
[err, deviceData]=await to(mongoose.connection.db.collection(myCollection).insert(payload));
if(err) TE(err.message, true);
socket.emit('data', deviceData);
return (deviceData)? deviceData.result:false;
},
//Service to get data
displayLogs:async function(tempUniqID, deviceID){
let err, respData;
var Query = (deviceID)? {"template": tempUniqID, "deviceId": deviceID}:{template: tempUniqID};
[err, respData]=await to(mongoose.connection.db.collection(tempUniqID).find(Query).sort({_id: -1}).limit(20).toArray())
if(err) {TE(err, true);}
return (respData)? respData:false;
}
}
Now I want to get most recently stored data in GET api using socket without reloading the page or without executing the GET route-api. I'm not getting which service I should use server socket-emit event in and how.
You can run node and your socket io in the same port, the following example used express and socket.io. I also created sensor code to imagine this solution:
You should use your route file like this:
ROUTES FILE
var router = require("express").Router();
router.post("/upload/device/data/:tempId", TemplateController.AddDeviceData);
router.get("/", function (req, res, next) {
res.sendFile('C:/Users/user/Desktop/data.html');
})
In MVC you will have a root file declare all works, you should delare your socket here.
Because in your codebase, every time you call AddDeviceLogs function, it will re-declare websocket, and your socket client in html file will disconnect, that's why it only work for the first time.
Then you should declare it global, for example:
server.js
var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http);
// and manything like router, middleware, etc...
io.on('connection', function(socket){
console.log('a user connected');
});
http.listen(3000, function(){
console.log('listening on port:3000');
});
TEMPLATE SERVICE FILE
module.exports={
AddDeviceLogs:async function(templateId, payload){
let err, deviceData;
payload.template=templateId;
const myCollection=templateId;
io.emit('data', payload) // emit to all client
[err, deviceData]=await to(mongoose.connection.db.collection(myCollection).insert(payload));
if(err) TE(err.message, true);
return (deviceData)? deviceData.result:false;
}
}
data.html
<html>
<head>
<script src="/socket.io/socket.io.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js"></script>
</head>
<body>
<script>
var socket = io.connect("http://localhost:3000/",{"forceNew": true});
socket.on('data', function(data){
if (data) {
$('#deviceid').text(data.deviceId);
$('#heat').text(data.heat);
$('#humidity').text(data.humidity);
}
});
</script>
<h4>Welcome to socket.io testing program!</h4>
<div id="deviceid"></div>
<div id="heat"></div>
<div id="humidity"></div>
</body>
</html>

Chat application using socket.io not connecting when deploying on production server

I am trying to implement chat application using nodejs and socket.io. The application works on localhost. But when I deploy same on my production server then socket.io can't make any connection.
Code for server.js
var express = require('express');
var app = express();
var socket = require('socket.io');
var chat_controller = require('./controllers/ChatController.js');
var user_controller = require('./controllers/UserController.js');
var Group_controller = require('./controllers/GroupChatController.js');
app.get('/search', function (req, res) {
user_controller.get(req, res);
});
app.get('/groupSearch', function (req, res) {
user_controller.get(req, res);
});
var server = app.listen(3600, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
});
var io = socket(server);
io.on('connection', (socket) => {
console.log('made socket connection', socket.id);
socket.broadcast.emit('userconnected');
chat_controller.respond(io, socket);
Group_controller.respond(io, socket);
user_controller.respond(io, socket);
});
io.on('disconnect', function () {
console.log('made socket disconnect', socket.id);
});
Code for client.js
var socket = io.connect('https://www.mywebsite.com', {
path: '/apichat'
});
/* Other events related to socket. */
As my server uses SSL I can't used IP:PORT directly so I am using ProxyPass as
ProxyPass /apichat http://127.0.0.1:3600
After all this still socket connection is not established between server and client.
Error shown in browser console is:
POST https://www.mywebsite.com/apichat/?EIO=3&transport=polling&t=MUc-TJK 404 (Not Found)
And in browser Network tab it shows:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot POST /</pre>
</body>
</html>
I have checked many other questions posted here and other sites but no question address this issue.
Please Help.
The issue you are encountering is probably due to ssl enabled on your website.
You need to pass ssl related files in your app.js file. Sample code for this is as follow:
var fs = require('fs');
var options = {
key: fs.readFileSync('PATH_TO_SSL_KEYS.key'),
cert: fs.readFileSync('PATH_TO_SSL_CERTS.crt'),
ca: fs.readFileSync('PATH_TO_SSL.pem')
};
var app = require('https').createServer(options, handler), io = require('socket.io').listen(app);
io.set('transports', [
'websocket',
'flashsocket',
'htmlfile',
'xhr-polling',
'jsonp-polling',
'polling'
]);
function handler(req, res) {
res.writeHead(200);
res.end("welcome sir!");
}
var chat_controller = require('./controllers/ChatController.js');
var user_controller = require('./controllers/UserController.js');
io.sockets.on('connection', function (socket) {
socket.broadcast.emit('userconnected');
chat_controller.respond(io, socket);
user_controller.respond(io, socket);
socket.on('message', function (data) {
socket.broadcast.emit('message', data);
});
});
io.on('disconnect', function (socket) {
console.log('made socket disconnect', socket.id);
});
app.listen(3300);
Try editing your application file as per above mentioned sample code and then try to use it. If you can't get path to ssl related file, then you need to contact either your system administrator or the hosting provider.
I hope it helped.

How to clear redis database when nodejs server disconnect?

I have a simple chatroom application using a node express server.
This uses a redis database connection to store the nicknames of the joined clients.
I need to clear the redis SET of nicknames named members when the server is closed/disconnected.
This can be done as following:
redisClient.del("members", function(err, reply){
console.log("members set delete :" + reply);
});
But where should I put this code? How to handle the final event from the server when disconnection, from the server side?
Server code - chatroom.js
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var redis = require('redis');
var redisClient = redis.createClient();
io.on('connection', function(client){
console.log("client connected...");
});
io.on('connection', function(client){
client.on('join', function(name){
client.nickname = name;
//adding names
client.broadcast.emit("add member", name);
redisClient.smembers('members', function(err, names) {
names.forEach(function(name){
client.emit('add member', name);
});
});
client.emit('add member', client.nickname)
redisClient.sadd("members", name);
});
// remove clients on disconnect
client.on('disconnect', function(name){
client.broadcast.emit("remove member", client.nickname);
redisClient.srem("members", client.nickname);
});
});
app.get('/', function(req, res){
res.sendFile(__dirname + '/views/index.html');
});
server.listen(8080);
Client code - views/index.html
<html>
<head>
<title>Socket.io Client</title>
<script src="/socket.io/socket.io.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</head>
<body>
<h2>Chat box</h2><br>
<h4 id="status"></h4><br>
<div>
<h3>Active members</h3>
<ul id="members"></ul>
</div>
<script>
var socket = io.connect('http://localhost:8080');
socket.on('connect', function(data){
nickname = prompt("What is your nickname?");
$('#status').html('Connected to Chat Room as \''+nickname+'\'.');
socket.emit('join', nickname);
});
socket.on('add member', function(name) {
var member = $('<li>'+name+'</li>').data('name', name);
$('#members').append(member);
});
socket.on('remove member', function(name) {
$('#members li').filter(function() { return $.text([this]) === name; }).remove();
});
socket.on('disconnect', function(data){
$('#status').html('Chatroom Server Down!');
});
</script>
</body>
</html>
How to clear the redis database set when nodejs server disconnect?
you can use error or end events on redisclient, check the Redis Package Documentation
redisClient.on("error", function (err) {
console.log("Error " + err)
// delete here
});
However, since your connection is closed, it is more healthy to delete on first connection to redis each time. do it on reconnection state too.
When a socket.io connection dies, an event named disconnect is fired. Register your reset logic to that callback.
io.sockets.on('connection', function (socket) {
socket.on('disconnect', function () {
redisClient.del("members", function(err, reply){
console.log("members set delete :" + reply);
});
});
});
Credits : How can i handle Close event in Socket.io?

How to move to Socket.io v1.x from v0.9.x

I have an application under development which uses socket.io to establish Web RTC connections between multiple clients. The application was developed by another developer and I am taking it over for now. One of the things I want to do is move from socket.io v0.9.16 which is being currently used to the most up to date version v1.3.5.
I have looked at the page on migrating from v0.9 to v1.0 and tried changing a few things, however it does not seem to work for me. I am getting the following error in the chrome console:
Failed to load resource: net::ERR_CONNECTION_REFUSED https://143.167.117.93:3000/socket.io/1/?t=1435567474680
indicating that there has been a problem with the socket.io initialisation. The code below shows the way it is being done currently, which works with socket.io v0.9.16.
var protocol = require('https');
var portNo = 3000;
var app = protocol.createServer(options, function (req, res) {
/**
* server serves pages otherwise 404.html
*/
file.serve(req, res, function (err, result) {
if (err) {
console.error('Error serving %s - %s', req.url, err.message);
if (err.status === 404 || err.status === 500) {
file.serveFile(util.format('/%d.html', err.status), err.status, {}, req, res);
} else {
res.writeHead(err.status, err.headers);
res.end();
}
} else {
console.log('serving %s ', req.url);
}
});
}).listen(portNo);
var io = require('socket.io').listen(app, {
log: false,
origins: '*:*'
});
io.set('transports', [
'websocket',
'xhr-polling',
'jsonp-polling'
]);
io.sockets.on('connection', function (socket) {
//Do something
});
If you need any more information to complete this question please let me know. I have limited experience using socket.io and node.js so I apologise if the question is too broad.
Looks like you are not setting correctly socket.io and you are still using some options from socket.io 0.9 version. Try to create a basic example using socket.io migration tutorial, below it is an example of using http node.js library along with socket.io 1.x library.
app.js file:
var protocol = require('http').createServer(handler);
var file = require('fs');
var io = require('socket.io')(protocol);
var portNo = 4040;
protocol.listen(portNo, function() {
console.log('server up and running');
});
function handler(req, res) {
file.readFile(__dirname + '/index.html', function(err, data) {
if (err) {
res.writeHead(500);
return res.send('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
io.on('connection', function(socket) {
socket.emit('message', 'you just connected dude!');
});
index.html file:
<!doctype html>
<html>
<head>
</head>
<body>
<h1>Hello World</h1>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.js">
</script>
<script>
var socket = io.connect();
socket.on('message', function(message) {
alert(message);
});
</script>
</body>
</html>

How to use Express post request to emit Socket.io or Sockjs?

I know this question is kind of awkward, but the problem comes from Samsung TV 2010 / 2011 SmartTV (and blue ray player; of course 2012 emulator working fine). I ported the simple chatting examples come from the source and package to SmartTV app. Both of them fall back to JSONP polling, but from SmartTV app only could emit / push to server once. Receiving the message from server could be multiple times without any problem. After looking for the answer in Samsung D forum (of course nothing there), I think the fastest way to work around this issue is to deploy an Express server, taking the post data and JSON.parse, then emit Socket.io / Sockjs internally inside the server itself.
Could anybody show me an easy sample code so I could start from there? Thanks a lot.
I quickly make code, but seems it doesn't work:
lib/server.js
var express = require('express')
, app = express.createServer()
, io = require('socket.io').listen(app);
app.listen(80);
app.use(express.bodyParser());
app.get('/', function (req, res) {
res.sendfile('/var/www/mpgs_lite_v3/index.html');
});
app.post('/', function(req, res){
console.log(req.body);
io.sockets.emit('my other event', req.body);
res.redirect('back');
});
io.sockets.on('connection', function (socket) {
//socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
index.html
<html>
<head>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost');
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
</script>
</head>
<body>
<form method="post" action="/">
<input type="hidden" name="_method" value="put" />
<input type="text" name="user[name]" />
<input type="text" name="user[email]" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
'my other event' seems not receive anything.
UPDATE: I updated the example for you to make it more complete. I didn't have an app.listen before, and here is also a client side script which shows that it, indeed, works fine:
<!doctype html>
<html>
<head>
<script src="//www.google.com/jsapi"></script>
<script src="/socket.io/socket.io.js"></script>
<script>google.load("jquery", "1.7.1")</script>
<script>
var socket = io.connect("localhost", {port: 3000});
socket.on("foo", function(message) { console.log("foo: ", message) });
$(function() {
$("button").click(function() {
$.post("/foo", { message: $("input").val() });
});
});
</script>
</head>
<body>
<input type=text>A message</input>
<button>Click me!</button>
</body>
</html>
And the server, now with an app.listen directive:
var express = require("express"),
app = express.createServer(),
io = require("socket.io").listen(app)
index = require("fs").readFileSync(__dirname + "/index.html", "utf8");
app.use(express.bodyParser());
app.get("/", function(req, res, next) {
res.send(index);
});
app.post("/foo", function(req, res, next) {
io.sockets.emit("foo", req.body);
res.send({});
});
app.listen(3000);
Usage:
node app.js
Navigate to http://localhost:3000/ and click the button. Check your console for output.
Based on SockJS express example server.js could look like:
var express = require('express');
var sockjs = require('sockjs');
// 1. Echo sockjs server
var sockjs_opts = {sockjs_url: "http://cdn.sockjs.org/sockjs-0.2.min.js"};
var sockjs_echo = sockjs.createServer(sockjs_opts);
connections = {};
sockjs_echo.on('connection', function(conn) {
console.log(conn.id);
connections[conn.id] = conn
conn.on('close', function() {
delete connections[conn.id];
});
// Echo.
conn.on('data', function(message) {
conn.write(message);
});
});
// 2. Express server
var app = express.createServer();
sockjs_echo.installHandlers(app, {prefix:'/echo'});
console.log(' [*] Listening on 0.0.0.0:9999' );
app.listen(9999, '0.0.0.0');
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
app.post("/send", function(req, res, next) {
for(var id in connections) {
connections[id].write('received POST');
}
res.send({});
});
To test open browser at localhost:9999 and run:
curl localhost:9999/send -X POST
just remove this comment
//socket.emit('news', { hello: 'world' });
to
socket.emit('news', { hello: 'world' });
it will work because its emiting data through news and you are listening using my other event instead of 'news' or you can do just listen using 'my other event'
I don't know if this would help, but you can make an emit abstraction on the client based on your browser and then make a separate get function on the server that will handle the request the same way as the socket.on callback. In order to know where to send the information I suggest you use some key that you can store in a hash table in the server and local storage on the client.
For the client:
var emit = function(event, options) {
if ("WebSocket" in window) {
socket.emit(event, options);
console.log("emited via WebSocket");
} else {
$.post("http://localhost/emit/" + event, options);
console.log("emited via AJAX");
}
}
emit("echo", {
key: localStorage.getItem("key"),
data: {
hello: "world"
}
});
socket.on("response", function(data) {
console.log(data.hello); //will print "world"
});
For the server:
var sockets = {};
var echo_handler = function(a) {
var socket = sockets[a.key];
var data = a.data;
socket.emit("response", data);
}
app.post("/emit/:event", function(req, res) {
var event = req.params.event;
switch (event) {
case "echo":
var a = {
key: req.param("key"),
data: req.param("data")
}
echo_handler(a);
break;
}
});
io.sockets.on("connection", function(socket) {
socket.on("connect", function(data) {
sockets[data.key] = socket;
});
socket.on("echo", echo_handler);
});
Another way to do this will be to switch to Sockjs and use their patch.
If someone have better solution for Socket.IO it will be appreciated, because I'm already deep into the project and it's too late to switch Socket.IO for Sockjs, and this solution is not to my liking :( .

Resources