I am using Passport js with Express and am confused about getting the current user's details within different components of the app.
I would like to get the username and put it into an array when a user connects to a socket. In my server.js, I am requiring my routes and socket.io file.
require('./app/routes.js')(app, passport);
require('./app/sockets.js').listen(server, passport);
In my socket.js file I am having some events when the user connects.
var users = [];
exports.listen = function(server, passport){
var socketio = require('socket.io');
io = socketio.listen(server);
io.on('connection', function(socket){
users.push({
id: socket.id
});
socket.emit('new user', socket.id);
console.log('user count: ' + io.engine.clientsCount);
console.log('users length: ' + users.length);
socket.on('send message', function(message){
if (/\S/.test(message)) {
io.sockets.emit('new message', message);
console.log('new message: ' + message);
}
});
socket.on('disconnect', function(socket){
console.log('user disconnected: ' + users.length);
users.splice(users.indexOf(socket.id), 1);
});
});
};
I can get the username inside the routes file and pass it onto the view. I am confused about how to get a details from the session with a file that doesn't have a request. such as:
app.get('/chat', isLoggedIn, function(req, res){
res.render('chat.ejs',{
user : req.user // get the user out of session and pass to template
});
});
The passport.socketio project on GitHub may be the solution.
Related
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/chat.html');
});
server.listen(8000, () => {
console.log('listening on *:8000');
});
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('disconnect', () => {
console.log('user disconnected');
});
});
io.on('connection', (socket) => {
socket.on('chat message', (msg) => {
console.log('message: ' + msg);
});
});
io.emit('some event', { someProperty: 'some value', otherProperty: 'other value' }); // This will emit the event to all connected sockets
io.on('connection', (socket) => {
socket.on('chat message', (msg) => {
io.emit('chat message', msg);
});
});
Currently it's localhost, and I have to run node index.js everytime I want to start it. But is there a way I can host it on GitHub so it always stays on?
Short answer: No.
GitHub hosts git repositories containing code, but doesn't run code. GitHub pages can serve static sites, but cannot run server side code, which include node.js and express. If you want to host something like this for free, I suggest looking into Heroku.
How to solve this? I don't get it,,please help, thanks. And this is the error message when I run node server.js:
client.on('getRelay', function (state) {
ReferenceError: client is not defined
var express = require ('express');
var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var port = 3000;
let bodyRelay = {
relayId: 'RELAY-123',
state: 1
}
app.use(express.static(__dirname + '/node_modules'));
app.get('/', function(req, res, next) {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(client) {
console.log('a user has connected');
});
io.sockets.emit('setRelay', bodyRelay);
client.on('getRelay', function (state) {
bodyRelay = state;
console.log('id: ' + client.id + 'bodyRelay: ' + JSON.stringify(bodyRelay));
// io.sockets.emit('setRelay', bodyRelay);
});
client.on('disconnect', function() {
console.log('a user has disconnected');
});
server.listen(port, () => {
console.log('Server is running on port: ' + port)
});
The blocks of code that reference client, must be inside this callback:
io.on('connection', function(client) {
console.log('a user has connected');
});
because that is where client is defined. Like this:
io.on('connection', function(client) {
console.log('a user has connected');
client.on('getRelay', function (state) {
bodyRelay = state;
console.log('id: ' + client.id + 'bodyRelay: ' + JSON.stringify(bodyRelay));
// io.sockets.emit('setRelay', bodyRelay);
});
client.on('disconnect', function() {
console.log('a user has disconnected');
});
});
A few other notes on your code.
The location you have this:
io.sockets.emit('setRelay', bodyRelay);
does not make any sense because you're calling it when you initialize the module which will NEVER have any connected socket.io clients so it will not do anything useful.
And, the way you are using the bodyRelay variable seems like a possible design error. You've made it a module-level variable which means it is shared among all request handlers for all connections. Unless this is intended to be something that all clients can change and all clients access the exact same set of data, then it perhaps needs a different design. I don't know what you're really trying to do with it to know what design to suggest.
user can access namespace like nsp1 by hitting localhost:3000/nsp1
the same with nsp2, I want to create them dynamically with a name entered from text box
but for now I tried to make just one namespace using code below but the server hits error Cannot GET /my-namespace
server.js
var io = require('socket.io')(http, { path: '/my-namespace'});
io
.of('/my-namespace')
.on('connection', function(socket){
console.log('a user connected with id %s', socket.id);
socket.on('my-message', function (data) {
io.of('my-namespace').emit('my-message', data);
// or socket.emit(...)
console.log('broadcasting my-message', data);
});
});
client.js
var socket = io('localhost:3000/my-namespace', { path: '/my-namespace'});
server.js
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
server.listen(3000);
app.get("/contact.html", function (req, res) {
res.sendfile(__dirname + '/contact.html');
});
app.get("/login.html", function (req, res) {
res.sendfile(__dirname + '/login.html');
});
app.get("/", function (req, res) {
res.sendfile(__dirname + '/home.html');
});
app.get(/(^\/[a-zA-Z0-9\-]+$)/, function (req, res) {
//Matches anything with alphabets,numbers and hyphen without trailing slash
res.sendfile(__dirname + '/room.html');
});
io.on('connection', function(socket){
console.log('a user connected with id %s', socket.id);
socket.on('join', function (room) {
//May be do some authorization
socket.join(room);
console.log(socket.id, "joined", room);
});
socket.on('leave', function (room) {
//May be do some authorization
socket.leave(room);
console.log(socket.id, "left", room);
});
socket.on('chat message', function (data) {
//May be do some authorization
io.to(data.room).emit("chat message", data.message);
});
});
room.html/client.js
var socket = io('localhost:3000');
socket.emit("join",location.pathname);
socket.emit("chat message",{room:location.pathname, message:<val>});
In my express's route I do this
var cookie = require('cookie');
var server = require("http").Server(express);
var io = require("socket.io")(server);
server.listen(5000);
io.on('connection', function(client) {
console.log('socket connected') // returned socket connected
if(client.request.headers.cookie){
console.log(userId) //returned userId
var userId = cookie.parse(client.request.headers.cookie).userId;
client.on('call_'+userId, function(data) {
io.emit('call_'+userId,data);
});
}
});
router.use(function(req, res, next){
if(!req.user){
res.redirect('/login');
}else{
res.locals.username = req.user.username;
//set cookie for socket.io purposes
if(!cookie.parse(req.headers.cookie).userId){
res.cookie('userId',querystring.escape(req.user._id));
}
return next();
}
});
router.get('/', function(req, res, next) {
res.redirect('./dashboard');
});
and I try to do an emit to port 5000, it worked. But it only work after I refresh the page after login, it doesn't work when I first come to dashboard's page. I've tried to see if the socket is connected upon login, and I did see it's connected.
Why it only for after I refresh? What's the issue?
I'm new to nodejs and socket io thing, but I'm really trying to understand how this works. I've already completed the "chat tutorial" from the socket io website. However, I'm trying to do something "new" here. Each time a new connection is established, I want to broadcast an event to all clients, by appending a new tab with a random number. However, the only things that happens, is that it appends once (on my own connection) but nothing to others? Is this not possible, or am i just doing it the wrong way?
Server,
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.use("/assets/stylesheets", express.static(__dirname + '/assets/stylesheets'));
app.use("/assets/javascripts", express.static(__dirname + '/assets/javascripts'));
app.use("/assets/demo/avatars", express.static(__dirname + '/assets/demo/avatars'));
app.use("/assets/fonts/font-awesome/", express.static(__dirname + '/assets/fonts/font-awesome/'));
app.get('/dashboard', function(req, res){
res.sendFile(__dirname + '/dashboard.html');
});
io.on('connection', function(socket) {
socket.on('new user', function(username) {
socket.emit('new connection', { nickname: username });
console.log('new connection ' + username);
});
});
http.listen(3000,function() {
console.log('Listening *:3000');
});
Client,
<script type="text/javascript">
var randomNumber = Math.floor((Math.random() * 10) + 1);
var socket = io();
socket.on('connect', function() {
socket.emit('new user', randomNumber);
});
socket.on('new connection', function(data) {
var nickname = data.nickname;
$('<li class="active"> ' + nickname + '<span class="label label-success">12</span> </li>').appendTo("#uidemo-tabs-default-demo");
});
</script>
You need to keep a list of all the open connections on the server and then, when a new connection occurs, send messages to all the other connections.
Here is modified code
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var connections = [];
app.use("/assets/stylesheets", express.static(__dirname + '/assets/stylesheets'));
app.use("/assets/javascripts", express.static(__dirname + '/assets/javascripts'));
app.use("/assets/demo/avatars", express.static(__dirname + '/assets/demo/avatars'));
app.use("/assets/fonts/font-awesome/", express.static(__dirname + '/assets/fonts/font-awesome/'));
app.get('/dashboard', function(req, res){
res.sendFile(__dirname + '/dashboard.html');
});
io.on('connection', function(socket) {
socket.on('new user', function(username) {
connections.forEach(function (socket) {
try {
socket.emit('new connection', { nickname: username });
} catch (err) {
console.log('connection probably closed: ', err);
}
});
console.log('new connection ' + username);
connections.push(socket);
});
});
http.listen(3000,function() {
console.log('Listening *:3000');
});
However, be aware that this will only work if your Node.js server only has one instance (i.e. you are not using the cluster module), more work will be required to get it to work in a cluster and even more if it must work in a redundant infrastructure.
You have to use socket.broadcast.emit to broadcast..
socket.on('new user', function(username) {
socket.broadcast.emit('new connection', { nickname: username });
console.log('new connection ' + username);
});
However this will not send the message to your own connection but to all other connections. If you want to send the message to all connections including yourself,
socket.on('new user', function(username) {
socket.emit('new connection', { nickname: username });
socket.broadcast.emit('new connection', { nickname: username });
console.log('new connection ' + username);
});