Faye web socket - node.js

I'm new with faye web socket, and I tried to set up a server and a client to exchange information. Unfortunately I'm missing something and I can't get on the client the messages sent from the server.
This is my server.js:
var faye = require('faye');
var Router = require('node-simple-router');
var router = new Router();
var server = require('http').createServer(router);
var port = 5000;
var bayeux = new faye.NodeAdapter({mount: '/faye/calls'});
bayeux.attach(server);
// Launch the server
server.listen(port, function() {
console.log('Listening on ' + port);
setInterval(function(){
bayeux.getClient().publish('/faye/calls', {text: 'Hello'});
},3000);
And is my client.js
var faye = require('faye');
var client = new faye.Client('http://localhost:5000/faye', {
timeout: 600,
retry: 5
});
var sub = client.subscribe('/calls', function(message) {
console.log('message:' + message);
});
sub.then(function() {
console.log('overall Subscription is now active!');
});
Can somebody please tell me what I'm missing?
Thanks very much
Have a good day

It looks like your paths are to blame:
var bayeux = new faye.NodeAdapter({mount: '/faye/calls'});
should mount to /faye:
var bayeux = new faye.NodeAdapter({mount: '/faye'});
and
bayeux.getClient().publish('/faye/calls', {text: 'Hello'});
Should actually publish to /calls
bayeux.getClient().publish('/calls', {text: 'Hello'});
That appears to resolve the issue for me:
overall Subscription is now active!
message:[object Object]
message:[object Object]
message:[object Object]

Related

How to use the client ID in HTML5 websocket and node.js chat?

I'm trying to send private message between users in a simple chat that I created using HTML5 websocket and node.js.
When the users connect, I create a simple ID for them (connection ID) and add that to this CLIENTS=[];
When I do a console.log(CLIENTS);, I see all the IDs like this:
[0, 1, 2]
Now I need to use the IDs to send Private messages to the users.
So i went ahead and this (For the testing purposes, I just need to send the message to the user with ID 2):
var express = require('express'),
app = express(),
http = require('http').Server(app),
WebSocketServer = require('ws').Server,
wss = new WebSocketServer({
port: 8080
});
CLIENTS = [];
connectionIDCounter = 0;
app.use(express.static('public'));
app.get('/', function(req, res) {
res.sendFile(__dirname + '/index.html');
});
wss.broadcast = function broadcast(data) {
wss.clients.forEach(function each(client) {
client.send(data);
});
};
wss.on('connection', function(ws) {
/////////SEE THE IDs HERE////////////////
ws.id = connectionIDCounter++;
CLIENTS.push(ws.id);
console.log(CLIENTS);
ws.on('message', function(msg) {
data = JSON.parse(msg);
/////SEND A PRIVATE MESSAGE TO USER WITH THE ID 2//////
CLIENTS['2'].send(data.message);
});
});
http.listen(3000, function() {
console.log('listening on *:3000');
});
When I run my code, I get the following error:
TypeError: CLIENTS.2.send is not a function
Could someone please advice on this issue?
Any help would be appreciated.
Thanks in advance.
Track clients manually, replace:
CLIENTS = [] with CLIENTS = {}, and CLIENTS.push(ws.id); with CLIENTS[ws.id] = ws;
According to docks https://github.com/websockets/ws/blob/master/doc/ws.md should be something like this:
new WebSocket.Server(options[, callback])
clientTracking {Boolean} Specifies whether or not to track clients.
server.clients - A set that stores all connected clients. Please note
that this property is only added when the clientTracking is truthy.
var WebSocketServer = require('ws').Server,
wss = new WebSocketServer({
port: 8080,
clientTracking: true
});
.....
wss.on('connection', function(ws) {
ws.on('message', function(msg) {
data = JSON.parse(msg);
wss.clients[ID].send(data.message);
});
});
I don't know what data format wss.clients is, so you should try it by yourself. If this is really {Set} as docks said, then try wss.clients.get(ID).send(data.message)

Node js, Call WebSocket server from http server

I have a node js ( supported by express js ) http application. So I had a server.js file as follows(not there complete code).
var app = require('./app/app');
var server = http.createServer(app);
server.listen(port, host);
server.on('error', onError);
server.on('listening', onListening);
I later added websocket server to there. So it is like this now.
// app server
var app = require('./app/app');
var server = http.createServer(app);
server.listen(port, host);
server.on('error', onError);
server.on('listening', onListening);
/**
* websocker Server
*/
var WebSocket = require('ws');
var wsServer = http.createServer();
var url = require('url');
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({ server: wsServer });
var express = require('express');
var wsApp = express();
var port = 1337;
wsApp.use(function (req, res) {
res.send({ msg: 'hello' });
});
wss.on('connection', function connection(ws) {
console.log((new Date()) + ' Connection from origin ');
ws.on('message', function incoming(message) {
console.log('received: %s', message);
var json = JSON.stringify({ type:'message', data: {hello : 'hello'} });
ws.send(json);
});
var json = JSON.stringify({ type:'message', data: {hello : 'hello'} });
ws.send(json);
});
wsServer.on('request', wsApp);
wsServer.listen(port, function () { console.log('Ws server Listening on ' + wsServer.address().port); });
Now these two are working happily. What I want is on a POST call to the http server, I want to trigger the web socket server to broadcast something to all clients. My problem is How I can trigger websocket server from http server?
Routes of http server is defined in app.js file. from there how can I call websocker server function?
If you encapsulate your ws functionality in one single javascript file (e.g: websocket.js) you could export your websocket object as a module.
module.exports = wss;
and then require it in your http controller
var wss = require(websocket.js)
In this case it should be easy to use wss.send({...}) wherever you like.
This peace of code is working to me:
//websocket.js
'use strict';
var io = require('socket.io');
var callme;
function Websocket(server) {
var server = io(server);
server.on('connection', function(socket){
console.log('Do something here');
});
callme = function (val) {
//you my choose a specific cliente if you want, read the socket.io doc
server.emit('I may emit it ' + val);
console.log("Called " + val);
return 'Somebody got it';
}
}
Websocket.route = function(req, res, next) {
if(typeof callme == 'function'){
res.send(callme(req.param('t')));
}else{
res.send('Websocket server is not running');
}
};
module.exports = Websocket;
On the express app definition, I put
var Websocket = require('./websocket');
app.use('/blablabla', Websocket.route);
Then, on the server js file, which run the application, I put
var server = http.createServer(app);
var s = new Websocket(server);
This last line works like the tradicional io(server); would work.
After that, when you request the address /blablabla the route will execute your websocket method.
My solution is not in production yet, let me know if somebody got an error.

Simple node.js socket server

I am trying to create a simple node.js server that will allow my socket based iOS app to send it's GPS coordinates to the server, and the server will broadcast the GPS coordinate to all connected iOS clients. Similarly, the clients are connected to the server using sockets. I tried using some sample code from Heroku's web server. CODE IS EDITED TO INCLUDE ANURAG'S ANSWER
var WebSocketServer = require("ws").Server
var http = require("http")
var express = require("express")
var app = express()
var port = process.env.PORT || 5000
app.use(express.static(__dirname + "/"))
var server = http.createServer(app)
server.listen(port)
console.log("http server listening on %d", port)
var wss = new WebSocketServer({server: server})
console.log("websocket server created")
var connectionList = [];
wss.on("connection", function(ws) {
console.log("connection");
connectionList.push(ws);
})
wss.on("message", function(data, id) {
var mes = server.unmaskMessage(data);
var str = server.convertToString(mes.message);
console.log(str);
var i;
for(i = 0; i < connectionList.lenth; i++) {
wss.sendMessage(one, str, connectionList[i]);
}
});
How do I modify this code to be able to receive messages from my app (via sockets) and then send that message to all other iOS clients connected. (The message is just a simple string)
BONUS QUESTION: Because Heroku makes you use it's environments port (rather than your own specified one), in my iOS app, when I connect to the server, would I just specify the Port that is printed to the console when the server is started.
Any help is appreciated, Thank you! :)
EDIT: For broadcasting to the clients, the code is:
wss.on('connection', function(ws) {
ws.on('message', function(message) {
wss.broadcast(message);
});
});
However how do I receive messages from a client, and how do I make the received message the message to be broadcasted to the other clients.
On getting the connection you need to store those connections.
Then you can send message to all those devices connect to your server using those connections.
You may try something like this:
var connectionList = [];
wss.on("connection", function(ws) {
connectionList.push(ws);
})
wss.on("message", function(data, id) {
var mes = server.unmaskMessage(data);
var str = server.convertToString(mes.message);
console.log(str);
var i;
for(i = 0; i < connectionList.lenth; i++) {
wss.sendMessage(one, str, connectionList[i]);
}
});
Read more here: https://www.npmjs.com/package/websocketserver
Here is the complete index.js code sothat the server brodcast received messages to clients:
var WebSocketServer = require("ws").Server
var http = require("http")
var express = require("express")
var app = express()
var port = process.env.PORT || 5000
app.use(express.static(__dirname + "/"))
var server = http.createServer(app)
server.listen(port)
console.log("http server listening on %d", port)
var wss = new WebSocketServer({server: server})
console.log("websocket server created")
wss.broadcast = function(data) {
for (var i in this.clients)
this.clients[i].send(data);
};
wss.on("connection", function(ws) {
console.log("websocket connection open");
ws.on('message', function(message) {
console.log("message received by server");
wss.broadcast(message);
})
ws.on("close", function() {
console.log("websocket connection close")
})
})

How to set RedisStore -- Node, Express, Socket.io, Heroku

I'm using Node & Express 4.0 deployed on Heroku, and I'm trying to implement Socket.io with Redis as aa session store. So I have this as my current code:
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var RedisStore = io.RedisStore;
if (process.env.REDISTOGO_URL) {
// inside if statement
var rtg = require("url").parse(process.env.REDISTOGO_URL);
var redis = require("redis").createClient(rtg.port, rtg.hostname);
redis.auth(rtg.auth.split(":")[1]);
} else {
var redis = require("redis").createClient();
}
/** Initialize RedisStore for socket.io **/
io.set('store', new RedisStore({
redis : redis
}));
But I get the following error:
14:25:03 web.1 | io.set('store', new RedisStore({
14:25:03 web.1 | ^
14:25:03 web.1 | TypeError: undefined is not a function
I've also seen this way of defining a RedisStore:
var redis = require('socket.io/node_modules/redis');
var RedisStore = require('socket.io/lib/stores/redis');
However, my installed version of socket.io, installed using npm install --save socket.io, doesn't include stores in the lib directory:
EDIT
I saw this on the socket.io page in regards to their 1.0 release:
// 2. Implement the socket.io-redis adapter
var io = require('socket.io')(3000);
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));
But there's no other documentation I could find regarding this new module, and since I'm new to this whole stack, I don't think I could figure it out on my own.
The trend among node.js modules is to remove functionality that isn't truly core to the module.
Which is why socket.io 1.0 no longer supports redis out of the box.
So step one is to track down the functionality you need.
http://socket.io/docs/server-api/
https://github.com/Automattic/socket.io-adapter
https://github.com/Automattic/socket.io-redis
Then you need to install the other module npm install socket.io-redis --save
And finally configure your app.
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var redis = require('socket.io-redis');
io.adapter(redis(process.env.REDISTOGO_URL));
The nice part is the socket.io-redis adapter accepts redis urls and defaults to localhost:6379 so you (should) be able to simple pass in the REDISTOGO_URL
I had to parse libraries above to get this example, so I figured I would post a full blown example, but I must admit there are a couple of things off, this uses REDISCLOUD, it is on Heroku, it does work. I'll post this elsewhere and maybe put it in a doc too.
var redis = require('redis');
var ioredis = require('socket.io-redis'); //Adapter
var url = require('url');
var redisURL = url.parse(process.env.REDISCLOUD_URL );
var pub = redis.createClient(redisURL.port, redisURL.hostname, {return_buffers: true});
var sub = redis.createClient(redisURL.port, redisURL.hostname, {return_buffers: true});
pub.auth(redisURL.auth.split(":")[1]);
sub.auth(redisURL.auth.split(":")[1]);
var redisOptions = {
pubClient: pub,
subClient: sub,
host: redisURL.hostname,
port: redisURL.port
};
io.adapter(ioredis(redisOptions));
Following code works for me with Heroku Redis, hope this helps.
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var redis = require('redis');
var redisAdapter = require('socket.io-redis');
io.adapter(redisAdapter({
pubClient: redis.createClient(process.env.REDIS_URL, {return_buffers: true}),
subClient: redis.createClient(process.env.REDIS_URL, {return_buffers: true})
}));
For the ones interested,
this is my prototype chat server running on newest socket.io with express, multiple cores and redis as an intermediate.
Broadcasted messages are send to all room users no matter if they are connected to a different node and port instance.
Just run
node server.js
and on other machines
node client.js
or for testing node client.js 7001, 7002, 7003 ......
server.js
var options = {
//workers: 2, // total workers (default: cpu cores count).
first_port: 7000, // 8000, 8001 are worker's ports (default: 8000).
proxy_port: 5000, // default (5000).
session_hash: function (req, res) { return req.connection.remoteAddress; },
no_sockets: false // allow socket.io proxy (default: false).
};
require('sticky-socket-cluster')(options, start);
function start(port) {
// requirements
var express = require('express');
var http = require('http');
var socketio = require('socket.io');
var path = require('path');
var sticky = require('sticky-session');
var app = express();
var server = http.createServer(app);
var io = socketio.listen(server);
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));
server.listen(port, function() {
console.log(' - listening on ' + port+ ' ' + __dirname);
});
// require our chatserver
var ChatServer = require('./chatserver');
// initialize a new chat server.
new ChatServer({io: io, port: port}).init();
}
chatserver.js
RoomUtil = (function(){
roomMessages = {};
return {
getMessages : function(room_id,limit,cb){
//TODO
cb(roomMessages[room_id] || []);
},
postMessage : function(message,room_id,cb){
if (!roomMessages[room_id]) roomMessages[room_id] = [];
roomMessages[room_id].push(message);
cb();
}
}
})();
var Server = function(options) {
var self = this;
self.io = options.io;
// users array
self.users = [];
// initialize function
self.init = function() {
console.log("init");
// Fired upon a connection
self.io.on('connection', function(socket) {
console.log("incoming connection");
// var ru = new RoomUser();
self.handleConnection(socket,options.port);
});
}
// socket handler for an incoming socket
self.handleConnection = function(socket,port) {
// wait for a login message
socket.emit("incoming connection",{});
socket.on("joinroom",function(data,joinroom_callback){
console.log("attempt to join room ",data.room_id," on port ",port);
if (!data.room_id){
console.log("cannon join room -> no room id given");
return socket.disconnect();
}
else{
var room_id = data.room_id;
socket.join(room_id,function(){
console.log(socket.rooms);
RoomUtil.getMessages(data.room_id,50,function(messages){
console.log("client succesfully joined room ",data.room_id);
joinroom_callback(null,{'messages':messages});
});
socket.on("login",function(data,login_callback){
if (!data.username){
login_callback("invalid userdata",null);
}
else{
login_callback(null,1);
socket.on("post_message",function(data,message_callback){
if (!data.message || data.message == ""){
console.log("empty message posted. ignore");
message_callback("invalid_message",null);
}
else{
console.log("received message on port ",port,data.message);
message_callback(null,1);
RoomUtil.postMessage(data.message,room_id,function(){
RoomUtil.getMessages(room_id,50,function(messages){
console.log("emit messages to room id ",room_id);
//socket.to(room_id).emit('update_messages', messages);
//socket.broadcast.to(room_id).emit('update_messages', messages);
//socket.broadcast.to(room_id).emit('update_messages', messages);
//self.io.to(room_id).emit('update_messages', messages);
self.io.in(room_id).emit('update_messages', messages);
});
})
}
});
}
});
});
}
});
}
}
module.exports = Server;
client.js
var servercon = 'http://localhost:'+(process.argv[2] || 5000);
console.log("going to connect to "+servercon)
var socket = require('socket.io-client')(servercon);
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
socket.on('connect', function(){
console.log("connected, going to login");
socket.emit("joinroom",{"room_id":123123}, function(error,data){
if (error){
console.log("cannot join room ",error);
}
else{
console.log("succesfully joined room -> going to login now");
console.log("received messages count",data.messages.length);
socket.emit("login",{username:"John Mckain"}, function(error, message){
if (error){
console.log("error logging in ",error);
}
else{
console.log("logged in succesfully -> post message now");
var readline = function(){
rl.question("type in a message -> ", function(message) {
socket.emit("post_message",{'message':message}, function(error, message){
if (error){
console.log("error posting message");
readline();
}
else{
console.log("succesfully posted message");
readline();
}
});
});
}
readline();
}
});
socket.on("update_messages",function(data){
console.log("received new messages count ",data.length,data);
});
}
});
});
socket.on('event', function(data){
console.log("event send",data);
});
socket.on('disconnect', function(e){
console.log("disconnected",e);
});
socket.on("welcome",function(data){
console.log("on welcome ",data)
})
socket.on("pong",function(e){
console.log("pong")
})

Unable to receive messages in browser client

I'm unsuccessfully attempting to create an pub-sub instant messaging service. I am unable to receive messages in browser client.
The following code is from my client1.html file. I believe the trouble I'm having relates to the client unsuccessfully subscribing to '/channel'. I've added the alerts and am receiving the 'BEFORE & AFTER' but not the 'DURING' and the message.text is not appearing on the console. Any thoughts as to why a client cannot see the messages on the browser would be appreciated.
var client = new Faye.Client('/faye',{
timeout: 20
});
alert("BEFORE client subscription");
client.subscribe('/channel', function(message) {
$('#messages').append('<p>' + message.text + '</p>');
alert("DURING client subscription");
console.log(message.text);
});
alert("AFTER client subscription");
The browser console repeats the following error repeatedly:
POST http://my.server#server:8000/faye 404 (Not Found)
This error points to 'faye-browser.js:2023' which refers to the following line:
xhr.send(Faye.toJSON(message));
EDIT
This is is the server.js file
var fs = require("fs");
var config = JSON.parse(fs.readFileSync("config.json"));
var host = config.host;
var port=config.port;
var express = require("express");
var Faye = require('faye');
var bayeux = new Faye.NodeAdapter({mount: '/faye', timeout:45});
var app = express();
app.configure(function(){
app.use(express.bodyParser());
app.use(express.static('/'+__dirname));
});
app.post('/message', function(request, response){
bayeux.getClient().publish('/channel', {text:request.body.message});
console.log('broadcast message:' + request.body.message);
response.send(200);
});
bayeux.attach(app);
app.listen(port);
I've just configured Faye for our application, you are doing
bayeux.attach(app);
app.listen(port);
did not work for me, what worked is this
bayeux.attach(app.listen(port, function() {}));
I also think that you should use the whole url when you are creating Faye, not just the final part, like so:
var client = new Faye.Client('http://my.url.com/faye', { timeout: 20 });

Resources