Cannot access io object in session.socket.io - node.js

I am using session.socket.io for my app
o = require('socket.io').listen(tmpServer),
appCookieParser = express.cookieParser(settings.cookie.secret),
appRedisStore = new RedisStore(),
sessionIO = new SessionSockets(io, appRedisStore, appCookieParser
App.app.use(appCookieParser)
App.app.use(express.session({
store: appRedisStore
}))
Note that App is a global variable which holds some of my app data and some helper functions, as I followed the LearnAllTheNodes application structure.
Then I define the callback on connection
sessionIO.on('connection', socketHandler)
where socketHandler is a function returned by a require call.
module.exports = function(err, socket, session) {
console.log(io.sockets.clients('a'))
socket.join('a')
console.log(io.sockets.clients('a'))
}
According to the documentation I should have access to my io object, but I am always getting the error that io is not defined.
Note that if I am emitting some events or listening for some events in the sockatHandler I am getting/sending them properly. Just I have no access to io.
UPDATE
It turns out it works perfectly if I am implementing the callback function as an anonymous function. The documentation is confusing, it should be: you can use io if you have a reference to it.

You seem to have forgotten to define io which here should be the listener.
According to the code you display, you should probably have something like
var app = express();
var server = http.createServer(app);
var io = socketio.listen(server);
Here's an example of a complete application using express, socket.io and session.socket.io.

To make my app less crowded I've updated the socketHandler so it takes all my socket related objects
socketHandler(sessionIO, io)
and I am handling the socket operations in another module via these objects.

Related

I'm trying to access socket.io in an express-generator app, but getting a null object

I've built a web app with express generator. I'd like to be able to send updates to the browser from a number of different modules.
However, I'm not quite sure why the solution I've put together, below, doesn't work.
I know that the exports.initialize() function is being called, through logging to the console, but the error I'm getting, cannot read property 'emit' of null suggests that socket.io is not being initialized, because it's returning a null object.
I've created a module containing the below wrapper:
const sio = require('socket.io')
let io = null
exports.io = function () {
return io
}
exports.initialize = function(server) {
console.log("init")
return io = sio(server)
}
I've initialised the module in my app.js file, like so:
// Create the http server
const server = require('http').createServer(app);
// Create the Socket IO server on
// the top of http server
const io = require('./app_modules/sockets').initialize(server)
and then, in modules where I need to send information to the browser, I'm calling the sockets module like this:
const io = require('./sockets').io()
Can anyone help me understand why this isn't working, and what I can do to fix it?
In order to start a Socket.IO server, you need to invoke the Server constructor. The io constructor is only for the client side.
Your sockets module should look like this:
const sio = require('socket.io')
let io = null
exports.io = io
exports.initialize = function(server) {
io = new sio.Server(server);
return io
}
And in modules where you need to send information to the clients, you should use something like this:
const io = require('./sockets').io

why we creating instance from events.EventEmitter(), and not for http?

Event Emitter
var events = require('events');
var eventEmitter = new events.EventEmitter();
Http Server Request
var http = require('http');
var server = http.createServer(function(req, res){})
Creating instance for new events.EventEmitter() not for http.createServer()
The http library exports the Server constructor so just like with eventEmitters, you can do:
let server = new http.Server(fn);
This, is exactly the same way that you do things with the events library.
http.createServer() is a factory function. It creates a Server object for you. It's not entirely obvious why they decided to also export a factory function, but you can use either the factory function or the constructor. If you look at the code for http.createServer(), you can see that this is all it does:
function createServer(requestListener) {
return new Server(requestListener);
}
where Server is the same thing as http.Server. So, the http library just offers two ways of creating a server, one of which works exactly like the events library.

How do I overload the functionality of app.listen in expressjs

I've been trying to create (basically) a factory function that configures and builds an expressjs server for a dozen smaller specialized servers I have. For part of this I want to augment the listen function.
I would like to know the best way to go about this. I'm also looking for a reusable design choice here.
Server is created normally:
var httpServer = express();
...
Because of the way express is designed (Not sure if I am correct) I cannot access a {whatever}.prototype.listen. So I have come up with two approaches.
Using an additional variable in the current scope:
var oldListen = httpServer.listen;
httpServer.listen = function(callback){
...
oldListen.call(httpServer, options.port, options.host, function(){
...
if ( typeof callback == 'function' ) callback();
});
};
Which works and is fairly straight forward but then I have a variable hoisting wart. I also have a closure solution, but I think it may be too obtuse to be practical:
httpServer.listen = (function(superListen){
return function(callback){
...
superListen.call(httpServer, options.port, options.host, function(){
...
if ( typeof callback == 'function' ) callback();
});
};
})(httpServer.listen);
Both examples are part of the factory context and I am intentionally reducing the arguments passed to the function.
Any help would be appreciated.
If you insist on "overloading", make sure you implement the original footprint (such is the nature of overloading). Express listen is just an alias to node's internal http listen method:
server.listen(port, [host], [backlog], [callback]);
UPDATE: Express even suggests using node's server API for custom implementations: http://expressjs.com/4x/api.html#app.listen
Otherwise, you should create your own custom listen method which would be defined like:
httpServer.myCustomListen = function (callback) {
httpServer.listen.call(httpServer, options.port, options.host, callback);
}
The second option is your best bet, but in order for it to work, you must extend the express library. Express is open source and hosted on Github. Fork it and modify it as you please. Periodically pull in new updates so you stay up-to-date with the core library. I do this all the time with node modules.
There are two benefits from doing it this way:
You have complete control to customize the code however you see fit while staying up to date with the code written by the original authors.
If you find a bug or build a cool feature, you can submit a pull request to benefit the community at large.
You would first fork the repository, then grab the URL for your fork, clone it, and then add a reference to the original "upstream" repo:
git clone [url_to your_fork]
cd express
git remote add upstream git#github.com:strongloop/express.git
Then you can push changes to your own repo (git push). If you want to get updates from the original repo, you can pull from the upstream repo: git pull upstream master.
If you want to add your custom fork of express as an npm module for a project, you would use the following:
npm install git://github.com/[your_user_name]/express.git --save
As Victor's answer pointed out, express's prototype is in express/lib/application.js. That file is used to build express and is exported via the application namespace in express/lib/express.js. Therefore, the .listen function can be referenced using express.appliction.listen.
One can use this method then: (similar to Victor's method)
var express = require('express');
express.application._listen = express.application.listen;
express.application.listen = function(callback) {
return this._listen(options.port, options.host, callback);
};
One can also use Lo-dash's _.wrap function if you don't want to store the base function in a variable yourself. It would look something like this:
var express = require('express');
var _ = require('lodash');
express.application.listen = _.wrap(express.application.listen, function(listenFn) {
return listenFn(options.port, options.host, callback); // Called with the same this
};
However, using these methods would run into the problems that you mentioned in your question (variable hoisting, creating an extra variable). To solve this, I would usually create my own subclass of express.application and replace the .listen function in that subclass and tell express to use that subclass instead. Due to express's current structure, however, you cannot replace express.application with your own subclass without overriding the express() function itself.
Hence, what I would do is to take over express.application.listen completely since it is only 2 lines. It is rather simple!
var express = require('express');
var http = require('http');
express.application.listen = function(callback) {
return http.createServer(this).listen(options.port, options.host, callback);
};
You can even make an https option!
var express = require('express');
var http = require('http');
var https = require('https');
express.application.listen = function(callback) {
return (options.https ? http.createServer(this) : https.createServer({ ... }, this))
.listen(options.port, options.host, callback);
};
Note: One of the other answers mentions forking express and modifying it. I would have a tough time justifying that for such a small function.
You should be able to easily overload the express listen function. You can access it in the following Object path: express.application.listen
So, you can implement something like this:
var express = require('express');
express.application.baseListen = express.application.listen;
express.application.listen = function(port) {
console.log('Port is: ' + port);
this.baseListen(port);
};
The implementation of the listen function is in the following path under the express module folder: node_modules\express\lib\application.js
Bind and listen for connections on the given host and port. This method is identical to node's http.Server#listen().
var express = require('express');
var app = express();
app.listen(3000);
The app returned by express() is in fact a JavaScript Function, designed to be passed to node's HTTP servers as a callback to handle requests. This allows you to provide both HTTP and HTTPS versions of your app with the same codebase easily, as the app does not inherit from these (it is simply a callback):
var express = require('express');
var https = require('https');
var http = require('http');
var app = express();
http.createServer(app).listen(80);
https.createServer(options, app).listen(443);
The app.listen() method is a convenience method for the following (if you wish to use HTTPS or provide both, use the technique above):
app.listen = function(){
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
Reference:http://expressjs.com/api.html
Hope This helps.

Object oriented style app with express.js and socket.io

I'm building an application in node, using express for simplify things and socket.io for sockets manipulation.
So, while I'm writing my code I realize that it works, but is not the best and elegant solution.
The only thing I want to do is to wrap all the code of the sockets events, and then reuse in more than one page request, so:
app.js
var express = require('express')
, io;
var app = express()
, PORT = 7777;
io = require('socket.io').listen(app.listen(PORT));
app.get("/", function ( req, res ) {
io.socket.on('connection', function ( socket ) {
socket.on('user', function () {
});
socket.on('message', function () {
});
socket.on('getConversation', function ( socket ) {
});
});
res.render('index');
});
But what happens if I want to assign to the /foo and /bar files the same approach?
i.e. I need to get it in a modular or object oriented way, as can be possible.
There is a pattern to do it?
All you're doing here is attaching event listeners to socket.io after someone makes a page request. Then every single request after that would be attaching new event listeners and your server slowly begins to run out of memory as you clog it with new event listeners every time someone makes a page request. It makes no sense to put socket.io code in your route handlers. Take a look at this:
https://www.npmjs.com/package/express.io

Node.js - Socket.io - Express 3

I'm a noob to Node.js and Express :( I'm having an issue with accessing the socket.io object in other modules. I have created a global variable to hold a socket object however as soon as that user closes the connection the connection isn't available anymore. Technically I guess the connection still lives on but I delete it for resource reasons.
Notice below everytime a connection is made we assign that socket to the global variable which is accessible to all other modules.
// App.js
var io = require('socket.io').listen(server);
var sessionsConnections = {};
io.sockets.on('connection', function (socket)
{
global.socket = socket;
sessionsConnections[socket.id] = socket;
.....
}
socket.on("disconnect", function()
{
delete sessionsConnections[socket.id];
});
// Match.js
global.socket.emit('lobby:createMatch', data);
If the connection last assigned to the global closes Match.js will be screwed. At this point Match.js is the only module who will ever need that socket.io reference. Match.js has a bunch of exports for handling events, emitting the changes and rendering the view.
Are there any suggestions to how this is handled? Is it possible to instantiate an initial socket connection to live in App.js for the purpose of being a global reference?
The socket variable in io.sockets.on('connection', function(socket) {...}) is different for each connection.
Since in your code global.socket is always a reference to the socket relative to the last connected client, it is normal that if this client disconnects, this socket will die.
In any case, I don't see any reason to use a global variable. If you need to send a message to a specific client, you can use the socket variable inside the connection callback:
io.sockets.on('connection', function (socket)
{
socket.emit('foo', 'bar');
}
If you need to access the sockets in another module, you can export the sessionsConnections object, and access the socket you need by its id:
//In app.js
exports.connections = sessionsConnections;
//In match.js
var app = require('./app.js');
app.connections[clientId].emit('foo', 'bar');
Of course, you need to keep track of the id's somewhere.
You might try express.io,
http://express-io.org/
npm install express.io
It works the same as express, except that it has socket.io integration built-in. It also has basic routing, so that it is a little easier to deal with your issue.
Check out this simple example:
app = require('express.io')()
app.http().io()
app.io.route('some-event', function(req) {
req.io.broadcast('announce', 'someone triggered some-event')
})
app.listen(7076)
You can also do routing with objects, which makes it more like a traditional controller:
app = require('express.io')()
app.http().io()
app.io.route('posts', {
create: function(req) {
// create a post
},
remove: function(req) {
// remove a post
}
})
app.listen(7076)
Hope that helps!

Resources