Using functions outside module exports - javascript

I'm trying to do my best to explain what I'm trying to do, please let me know if something wasn't understandable.
I have a file called www where I'm setting up my socket like that
var server = http.createServer(app);
var io = require('socket.io')(server);
require('../store.js')(io);
I'm sending the io data to another file to use it properly. To capture the io I'm using.
module.exports = function (io){
}
What I'm trying to do is how could I use the io outside from the module.exports in the store.js file? I've tried to create a variable and then use it, but that doesn't seem to work.
Example how I've tried it.
var ioData;
ioData.on('connection', function(socket) {
//Doesn't work
});
module.exports = function(io){
ioData = io;
}

you can do this
store.js
const store = {
io: {},
setIo(io) {
store.io = io;
},
setHandlers() {
store.io.on('connection', function(socket) {
// do something with connected socket
});
}
};
module.exports = store;
www
var server = http.createServer(app);
var store = require('../store');
var io = require('socket.io')(server);
store.setIo(io);
store.setHandlers(io);

You need to create a add the connection event handler into the module export function, since when you change ioData, it doesn't re-add the handler.
var ioData;
module.exports = function(io){
ioData = io;
ioData.on('connection', function(socket) {
//Doesn't work
});
}

Related

socket.io not recieving/sending

I have a simple setup where I have some draggable divs and I want to use sockets.io to update the position between clients.
On my client (index.html) I have :
// find the elements
var elements = document.getElementsByClassName('ball'),
labelsX = document.getElementsByClassName('coords-x'),
labelsY = document.getElementsByClassName('coords-y');
// loop over the 3 items...
for (var n = elements.length; n--;) {
// ... augment our default options with individual `onDrag` handlers
var opts = {
onDrag: onDragFactory(n),
setCursor: true
};
// ... and initialize drag for each
window.d = new Draggable(elements[n], opts);
console.log('ddd');
}
// bind `n` to its value at iteration time
function onDragFactory (n) {
return function (element, x, y) {
//This doesnt seem to work
console.log(elements[n].style.top);
socket.emit('positionx', elements[n].style.top);
socket.on('positionx', function(positionx){
elements[n].style.top= positionx.value();
});
}
}
My server is then :
var express = require('express');
var path = require('path');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var publicPath = path.resolve(__dirname, 'public');
app.use(express.static(publicPath));
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
//Server Side Listen for an event from the client
io.on('connection', function(socket){
socket.on('positionx', function(positionx){
console.log('recieving');
console.log(positionx);
io.emit('positionx', positionx);
});
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
The server however doesn't seem to receive any information. Is there something I'm doing wrong? Any help would be much appreciated!
In your client you need to define socket.
var socket = io();
Also, make sure you are including socket.io-x.x.x.js prior to calling socket.io in your javaScript. You are probably already doing this, but it's unclear without seeing more code.

io.on is not a function

I have this code working for receiving data from my Arduino but I will like to send data back to my Arduino and get a response on my client page. I added a listening function but I keep getting io.on is not a function when I send data from my client page.
test.js
io.listen(app.listen(3000)).on('connection', function (client) {
// store client into array
clients.push(client);
// on disconnect
client.on('disconnect', function() {
// remove client from array
clients.splice(clients.indexOf(client), 1);
});
// I added this to listen for event from my chart.JS
io.on('connection', function(socket){
socket.on('LED on', function (data) {
console.log(data);
});
socket.on('LED off', function (data) {
console.log(data);
});
});
});
Your value of io is not what it should be.
The usual way of doing things is like this:
var app = require('http').createServer(handler)
var io = require('socket.io')(app);
var fs = require('fs');
app.listen(80);
io.on('connect', ...);
But I'm guessing that your value of io is something like this:
var io = require('socket.io');
That's not the same thing. That's the module handle. But, when you do it this way:
var io = require('socket.io')(app);
Then, io is a socket.io instance. You can bind listeners to an instance, not to the module handle.
In every single socket.io server-side example on this doc page, they use one of these forms:
var io = require('socket.io')(app);
var io = require('socket.io')(port);
var io = require('socket.io')(server);
with this:
io.on('connection', ....);
Nowhere do they do:
var io = require('socket.io`);
io.listen(server);
io.on('connection', ....);
That's just the wrong value for io.
Long story, shortened, you need to fix what you assign to io to be consistent with the docs. It's the return value from require('socket.io')(app); that gives you a socket.io instance object that you can then set up event handlers on.
if you are using express
var express = require('express');
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
let APP_PORT=3000;
server.listen(APP_PORT,()=>{
console.log(`SERVER RUNNING ON PORT : ${APP_PORT}`);
});
io.on('connection', (socket) => {
/* SOCKET - CORE EVENTS */
socket.on('connect', (message) => {
console.log("connected: " + message+"socket_id:"+socket.id);
});
socket.on('disconnect',(data)=>{
console.log('user disconnected:' + socket.id);
});
socket.on('error', function (err){
console.log('received error from client:', socket.id,' Error :',err);
});
});

How to create a reusable Socket.IO module

I have troubles for creating a module which exposes functionalities for my Socket.IO library:
const sio = require('socket.io');
module.exports = function(server) {
const io = sio(server);
return {
register: function(namespace) {
let nsp = io.of(namespace);
nsp.on('connect', function(socket) {
// ...
}
}
}
}
The problem is now how do I make use of this in other modules? In my app.js
I create the server with Express and can instantiate the module with require('./mysocketio')(server) but not in other modules because server is not available there. What's a nice way to resolve these circular dependencies?
Well you can achieve those in various ways, like:
setting objects to global namespace. (altering global needs care)
Use module.exports and require the object in the other files. (can lead to circular dependency issues if not done properly)
pass the instance as arguments to the controllers, while requiring them in routes.
myModule.js Module which exposes functionalities of your Socket.IO library
const sio = require('socket.io');
module.exports = function(server) {
const io = sio(server);
return {
register: function(namespace) {
let nsp = io.of(namespace);
nsp.on('connect', function(socket) {
// ...
}
}
}
}
FLow 1: set the module in global namespace.
app.js
var app = require('express').createServer();
var io = require('./myModule')(app);
global._io = io;
app.listen(80)
controller.js
module.exports = function(io){
var that={};
/*
* Private local variable
* made const so that
* one does not alter it by mistake
* later on.
*/
const _io = global._io;
that.myAction = function(req,res){
_io.register('newRoom');
res.send('Done');
}
return that;
}
Flow 2: passing module as arguments.
app.js
var app = require('express').createServer();
var io = require('./myModule')(app);
require(./router.js)(app,io);
app.listen(80);
router.js
/*
* Contains the routing logic
*/
module.exports = function (app,io) {
//passing while creating the instance of controller for the first time.
var controller = require("./controller")(io);
app.get('/test/about',controller.myAction);
};
controller.js
module.exports = function(io){
var that={};
const _io = io;
that.myAction = function(req,res){
_io.register('newsRoom');
res.send('Done');
}
// everything attached to that will be exposed
// more like making public member functions and properties.
return that;
}
Flow 3: Setting io to global. Thus no need to pass server every time.
app.js
var app = require('express').createServer();
require('./myModule')(app);
require(./router.js)(app);
app.listen(80);
controller.js
// no need to pass the server as io is already initialized
const _io = require('./myModule')();
module.exports = function(io){
var that={};
that.myAction = function(req,res){
_io.register('newsRoom');
res.send('Done');
}
return that;
}
myModule.js
module.exports = function( server ) {
const _io = global._io || require('socket.io')(server);
if(global._io === undefined){
//initializing io for future use
global._io = _io;
}
return {
register: function(namespace) {
let nsp = _io.of(namespace);
nsp.on('connect', function(socket) {
// ...
}
}
}
}
Probably, the cleanest way is to pass is as arguments to the controllers, while requiring them in routes. Although 3rd flow seems promising but one should be care full while altering the global namespace.
It's not really a circular dependency; It's just that your module a) depends on another module that's not globally available and b) your module is presumably used in many places in your code.
Global
A possible solution (with downsides), is to just load your module once, and attach it to a global:
global.mysocketio = require('./mysocketio')(server);
This allows you to access global.mysocketio anywhere in your project, once it has been loaded. This is a construction that I personally use for an own logger construction; My logger is used in many places around my code, so I just keep it attached to global.log.
However, usage of globals is a bit dirty; It gives problems with namespace-separation (what is somewhere some code decides to use global.mysocketio itself), and it creates an 'invisible' dependency; Other code just assumes that a certain global will exist, and it's not that easy to find these dependencies.
Export
A nicer solution is to just pass the variable wherever needed. There are many ways to do this. I understand that your app.js doesn't have the server variable available, but it surely is including your express-code in some way. If you need the 'server' or 'mysocketio' available from app.js, just export it from your module where you are creating 'server'. Like:
module.exports.expressServerVar = server;
Just my 2 cents; Do you strongly disagree with me or am I missing something important? Let me know!
I'd use a factory or dependency injection. You could use something like jimple.
But here's an example without using any external dependencies. This is by no means the best code example but it should hopefully get the point across. I'd still recommend using jimple rather than this.
// app.js
var express = require('express');
var app = express();
var factory = require('./factory.js');
factory.setExpress(app); // This could also be done in the factory constructor. Or you could instanciate your express app in the factory.js class.
// factory.js
var socketIoModule = require('./your-socket-io-module.js')
function Factory() {
}
Factory.prototype.setExpress = function(app) {
this.app = app;
}
Factory.prototype.getSocketIOModule = function() {
return socketIoModule(this.app);
}
// By exporting it this way we are making it a singleton
// This means that each module that requires this file will
// get the same instance of factory.
module.exports = new Factory();
// some code that needs socket io module
var factory = require('./factory.js');
function() {
var socketIo = factory.getSocketIOModule();
socketIo.doStuff();
}
Approach that I use in my applications is exposing server and io instances from start script and reusing them in modules
// Setup servers.
var http = require('http').Server(app);
var io = require('socket.io')(http);
// Setup application.
require('./server/app')(app, express, io);
// Start listening on port.
http.listen(configs.PORT, function() {
console.log("Listening on " + configs.PORT);
});
Inside your modules you can use io instance to setup event handlers or emit events, something like this
module.exports = {
contest: function(io, contest) {
var namespace = io.of('/' + contest.id);
namespace.on('connection', function(socket) {
socket.on('word', function(data) {
...
});
});
}
};
For your sample
I would put this part in app.js or in js file that is used to start server
const sio = require('socket.io');
const io = sio(server);
and will have Socket.IO module like this
module.exports = function(server, io) {
return {
register: function(namespace) {
let nsp = io.of(namespace);
nsp.on('connect', function(socket) {
// ...
}
}
}
}
My sample
https://github.com/gevorg/typeitquick/blob/master/web.js
https://github.com/gevorg/typeitquick/blob/master/server/contest.coffee
https://github.com/gevorg/typeitquick/blob/master/server/io.coffee

javascript class variable scope confusion (socket.io events)

I'm using node with express and socket.io to create a game server. I've put the game server in a extra module.
I have the problem that I can't access the game server object within the io event.
How do I solve this problem or should I structure my project differently?
// gameServer.js
'use strict'
var io = require('socket.io');
var socketioJwt = require('socketio-jwt');
var config = require('../config.js');
class GameServer {
constructor(http) {
this.io = new io(http);
this.connectedUsers = [];
this.initSocket();
}
initSocket() {
console.log('users', this.connectedUsers);
this.io.on('connection', this.onConnection);
}
onConnection(socket) {
console.log('users', this.connectedUsers); // undefined
}
}
I initialize the server like that:
'use strict'
var express = require('express');
var app = express();
var http = require('http').Server(app);
// init game server
var gameServerApp = new GameServer(http);
http.listen(3000, function() {
console.log('listening on *:3000');
});
I assume this is a common question but I can't figure out how to solve it.
You can bind this to this.onConnection
initSocket() {
console.log('users', this.connectedUsers);
this.io.on('connection', this.onConnection.bind(this));
}

Emit socket from a controller - How to get access to socket server from a controller

Bases
I'm trying to use sockets on my node project. This is the how it basically works :
/
|-> controllers/
| |-> home.js
|-> app.js
|-> sockets.js
/app.js
On app, I call sockets.js to start the socket server :
var express = require('express');
var sockets = require('./sockets');
var app = module.exports = express();
var server = app.listen(config.PORT);
var io = sockets(server);
/sockets.js
On this file I start the socket server, and return io.
var socket = require('socket.io');
module.exports = function(server) {
var io = socket.listen(server);
io.sockets.on('connection', function(socket) {
// Here I can call every socket I want (if I have the socket_id) with this code :
var socket = io.to(socket_id);
socket.emit('message', {});
});
return io;
};
Question
But now, I want to retrieve my io server on my home controller and call a specific socket. I've tried to do this :
/controller/home.js
var io = require('../sockets.js');
module.exports = {
home: function(req, res, next) {
var socket = io.to(socket_id);
socket.emit('message', {});
}
};
But I have this error, cause I don't execute the function (but I don't want create a new socket server here) :
TypeError: Object function (server) {
var io = socket.listen(server);
/*.....*/
return io;
} has no method 'to'
I want to get an access to the io variable returned by this function called on app.js. How Can i get it ?
You could convert sockets.js into an object that exposes your io property. You would also add a function listen that app.js calls during initialization.
// sockets.js
module.exports = {
listen: function(server) {
this.io = socket.listen(server);
//...
return this.io;
}
}
Your controller can then access require('../sockets.js').io, You just need to make sure io is defined at the time you use it, or otherwise make sure app.js calls listen before your controller gets invoked.
You must be convert sockets.js into an object that exposes your io property.
You would also add a function listen that app.js calls during initialization.
Your controller can then access require('../sockets.js').io.

Categories