So i have this basic node.js server running, now i want to add another layer to it with socket io. I can use socket io, the example here is pretty simple and works great. But my app is much bigger so I do this thing where i load a bunch of resources and then load this server module by calling start_app.
I know i cant put io.listen(app) on line 3 because my server hasn't started yet.
I need that functional dependency, so how do i add add socket.io to the mix?
var app= require('http') // all http requests go to onRequest
, url= require('url') // path info stuff
, io = require('socket.io') // socket io
function start_app(route, handle) {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname.replace("/","")
route(handle, pathname, request, response)
}
app.createServer(onRequest).listen(process.env.PORT || 8888)
io.listen(app)
console.log(". http://localhost:8888 .")
}
exports.start_app = start_app;
my error:
...socket.io/lib/manager.js:104
server.on('error', function(err) {
^
TypeError: Object #<Object> has no method 'on'...
Instead of your code:
app.createServer(onRequest).listen(process.env.PORT || 8888)
io.listen(app)
Could you do it like below?
var createdServer = app.createServer(onRequest).listen(process.env.PORT || 8888);
io.listen(server).on('connection', function (socket) {
socket.on('message', function (msg) {
console.log('Message Received: ', msg);
socket.broadcast.emit('message', msg);
});
});
We need the actual created server so socket.io can listen to that. Then handle the 'connection' event.
changeing the first few lines of the server fixed it.
I'm not 100% sure why this works but, I guess it makes sense that the server shouldn't start until this function is called, since its the entry into the main event loop of the app.
var app // all http requests go to onRequest
, url = require('url') // path info stuff
, sio = require('socket.io') // socket io
function start_app(route, handle) {
app = require('http').createServer(onRequest)
sio = require('socket.io').listen(app)
app.listen(process.env.PORT || 8888)
Related
Either I have a fundamental misunderstanding of how socket.io works (highly likely), or I am just finding some bug that nobody knows about (nearly impossible).
I've been trying to integrate express with socket.io. On the client side, everything works fine: user clicks button, event emits, everybody's happy.
However, let's say I want to emit this event from within an express route before rendering a page. The event never seems to be emitted. From all the questions on this that I've looked at, I'm supposed to be able to simply plug my "io" instance into my app and then access it from within my routes.
So this is my setup...
// index.js
var app = express();
var port = process.env.PORT || 3700
var io = require('socket.io').listen(app.listen(port));
io.on('connection', function (socket) {
console.log("Socket connected on port " + port)
socket.on('send', function (data) {
console.log("WAFFLES")
});
});
console.log('The magic happens on port ' + port);
require('./app/routes.js')(app, io);
// app/routes.js
module.exports = function(app, io){
app.get('/', function(req, res){
io.on('connection', function (socket) {
console.log("Hello from the route!")
socket.emit('send', {message: 'urdum'})
});
res.render('index')
})
}
So in this instance, I want to be able to go into the / route, see "Hello from the route" and then "WAFFLES" logged to the console after emitting the "send" event. Instead I get absolutely nothing.
I've tried to pass in "io" via app.set('socketio', io). But no matter what, nothing works.
I've also tried emitting the event within the route without the io.on('connection') and simply just doing
io.emit('send' ...)
OR
io.sockets.emit('send' ...)
I have a fundamental misunderstanding of how socket.io works (highly likely)
You are right,
This is typical setup for socket-io, read more in https://socket.io/docs/
// index.js
var express = require('express');
var socketio = require('socket.io');
var http = http = require('http');
var app = express();
// Attach Socket.io
var server = http.createServer(app);
var io = socketio.listen(server);
app.set('socketio', io); // <-- bind socket to app
app.set('server', server); // <-- optional
io.on('connection', function (socket) {
console.log("Socket connected on port " + port);
});
app.listen(3000);
server.listen(3001) // <-- socket port
// app.get('server').listen(3001); // <-- use server or app.get('server')
In your router, access socket by req.app.get('socketio');
// app/routes.js
module.exports = function(app, io){
app.get('/', function(req, res){
var socketio = req.app.get('socketio');
socketio.emit('send', {message: 'urdum'});
res.render('index')
})
}
How can I trigger an emit from the server-side with socketIO ?
I have a socket.on('My_Event') on my nodejs server and I wish to trigger that event from some place else on my server with .emit('My_Event').
My goal here is to broadcast to the client-side some notification datas.
server side - app.js
var app = express(),
server = http.createServer(app),
io = require('socket.io')(server);
io.on('connection', function(socket){
socket.on('My_Event', function(data){
socket.volatile.emit('event', data);
});
});
server.listen(config.listenPort, '0.0.0.0', 511, function() {
// config.listenPort is already defined
console.log('node Server - listening on port: ' + config.listenPort);
});
export - the module from which I'd like to trigger the event
var io = require('socket.io')();
exports.addStrategy = function(app) {
var fn = {
doSomething : function(req, res, next) {
// HERE I wish to trigger my socket event
// io.emit('MY_EVENT', {}); ????
res.status(200).json(done());
};
return fn;
};
so far I can't get it to work. is it how I should do it ?
One option is to create a single global instance of Socket.IO that could eventually be shared across multiple modules/applications.
global.socket = require('socket.io').listen(app);
Happy Helping!
I am having a problem of using socket IO to connect my server to the client(http website).
On the client, I have a button that when pressed, sends data to the server. However, this only works with one client.
If I have two clients, the first person to open the http website gets the socket IO connection, while the second person can open the page, but can't send any data to the server.
On the client side:
var socket = new io.connect('ServerIP:8090');
socket.on('message', function(obj){
if ('buffer' in obj){
//ignore this
} else message(obj);
});
On server side:
var io = io.listen(server)
, buffer = [];
io.on('connection', function(client)
{
client.send({ buffer: buffer });
client.broadcast.send({ announcement: client.sessionId + ' connected' });
chatGuests.push(client);
client.on('message', function(message){
var msg = { message: [client.sessionId, message] };
buffer.push(msg);
if (buffer.length > 15) buffer.shift();
client.broadcast.send(msg);
});
client.on('disconnect', function(){
client.broadcast.send({ announcement: client.sessionId + ' disconnected' });
});
Instead of using client.broadcast.send(something) and client.send(something) use io.emit('eventName', something). Also, for setting up the server with the variable io use
var socket = require('socket.io');
var http = require('http');
var express = require('express');
var app = express();
var server = http.createServer(app);
var io = socket.listen(server);
And then after your code:
server.listen(8090);
This allows you to use the node.js module express, which allows additional communication between the client and server (but doesn't require you to rewrite your socket.io code).
For your client code, instead of using:
socket.on('message', function(obj){
//Do something
});
Use:
socket.on('eventName', function(something){
//Do something
});
This works for multiple kinds of data passing, not just messages. You can multiple event listeners to each do different things
I try socket.io again since v.1.0 released.
As the doc,
https://github.com/Automattic/socket.io
Server side:
var server = require('http').Server();
var io = require('socket.io')(server);
io.on('connection', function(socket){
socket.on('event', function(data){});
socket.on('disconnect', function(){});
});
server.listen(5000);
Client side
var socket = io.connect('http://yourhostname.com/');
In development, surely
var socket = io.connect('http://localhost:5000/');
It works, but I'm very uncomfortable with hardcoding the hostname(subdomain.domain) in the client code(/index.js).
The index.js is hosted by the http-sever and the socket.io is bundled to the http-server in this configuration.
Is there any smart way not to hardcode the hostname but to code in some relative path?
Thanks.
EDIT:
When I try:
var socket = io.connect('./');
The connection error:
GET http://.:5000/socket.io/?EIO=2&transport=polling&t=1401659441615-0 net::ERR_NAME_NOT_RESOLVED
is like this, so at least the port number (5000) is obtained properly without hardcoding in the client side.
Final answer.
I have totally forgotton that we can obtain the current url/domain in browser.
window.location.hostname
So, simply goes:
'use strict';
/*global window, require, console, __dirname, $,alert*/
var log = function(msg)
{
console.log(msg);
};
log('init');
$('document').ready(function()
{
var io = require('socket.io-client');
var socket = io.connect(window.location.hostname);
socket.on('connect', function()
{
log('socket connected');
});
});
You have to remember that Node.js is not a web server. It's a platform. When you specify a relative path, it doesn't know that you mean "relative to the current domain."
What you need to do is send the domain to the client when you send them the webpage (I don't know the specifics of your setup, but perhaps using a template variable?), and send them the localhost:5000 domain if you're in development, or your real domain if you're in production (alternatively, you can use a library like nconf, but you get the idea).
dunno, so far I did as follows:
'use strict';
/*global window, require, console, __dirname, $,alert*/
var log = function(msg)
{
console.log(msg);
};
log('init');
$.getJSON("../config.json", function(data)
{
var host = data.url;
var port = data.port;
$('document').ready(function()
{
alert(host + ':' + port);
var io = require('socket.io-client');
var socket = io.connect(host);
socket.on('connect', function()
{
log('socket connected');
});
});
});
It's browserified with socket.io-client.
I'm trying out Websockets/Node.js/Socket.io/Express for the first time and I'm trying to create a simple chat program. Everything runs fine and I see both clients in my node termial.
But when I try to execute my socket.send(), I get an error in Firefox (socket.send is not a function). It doesn't complain about socket.connect() so I know the socket.io.js is loaded.
Here is my server code:
var sys = require('util');
var express = require('express');
var io = require('socket.io');
var app = express.createServer();
app.listen(8080);
app.use(express.static(__dirname));
app.get('/', function (req, res) {
res.render('index.html', {
title: 'Chat'
});
});
var socket = io.listen(app);
socket.on('connection', function (client) {
client.on('message', function (message) {
console.log("Message: " + JSON.stringify(data));
socket.broadcast(message);
});
client.on('disconnect', function () {});
});
My client code:
<script src="http://localhost:8080/socket.io/socket.io.js"></script>
var socket = new io.Socket("http://localhost:8080");
socket.connect();
Then I do some code to get the chat message and send it.
socket.send(JSON.stringify(values));
Explanations
You haven't initialized Socket.io correctly on the server-side and client-side.
Client Side
new io.Socket("http://localhost:8080"); doesn't give you the object that you want, you need new io.connect("http://localhost:8080");.
You need to wait until the client is connected to the server before sending a message.
Server side
socket is the object send back by Socket.IO, you need to use socket.sockets to have access to on.
To broadcast a message, you need to use the client object like this: client.broadcast.send()
The variable data doesn't exist on your broadcast. You probably mean message.
Solution
Server
var sys = require('util'),
express = require('express'),
io = require('socket.io'),
app = express.createServer();
app.listen(8080);
app.use(express.static(__dirname));
app.get('/', function (req, res) {
res.render('index.html', {
title: 'Chat'
});
});
var io = io.listen(app);
io.sockets.on('connection', function (client) {
client.on('message', function (message) {
console.log("Message: " + JSON.stringify(message));
client.broadcast.send(message);
});
client.on('disconnect', function () {});
});
Client
<script src="http://localhost:8080/socket.io/socket.io.js"></script>
<script>
var socket = new io.connect("http://localhost:8080"),
connected = false;
socket.on('connect', function () {
connected = true;
});
// Use this in your chat function.
if (connected) {
socket.send(JSON.stringify(values));
}
</script>
socket.broadcast(message); should be io.sockets.emit('key', message);
when you use the socket object passed in threw the connect event your only emitting information to that client, to emit to all clients you have to use io.sockets.emit().
also with socket.send(JSON.stringify(values)); I think you want to do socket.emit(namespace, data);
see my connection file from one of my projects here: https://github.com/AdminSpot/HangoutCanopy/blob/master/javascripts/connection.js
You have to wait for socket.io to connect on the client side
var socket = new io.Socket("http://localhost:8080");
socket.connect();
socket.on('connect', function() {
socket.emit('event', data);
});