I'm trying to call a socket.on() event from an external .js file and I can't figure out what I'm missing...
I'm using NodeJS with ExpressJS.Below are the files:
app.js(the server file)
const fs = require('fs');
const express = require('express');
const app = express();
const http = require('http').Server(app);
var io = require('socket.io')(http);
....
//Socket Io functions
const ioObj = require( './library/io.js')(app, express, io);
// This route will be used to print the type of HTTP request the particular Route is referring to
router.use(function (req, res, next) {
console.log("/" + req.method);
next();
});
....
/library/io.js (sockets file)
module.exports = function(app, express, io){
io.on('connection', async function(socket) {
socket.on('refreshPage', function(){
console.log("page should now be refreshed !!");
socket.emit("refreshPageNow");
});
....
});
}
What I'm trying to do is to call/access the refreshPage event from /library/io.js so I can send further a "refresh webpage" signal.
I tried to do something like :
io.sockets.emit("refreshPage");
and
ioObj.sockets.emit("refreshPage");
But didn't work...
Related
I have an existing project written in Express, where I've made a messaging system. Everything was working on POST/GET methods (to send and receive the messages).
I wanted to make them appear in real time, so I installed socket.io both on the client and server side. In my server.js I added these lines:
const http = require("http");
const io = require("socket.io");
const server = http.createServer();
const socket = io.listen(server);
and changed my app.listen(...) into server.listen(...).
Added also:
socket.on("connection", socket => {
console.log("New client connected");
socket.on('test', (test) => {
console.log('test-test')
});
socket.emit('hello', {hello:'hello!'});
socket.on("disconnect", () => console.log("Client disconnected"));
});
On the front part I put such code in the componentDidMount method:
const socket = socketIOClient();
socket.emit('test', {test:'test!'})
socket.on('hello', () => {
console.log('aaa')
})
Now I got 2 problems. Although the console.log() works correctly, I get an error on the React app:
WebSocket connection to 'ws://localhost:3000/sockjs-node/039/lmrt05dl/websocket' failed: WebSocket is closed before the connection is established.
Is that normal?
Also, when I change app.listen(...) into server.listen(...) in the server.js file, my routing stops working. All the POST and GET methods don't work, because the server is responding endlessly. Is that possible to use the socket.io just on a specific method in a specific routing file?
I keep my routes that way: app.use('/api/user', user); where user is a router file.
UPDATE:
full server.js require:
const express = require('express');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const bodyparser = require('body-parser');
const passport = require('passport');
const user = require('./routes/api/v1/User');
const company = require('./routes/api/v1/Company');
const http = require("http");
const io = require("socket.io");
const app = express();
dotenv.config();
app.use(passport.initialize());
require('./config/seed');
require('./config/passport')(passport);
const server = http.createServer();
const socket = io.listen(server);
You're not initializing server properly. Try making the following change
// const server = http.createServer();
const server = http.createServer(app);
and make sure you listen on server and not io
server.listen(PORT_GOES_HERE)
[UPDATE]
Working Example:
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
server.listen(80);
// WARNING: app.listen(80) will NOT work here!
// DO STUFF WITH EXPRESS SERVER
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
For more details check this: https://socket.io/docs/
I'm trying to use Socket.io combined with Express.JS (using Express application generator).
I've found some aswers how to do this (Using socket.io in Express 4 and express-generator's /bin/www).My problem is that i cannot make use of the sockets inside the routes folder.
I can use them in the app.js and bin/www.js files. When i call the route index.js it just keeps loading the webpage for a long time without giving any errors.
bin/www.js
...
/**
* Create HTTP server.
*/
var server = http.createServer(app);
var io = app.io
io.attach( server );
...
app.js
...
// Express
var app = express();
// Socket.io
var io = socket_io();
app.io = io;
var routes = require('./routes/index')(io);
...
routes/index.js
module.exports = function(io) {
var app = require('express');
var router = app.Router();
io.on('connection', function(socket) {
console.log('User connected');
});
return router;
}
Here is a simple example on how to use Socket.io with Express that I made available on GitHub here:
https://github.com/rsp/node-websocket-vs-socket.io
The backend code is this:
var path = require('path');
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', (req, res) => {
console.error('express connection');
res.sendFile(path.join(__dirname, 'si.html'));
});
io.on('connection', s => {
console.error('socket.io connection');
for (var t = 0; t < 3; t++)
setTimeout(() => s.emit('message', 'message from server'), 1000*t);
});
http.listen(3002, () => console.error('listening on http://localhost:3002/'));
console.error('socket.io example');
See https://github.com/rsp/node-websocket-vs-socket.io/blob/master/si.js
As you can see here, I am creating the express app with:
var app = require('express')();
Then I create an http server with that app with:
var http = require('http').Server(app);
And finally I use that http server to create the Socket.io instance:
var io = require('socket.io')(http);
After running:
http.listen(3002, () => console.error('listening on http://localhost:3002/'));
it all works together.
You can see the entire example on GitHub with both backend and frontend code that works. It currently uses Express 4.14.0 and socket.io 1.4.8.
For anyone who still want to use socket.io and express http request. Easiest way is to create two seprate instance of http server listing to different ports. 1 for websockets and 2nd for api requests.
const express = require("express");
const app = express();
const httpServer = require("http").createServer(app);
const io = require("socket.io")(httpServer, {
path: '/'
});
// routes and io on connection
httpServer.listen(5000, () => {
console.log("Websocket started at port ", 5000)
});
app.listen(3000, () =>{
console.log("Http server listening at", 3000)
})
I'm trying to use simplewebrtc in my app, I already have a simple nodejs server with express web framework. But to use simpleWebrtc we have to install signal master. I'm looking at the source code for the server.js file in the signal master package but I can't figure out how to combine this server.js with my already existing app.js file. This is basically my app.js
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var mongoose = require('mongoose');
var favicon = require('serve-favicon');
var bodyParser = require('body-parser');
app.get('/', function(req, res) {
res.sendFile(__dirname + '/index.html');
console.log("connected to index");
});
and this is server.js of signalMaster
/*global console*/
var yetify = require('yetify'),
config = require('getconfig'),
uuid = require('node-uuid'),
crypto = require('crypto'),
fs = require('fs'),
port = parseInt(process.env.PORT || config.server.port, 10),
server_handler = function (req, res) {
res.writeHead(404);
res.end();
},
server = null;
// Create an http(s) server instance to that socket.io can listen to
if (config.server.secure) {
server = require('https').Server({
key: fs.readFileSync(config.server.key),
cert: fs.readFileSync(config.server.cert),
passphrase: config.server.password
}, server_handler);
} else {
server = require('http').Server(server_handler);
}
server.listen(port);
var io = require('socket.io').listen(server);
if (config.logLevel) {
// https://github.com/Automattic/socket.io/wiki/Configuring-Socket.IO
io.set('log level', config.logLevel);
}
etc, etc you can look at the rest by downloading the zip. I thought it would be just replacing server with http, but the server=null doesn't really make sense. All the dependencies are in the directory of the signalMaster unzipped file. I was reading about signalMaster here.
You will need something like this
var os = require('os');
var static = require('node-static');
var http = require('http');
var socketIO = require('socket.io');
var fileServer = new(static.Server)();
var app = http.createServer(function (req, res) {
fileServer.serve(req, res);
}).listen(2013);
var io = socketIO.listen(app);
io.sockets.on('connection', function (socket){
...
socket.on('join', function (message) {
...
}
...
}
i hope this help u
I have loads of router.get functions in my code which I think, could be reduced to a single switch-case function. Here is what I have tried:
function handlerA(req, res) {}
function handlerB(req, res) {}
var routes = {
'/url-one': handlerA,
'/url-two': handlerB
}
router.get('/*', function(req, res) {
var url = req.url;
if (routes[url]) {
routes[url](req, res);
}
});
This works but also, significantly slows my application. Is there any other solution which would not hit the performance of my app?
Thanks
Is there a reason you don't want to use router.get functions? I would guess express.js is internally performing the same logic that you are doing anyway. You are just replacing get functions with handlers.
If you are using similar logic between multiple routes, that may be worth abstracting.
I usually go with a setup like this:
app.js
routes.js
api/
user/
index.js
user.controller.js
user.model.js
image/
index.js
image.controller.js
image.model.js
/api/user/index.js:
var express = require('express');
var controller = require('./user.controller');
var router = express.Router();
router.get('/', controller.index);
router.post('/', controller.create);
module.exports = router;
/api/user/user.controller.js:
var User = require('./user.model');
exports.index = function(req, res) {
// Show list of users
};
exports.create = function (req, res, next) {
// Create user
};
/routes.js:
module.exports = function(app) {
// Insert routes below
app.use('/api/users', require('./api/user'));
app.use('/api/images', require('./api/image'));
// All undefined asset or api routes should return a 404
app.route('/:url(api|auth|components|app|bower_components|assets)/*')
.get(errors[404]);
// All other routes should redirect to the index.html
app.route('/*')
.get(function(req, res) {
res.sendfile(app.get('appPath') + '/index.html');
});
};
And lastly, the /app.js:
// Set default node environment to development
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var express = require('express');
var mongoose = require('mongoose');
var config = require('./config/environment');
// Connect to database
mongoose.connect(config.mongo.uri, config.mongo.options);
// Populate DB with sample data
if(config.seedDB) { require('./config/seed'); }
// Setup server
var app = express();
var server = require('http').createServer(app);
require('./config/express')(app);
require('./routes')(app);
// Start server
server.listen(config.port, config.ip, function () {
console.log('Express server listening on %d, in %s mode', config.port, app.get('env'));
});
// Expose app
exports = module.exports = app;
Most of this is directly from the Yeoman Generator Angular-Fullstack and it has a really nice setup!
I'm trying to modularize my application files and I'm having problems with Socket.io. I would like to use the io inside my routes.js. Something like this:
var router = require('express').Router();
var io = require('./sockets/my-io');
router.get('/', function(req, res) {
io.emit('request-detected');
});
module.exports = router;
But I can't do, because the socket.io needs the app server, and when I'm inside the routes.js file, the app server is not listening or being exported yet.
Can you give me a solution, or any other approach to this problem?
Here's what I have, and if it's possible, I would like to keep the file structure:
app.js
var app = require('express')();
var routes = require('./routes');
/* ... */
app.use('/contacts', routes);
module.exports = app;
bin/www
#!/usr/bin/env node
var app = require('../wallet');
var server = app.listen(port, function() {
debug('Express is listening o port ' + port);
});
routes.js
var router = require('express').Router();
router.get('/', function(req, res) {
console.log('hey');
});
module.exports = router;
You can do it by passing the io variable to your routes module.
bin/www
#!/usr/bin/env node
var app = require('./app');
var server = app.listen(3000, function() {
console.log('Express is listening on port 3000');
}); // start the server
var socket = require('./socket')(server); // require socket.io code
var routes = require('./routes')(socket); // require routes
app.use('/', routes);
app.js
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.set('views engine', 'ejs');
app.set('views', __dirname + '/');
module.exports = app;
socket.js
var socketio = require('socket.io');
function init(server) {
var io = socketio(server);
io.on('connection', function (socket) {
console.log("socket connected");
socket.on('newEvent', function (data) {
console.log(data);
});
});
return io;
}
module.exports = init;
routes.js
var express = require('express');
var route = express.Router();
function init(io) {
route.get('/', function (req, res) {
res.render('index.ejs', {});
setTimeout(function() {io.emit('newEvent', {message: "Hi from the server"})}, 2000);
});
return route;
}
module.exports = init;
The code above worked for me. However, I'm not sure why you want to do that.
Inside the router, you still have full control of what you want to send to the user via html, so you can just add the data to the html directly.
The idea of socket.io is that you can send data between the client and back once he has loaded the html and established a connection to your server with socket.io.
As you can see in the routes.js, I had to add a timeout to the emit. This is because the socket event will be emit before the browser has reloaded the page. In my case the browser logged the event and then immediately refreshed, losing the data you just sent.
Another problem is that you don't know anything about the socket of the client that is requesting the page because he hasn't connected yet. This means that calling io.emit() will send the event to all connected sockets.
As I said, this really depends on what exactly you want to do.
EDIT:
Instead of updating your contacts using ajax, you can do that with socket.io.
socket.js
var socketio = require('socket.io');
function init(server) {
var io = socketio(server);
io.on('connection', function (socket) {
console.log("socket connected");
socket.on('newContact', function (data, callback) {
// add data.contactName to db
// after adding something, you use the callback to
// send the added data back to the client
// callback(newContact);
});
});
return io;
}
module.exports = init;
index.html
<script type="text/javascript" >
var socket = io();
// call this emit when the user wants to add a contact
socket.emit('newContact', {contactName: name}, function(newContact) {
// here you will get the result from the server and you can
// update the html with jquery for example
});
</script>
If i understand your question correctly ,maybe you can try this way.
in your routes.js file
var app = require('./app');
var server = require('http').createServer(app);
var io = require('./sockets/my-io')(server);
var route = app.Router();
in your app.js file
var port = process.env.PORT || 3000;
app.listen(port,function(){
console.log('server on port ' + port)
})