I am building a real-time notification system using socket.io. This is my server-side code at the moment:
bin/www:
var app = require('../app');
var server = http.createServer(app);
var io = app.io
io.attach(server);
server.listen(port, function(err) {
if (err) console.log(err);
console.log('Listening on port ' + port + '...');
});
app.js:
var socket_io = require('socket.io');
var express = require('express');
var app = express();
var io = socket_io();
app.io = io;
require('./config/socket')(app.io);
config/socket.js:
var User = require('../controllers/user');
module.exports = function (io) {
io.on('connection', function (socket) {
console.log('Socket.io connected');
socket.emit('connection', "Connection created.");
socket.on('send notification', function(data) {
User.createNotification(socket.request.user, data);
});
});
};
routes/index.js:
var express = require('express');
var User = require('../controllers/user');
var router = express.Router();
router.post('/order', User.order);
module.exports = router;
controllers/user.js:
var User = require('../models/user').model;
var io = require('socket.io');
module.exports = {
order: function(req, res) {
/* some create order code */
io.emit('send notification', 'Your order was successful!');
res.sendStatus(200);
}
}
I keep getting the error TypeError: io.emit is not a function whenever I try to call the route POST /send even though I am clearly initiating socket.io in my app.js and bin/www files and requiring it in controllers/user.js. All the examples I've seen online emit notifications from within this part:
io.on('connection', function (socket) {
socket.emit(event, msg);
});
but I want my notifications to be triggered from the middleware so I can send custom notifications to the user when certain events happen in the application backend.
Try the following instead:
io.on('connection', function(socket){
socket.on('xxx', function(obj){
io.emit('xxx', {xxx: xxx})
})
})
This should suppress your TypeError:.
Related
I want to initialize my socket inside a route and according to documents I have to pass server instance to my socket. I have a separate server.js file like this:
var app = require('./app');
var http = require('http');
var port = '2002';
app.set('port', port);
var server = http.createServer(app);
server.listen(port, function(err){
if(err)
console.log(err);
else
console.log('Server listening on port : ' + port);
});
module.exports = server;
and my router:
var express = require('express');
var server = require('../server');
var router = express.Router();
var io = require('socket.io')(server);
router.get('/', function(req, res, next){
res.render('index');
});
router.post('/', function(req, res, next){
io.on('connection', function(socket){
socket.emit('server emit', { hello: 'server emit' });
socket.on('client emit', function (data) {
console.log("Server received : " + data);
});
});
});
module.exports = router;
and my client script:
var socket = io('http://localhost:2002');
socket.on('connect', function() {
socket.on('server emit', function(data) {
console.log('inside eventtt');
console.log(data);
});
});
But I face this error in my browser console:
socket.io-1.4.5.js:1 GET http://localhost:2002/socket.io/?EIO=3&transport=polling&t=LPajDxI
I think the problem is due to wrong initialization of my socket on the server side, but I don't know how to handle the problem.
I am working with socket.io , so i created server on app.js and connect socket to client and i see emit('message') is printing to the client console, Now i want to send another message from different file consumer.js and emit message to client but its throwing exception on server side io.on is not a function. Any idea what is implemented wrong in consumer.js file ?
app.js
var express = require('express');
var app = express();
var consumer = require('./consumer');
var server = require('http').createServer(app);
var io = require('socket.io')(server);
app.use(express.static(__dirname + "/public"));
io.on('connection', function(client) {
console.log('Client connected...');
client.emit('message', ' hello from server');
});
server.listen(3000, function () {
console.log('Example app listening on port 3000!');
consumer.start();
});
consumer.js
var io = require('socket.io');
function startConsumer(consumer) {
consumer.on('message', function (message) {
logger.log('info', message.value);
io.on('connection', function(client) {
console.log('Consumer connected...');
client.emit('Consumer-Message', 'Message from dit consumer');
});
});
consumer.on('error', function (err) {
console.log('error', err);
});
};
exports.start = start;
angularCtrl.js
socket.on('message',function (data) {
console.log(data);
});
socket.on('Consumer-Message',function (data) {
console.log(data);
});
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)
})
in a node.js app, let's say i have a app.js like this
var express = require('express')
var app = express();
var server = http.createServer(app);
...
module.exports = {
app:app,
server:server
}
also, there is /lib/sockets.js, where all the logic of socket.io should go in. It looks like this:
var server = require('../app.js').server;
var io = require("socket.io").listen(server);
io.sockets.on('connection', function(socket) {
socket.on('event', function(msg) {
socket.emit('news', msg});
});
});
module.exports = io;
Is it good practice to require the server from app.js here? If not, what would be a better solution? thx
Try having your sockets.js file export a function. Then require the sockets file in your app.js and pass in any relevant arguments.
In your lib/sockets.js:
module.exports = function(server){
var io = require("socket.io").listen(server);
io.sockets.on('connection', function(socket) {
socket.on('event', function(msg) {
socket.emit('news', msg);
});
});
return io;
};
And in your app.js
var express = require("express");
var app = express();
var io = require("./lib/sockets")(app);
How would I set up a MongoDB database connection with node.js?
Here is my app.js file:
var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server);
server.listen(3000);
app.get('/', function(req, res) {
res.sendfile(__dirname + '/index.htm');
});
app.use(express.static(__dirname + '/assets'));
io.sockets.on('connection', function(socket) {
socket.on('send message', function(data) {
io.sockets.emit('new message', data);
});
});
I have already set-up MongoDB and have it running as a service on Windows.
As of 1.2, the recommended way to perform a connection is in documentation:
http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html
excerpt:
var MongoClient = require('mongodb').MongoClient
, Server = require('mongodb').Server;
var mongoClient = new MongoClient(new Server('localhost', 27017));
mongoClient.open(function(err, mongoClient) {
var db1 = mongoClient.db("mydb");
mongoClient.close();
});
You may find that a connection singleton is useful for the current state of the official node.js driver. Below is some sample code that I use:
connection.js module:
var MongoClient = require('mongodb').MongoClient;
var db_singleton = null;
var getConnection= function getConnection(callback)
{
if (db_singleton)
{
callback(null,db_singleton);
}
else
{
//placeholder: modify this-should come from a configuration source
var connURL = "mongodb://localhost:27017/test";
MongoClient.connect(connURL,function(err,db){
if(err)
log("Error creating new connection "+err);
else
{
db_singleton=db;
log("created new connection");
}
callback(err,db_singleton);
return;
});
}
}
module.exports = getConnection;
Referencing module:
var getConnection = require('yourpath/connection.js')
function yourfunction()
{
getConnection(function(err,db)
{
//your callback code
}
.
.
.
}