Socket.io in Different Files - javascript

To use the io object in different files I am using the approach below.. I seems like I am not getting compile errors. So io is "defined" in the users.js file.. But I dont seem to be emmiting any event. Does anyone see the problem?
app.js
var app = require('express')()
, server = require('http').createServer(app)
global = require('./global.js');
global.io = require('socket.io').listen(server);
global.io.configure(function () {
global.io.set("transports", ["xhr-polling"]);
global.io.set("polling duration", 10);
});
// express settings
require('./config/express')(app, config, passport)
require('./config/passport')(passport, config, env)
// Bootstrap routes
require('./config/routes')(app,passport)
var port = process.env.PORT || 3000
server.listen(port)
global.js
var Global = {
io : { }
};
module.exports = Global;
routes.js
var users = require('../app/controllers/users')
module.exports = function (app, passport) {
app.post('/incomingFake', users.getFake);
}
users.js
var global = require('../../global.js')
exports.getFake = function(req, res){
global.io.sockets.on('connection', function(socket) {
socket.broadcast.emit('email', req.body);
});
User.findAndStoreEmail(senderEmail, email ,function(){
res.writeHead(200, {'content-type': 'text/plain'})
res.end('Message Received. Thanks!\r\n')
})
}
and I try to receive this in a backbone collection in the frontend
define([
'jquery',
'underscore',
'backbone',
'Email',
'marionette',
'socketio'
], function ($, _, Backbone, emailModel, Marionette, io) {
'use strict';
var Emails = Backbone.Collection.extend({
url : '/emails',
model : emailModel,
initialize : function() {
var socket = io.connect('http://localhost:3000');
socket.on('email', function (data) {
console.log("i got the socket connection");
console.log(data);
});
}
});
return Emails;
});
edit:
I realized something! I think this might help a lot to resolve the problem, I actually receive the connection event and the socket emits something but this all happens with the page load.. I want this event to be emitted only the 'getFake' function is called

since you are trying to manage connections, based on the route that the client is in.
You can try Socket.io namespaces
Represents a pool of sockets connected under a given scope identified by a pathname (eg: /chat).
By default the client always connects to /.
so on server-side code, a short example would be
io.of("/users").on("connection",function(socket){
/*
when connecting from /users, the socket object will be available here
*/
});
// all clients of pathname /users will get this message
io.of("/users").emit("greeding","Hello fellow users");

Related

Socket.io only successfully connects if window opens before server starts

I've been trying to resolve a really strange Socket.io bug.
If I open the page on the client while the server is running, it will fail to connect with the message:
universalModuleDefinition:3 WebSocket connection to
'ws://localhost:4000/socket.io/?EIO=3&transport=websocket&sid=f6LwPIDZubiPKE-TAAAA'
failed: Connection closed before receiving a handshake response
If I then restart the server, while leaving the page open, it connects without issue.
app.js
const app = express();
const server = require('http').Server(app);
require('./socket')(server);
// More code here
server.listen(app.get('port'))
socket.js
const io = require('socket.io');
const jackrabbit = require(`jackrabbit`);
const rabbit = jackrabbit(process.env.RABBIT_URI);
const exchange = rabbit.default();
function Socket (app) {
this.io = io(app);
this.io.on('connection', socket => {
socket.emit('sync');
socket.on('room', room => {
socket.join(room);
});
})
this.queue = exchange.queue({ name: 'worker.socket' });
this.queue.consume(this.onMessage.bind(this), { noAck: true });
}
Socket.prototype.onMessage = function (message) {
this.io.to(message.report).emit('photo', message.photo);
}
module.exports = function (app) {
return new Socket(app);
}
client
var socket = io.connect();
socket.on('connect', function () {
// This gets triggered every time (after the error above)
console.log('Connected');
// This is never logged by the server
socket.emit('room', value); // value set by template engine
});
socket.on('sync', function(){
// will not execute first time I connect, but if I restart
// the server, it runs no problem
alert('Synced with server');
})
socket.on('photo', function(data) {
// also will not be run the first time, but works if the
// server is restarted when the page is open
})
Edit:
I've tried rewriting it to
Initialise socket.io within app.js, then pass it to the socket controller
Run server.listen before requiring socket.js
Initialising the client after a timeout
Setting the transport method on the client strictly to websocket
None of these methods have worked
Found the solution to my problem (actually not an issue with any of the code I posted). I was using the compression middleware for Express, which appears to break socket.io. Solution was to add the following:
app.use((req, res, next) => {
// Disable compression for socket.io
if (req.originalUrl.indexOf('socket.io') > -1) {
return next();
}
compression()(req, res, next);
});

Save a JSON file to server in express (node)

Having this function in express that writes a JSON file on a folder
var savingtheJson=function(path, jsonObject, callback){
jsonfile.writeFile(file2, jsonO, callback);
}
I will like to know how can I access/read this file from the browser once is saved.
If I do this:
savingtheJson('/json/myfile.json', jsonObj, function(){
console.log("done it!");
});
When I go to the browser and I type:
http://localhost:8080/json/myfile.json
Of course I get an error from express "Cannot Get ...." cause I think is trying to resolve it like an specific request
How can I store this file into the static folder declared for this goal
(app.use(express.static(__dirname + '/public'))?
How can I access this file once is saved?
First you need to define which folder is going to be exposed as public, so that you can save your json file inside there.
You can use the built-in middleware express.static for this purpose.
Below in the example I have created a endpoint called /users?name=wilson&age=32 which receives query data in order grab user's information as name and age for then you can save it as file named person.json.
So after you consume the above endpoint mentioned, you will be able to consume your file with something like http://localhost:4040/person.json successfully.
var express = require('express');
var app = express();
var port = 4040;
var fs = require('fs');
app.use(express.static('public'));
app.get('/users', function(req, res) {
var name = req.query.name;
var age = req.query.age;
var person = {
name: name,
age: age
};
savePersonToPublicFolder(person, function(err) {
if (err) {
res.status(404).send('User not saved');
return;
}
res.send('User saved');
});
});
function savePersonToPublicFolder(person, callback) {
fs.writeFile('./public/person.json', JSON.stringify(person), callback);
}
app.listen(port, function() {
console.log('server up and running at port: %s', port);
});

How to use middleware that requires socket connection?

I am using express.io and am trying to craft a middleware that requires a connection to a remote server via two sockets. However, I am having a problem.
var net = require('net');
module.exports = function (host, port) {
return function (req, res, next) {
req._messages = net.connect(port, host);
req._commands = net.connect(port, host);
req._messages.on('data', function (data) {
req.io.broadcast('data', data.toString('ascii'));
});
req._messages.write('CF I\r'); // initialization command
next();
}
}
then in my main app:
var port = process.env.CYLON_PORT;
var host = process.env.CYLON_HOST;
var app = require('express.io').http().io();
app.use(require('./cylon/controller')(host, port));
module.exports = app;
However, I am coming across a problem. On each request, it attempts to reconnect. This causes an Error: connect ECONNREFUSED. Ideally, I would like this to connect once when the application starts and maintain that socket, but it needs to intercept each connect.
How can I use sockets in middleware?
You can try that way:
var net = require('net');
module.exports = function (host, port) {
var messagesConnection = net.connect(port, host);
var commandsConnection = net.connect(port, host);
return function (req, res, next) {
req._messages = messagesConnection;
req._commands = commandsConnection;
req._messages.on('data', function (data) {
req.io.broadcast('data', data.toString('ascii'));
});
req._messages.write('CF I\r'); // initialization command
next();
}
}
The call to require('./cylon/controller')(host, port) will start the connections and they will then be reused each time the middleware is called.
Edit: I'm wondering whether you really need to set all those new fields on you req object. You could have some files that export io, messagesConnection and commandsConnection for instance, and you could require them when needed.
Here you end up adding an even listener on messagesConnection each time the middleware is called, which is everything but good.
Edit2: What you could do instead, because you seem to be using express-io:
var net = require('net');
module.exports = function (io, host, port) {
var messagesConnection = net.connect(port, host);
var commandsConnection = net.connect(port, host);
messagesConnection.on('data', function (data) {
io.broadcast('data', data.toString('ascii'));
});
messagesConnection.write('CF I\r'); // initialization command
return function (req, res, next) {
req._messages = messagesConnection;
req._commands = commandsConnection;
next();
}
}
And in your main file:
var port = process.env.CYLON_PORT;
var host = process.env.CYLON_HOST;
var app = require('express.io').http().io();
app.use(require('./cylon/controller')(app.io, host, port));
module.exports = app;

NodeJS, websocket, and module.export

I have a server.js file.
Inside, i defined my routes.
// routes
var mainRoutes = require('./routes/main.js')(app, express);
var apiRoutes = require('./routes/api.js')(app, express);
var socketRoutes = require('./routes/socket.js');
app.use('/', mainRoutes);
app.use('/api', apiRoutes);
// socket.io communication
io.sockets.on('connection', socketRoutes);
My socket.js file looks like that :
module.exports = function (socket) {
console.log('user connected');
socket.on('myEvent', function(data) {
// whatever ...
});
}
Inside this function, i can catch events and send some.
BUT i need to send a message to everyone at some point. Let say when i receive an 'myEvent' event.
So basically, i would like to do :
io.sockets.emit('messageForEveryone', "This is a test");
But here, i can only work on the 'socket' argument, which is for 1 person only i guess.
I would like to pass io from server.js, to socket.js.
I tried that (in server.js) :
var socketRoutes = require('./routes/socket.js', io);
And that (in socket.js) :
module.exports = function (io, socket)
Obviously, it's not working. I don't even understand where the socket argument is coming from.
Question : How can i work on io object, when i'm inside the module.export of the sockets.js file ?
I would really appreciate any help, i'm new to all of this.
Thanks !
Since you just want to emit to all clients, instead of passing io to socketRoutes, you can simply do this.
module.exports = function (socket) {
var sockets = this;
console.log('user connected');
socket.on('myEvent', function(data) {
sockets.emit('hello_all_clients',data);
});
}
You could return a function from exports as such.
module.exports = function (io) { // pass io to initialize
return function (socket) {
// io and socket are both scoped
}
}
then in server.js
// socket.io communication
io.sockets.on('connection', socketRoutes(io));

flatiron.js routing and templating with union, director and plates?

Coming from express.js, I want to give flatiron a try for a small project. However, there are some small problems which keep me from actually getting somewhere.
var flatiron = require('flatiron')
, session = require('connect').session
, ecstatic = require('ecstatic')
, path = require('path')
, fs = require('fs')
, plates = require('plates')
, director = require('director')
, winston = require('winston')
, union = require('union');
var router = new director.http.Router();
var server = union.createServer({
before: [
ecstatic(__dirname + '/public')
]
});
router.get('/', function () {
var self = this;
fs.readFile('public/layout.html', 'utf-8', function(err, html) {
[...]
})
});
server.listen(3000, function () {
console.log('Application is now started on port 3000');
});
How does routing with director work? When I leave ecstatic out, I can define routes like '/' and it works, but then I don't get static CSS and JS content. With ecstatic / is replaced with 'index.html' and ecstatic has priority over all defined routes.
- It's the same behavior with connect-static. Route (/) is replaced by index.html.
I also tried a different approach using the connect middleware, which doesn't work:
var flatiron = require('flatiron')
, connect = require('connect')
, path = require('path')
, fs = require('fs')
, plates = require('plates')
, app = flatiron.app;
app.use(flatiron.plugins.http);
app.use(connect.favicon());
app.use(connect.static(__dirname + '/public'));
app.use(connect.directory(__dirname + '/public'));
app.use(connect.cookieParser('my secret here'));
app.use(connect.session({'secret': 'keyboard cat'}));
app.router.get('/', function () {
console.log("GET /");
var self = this;
fs.readFile('public/layout.html', 'utf-8', function(err, html) {
[...]
})
});
app.listen(3000, function () {
console.log('Application is now started on port 3000');
});
I think the best answer for your question about routing in flatiron is, as always, inside the source code:
app.server = union.createServer({
after: app.http.after,
before: app.http.before.concat(function (req, res) {
if (!app.router.dispatch(req, res, app.http.onError || union.errorHandler)) {
if (!app.http.onError) res.emit('next');
}
}),
headers: app.http.headers,
limit: app.http.limit
});
As you can see here flatiron binds router as the last request handler, that is called after all middleware. If you place 'ecstatic' in app.http.before and it will be dispatched during workflow, no other middleware would be called.
Your second block of code demonstrates that you don't undestand difference between Flatiron's .use() method from Express/Connect's. I'll try to make it clear on this example:
flatironApp.use({
// plugin object
name : "pluginName"
, attach : function(options) {
/*code*/
}
, init : function(done) {
/*code*/
done();
}
})
connectApp.use(function(req, res, next) {
/* code */
next();
})
If you want to use Connect's middleware in Flatiron you should place it respectively in app.http.before array like this:
// Initiating application
app.use(flatiron.plugins.http);
// Adding request handlers
app.http.before.push( connect.favicon() );
app.http.before.push( ecstatic(__dirname + '/public') );
var connect = require('connect');
var server = union.createServer({
before: [
function (req, res) {
var found = router.dispatch(req, res);
if (!found) {
res.emit('next');
}
},
connect.static('public')
]
});
I forgot to insert the dispatch-function. This works.

Categories