Please excuse any noobiness, I'm learning. :)
I have Socket.IO set up so that I can use io.sockets.emit inside of my routes, and I have that working. There are a few problems.
(SOLVED? SEE EDIT 3) To use, I cannot start with the word
socket
. I have to start withio
or I get "ReferenceError: socket is not defined." I'd like to be able to usesocket.broadcast.emit
to emit the event to all clients except for the current user. Right now I'm having to do a check on the client side to not execute the event if it's the current user and it's becoming a real headache as I'm having to emit more events as my project progresses.(SOLVED, SEE EDIT 1 & 2) I have to run the application with
node app.js
and restart the server manually every time I make a server-side change. When I run nodemon, I get "Port 3000 is already in use." I feel that this must be related to the following...(SOLVED, SEE EDIT 2) When pushing to Heroku, I have the port from the code below changed from 3000 to 80 in bin/www and app.js, but it does not work (I can see a 404 error for sockets in the console). If this and #2 are caused by dealing with http/ports in both places, how do I properly set this up and why does
node app.js
work?I only need to run Socket.IO on the route shown below (battlefield). Am I already doing this with am I already doing this with
require('./routes/battlefield')(io)
?
bin/www
var app = require('../app');
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
var server = http.createServer(app);
server.listen(port);
app.js
var app = express();
var http = require('http').Server(app);
http.listen(3000);
var io = require('socket.io')(http);
app.set('socketio', io);
var battlefield = require('./routes/battlefield')(io);
battlefield.js
var express = require('express');
var router = express.Router();
var returnRouter = function(io) {
router.get('/', function(req, res, next) {
// other stuff
io.sockets.emit('message', 'This works');
socket.broadcast.emit('message', 'Socket is undefined');
})
return router;
};
module.exports = returnRouter;
I tried wrapping my routes in io.on('connection', function (socket) {
to be able to use socket
, and instead of 'Socket is undefined,' the event does not occur.
var returnRouter = function(io) {
io.on('connection', function (socket) {
router.get('/', function(req, res, next) {
// other stuff
socket.emit('message', 'This is never emitted');
})
})
return router;
};
I apologize for such a lengthy question. THANK YOU for any help!
EDIT1: Writing out this question helped me understand the problem better. I commented out server.listen(port);
in my bin/www and nodemon now works. However, the app crashes on Heroku. My Procfile is web: node ./bin/www
... does that need to be changed?
EDIT2: After figuring out Edit1 and a bit of Googling, I found that I can't have server.listen();
(bin/www) and http.listen(3000);
(app.js).
In bin/www, I removed server.listen();
.
In app.js, for clarity's sake I changed var http = ... to var server = ... and had it listen for process.env.PORT || '3000';
, taken from bin/www. I also removed app.set('socketio', io);
because it looks like that was doing nothing... I wonder why it was in there.
app.js
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var port = process.env.PORT || '3000';
server.listen(port);
This also makes Heroku work because of process.env.PORT
, hurray! I'm guessing node app.js
worked because I was initializing the app with app.js, I guess bin/www is not executed when you do that?
I still need help with #1 (using socket.broadcast.emit) .
EDIT 3: Well, it took me literally the entire day but I believe I have it figured out with one quirk. Of course I couldn't use socket
, it is a parameter given on connect. I also need to access socket across different routes and found this SO question. This is what I ended up doing in battlefield.js:
var returnRouter = function(io) {
var socket;
router.get('/', authenticatedUser, function(req, res, next) {
io.on('connection', function(client){
socket = client;
});
// other stuff
res.render('battlefield', {/* data */});
setTimeout(function(){socket.emit('test', 'It works!')}, 500);
});
router.post('/', function(req, res, next) {
// socket can be accessed
});
return router;
};
module.exports = returnRouter;
(Note: I took out a lot of my own code so I don't know if this is copy and pasteable ready, and you should probably check that socket is not null)
Without setTimeout
, socket is undefined on GET '/'. To my understanding, the page must render first... Strange that 200 sometimes doesn't work for me and 500 does. I can leave it at 500, but this is for a game so time is pretty important.
My questions now are:
Can this be improved / is there a way I can do this without setTimeout? Am I 'connecting' clients properly with this code and am I (question #4 up there^) using Socket.IO efficiently?
P.S. If no one answers ^ these questions, I'll edit this, answer the question, and accept my answer as best answer.