I implemented one to one chat , and while sending message i publish message in controller as
$redis->publish('message', json_encode($data));
Now in server.js i subscribe message for each connection. and i send that message to particular user by selecting specific socket from pool. My issue is that my each message send to receiver multiple times equal to number of connection. my code in server.js is
io.on('connection', function (socket)
{
clients[socket.id] = socket;
var redisClient = redis.createClient();
redisClient.subscribe('message');
redisClient.on("message", function(channel, message)
{
var data = JSON.parse(message);
console.info("sent");
if(typeof connectedClients[data['receiver']] === 'undefined'){}
else
{
connectedClients[data['receiver']].socket.emit(channel, message);
}
});
Related
I am new to Nodejs and Socket.io, and this is first time when I am creating any chat application, so pardon me if I am asking some silly question.
In my web I have to kind of chat services, one is Live debate which is kind of chat room, and another one is private messaging like Facebook Messenger.
I have created both, in private messenger before showing the message I am checking the conversation Id, it's working quite appropriately. Live debate is also working appropriately.
But there is a issue, any message sent in private messenger displays in live debate window also. So I change the Server.js file for messenger and also changed the listening port, now the listening port for live debate is 3000 and for messenger is 8050, but still Live debate receiving the messenger messages.
Am I doing this in wrong way? Is there any other way to run two chat applications ?
I am using this server code
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var redis = require('redis');
server.listen(3000);
io.on('connection', function (socket) {
console.log("client connected");
var redisClient = redis.createClient();
redisClient.subscribe('message');
redisClient.on("message", function(channel, data) {
console.log("mew message add in queue "+ data+ " channel");
socket.emit(channel, data);
});
socket.on('disconnect', function() {
redisClient.quit();
});
});
With using Namespace
server.js
var nsp = io.of('/debate')
nsp.on('connection', function (socket) {
console.log("client connected"+socket.id);
var redisClient = redis.createClient();
redisClient.subscribe('message');
var redisClient1 = redis.createClient();
redisClient1.subscribe('debate');
redisClient.on("message", function(channel, data) {
console.log("mew message add in queue "+ data+ " channel");
nsp.emit(channel, data);
});
socket.on('disconnect', function() {
redisClient.quit();
});
});
client code
var socket = io.connect('http://localhost:3000/debate');
socket.on('message', function (data) {
data = jQuery.parseJSON(data);
console.log(data.user);
$( "#messages" ).append( "<strong>"+data.user+":</strong><p>"+data.message+"</p>" );
$('#messages').animate({
scrollTop: $('#messages').get(0).scrollHeight}, 200);
});
socket.io supports the use of different namespaces. You should use that feature instead of creating two individual servers. After that you can use socket.emit to that specific namespace. For more information see the documentation: https://socket.io/docs/rooms-and-namespaces/
It's not too difficult, I wrote a chat app, as I think everyone does when they start nodejs, but nodeJS has rooms which are quite easy to use.
io.on('connection', function(client){
client.on('room_connection', function(id){
client.join(id); // User joins room.
})
client.on('message', function(data){
io.to(data.room).emit('message', {message:data.message, client:client.conn.id});
});
})
This is pretty much all you need. This works for PM's since u simply won't allow multiple users to join this chatroom, and normal chatrooms which multiple users can join.
I'm trying to build a secure private facebook like messaging system using laravel, redis pub/sub and socket io. All the console.log functions log the messages to say everything went through on the node server and everything works fine untill I try and emit the message to the client. When I try to emit the message to the client nothing at all happens.
Although I don't think my controller method on laravel is of significance here it is anyway. You can skip the Laravel controller if it's not necessary
Laravel Message Controller:
public function store($id, Request $request)
{
//Stores message in $message
//Connects redis
$redis = Redis::connection();
$data = ['message' => $request->input('message'), 'user' => Auth::user()->name,
'room' => $message->conversation_id];
$redis->publish('message', json_encode($data));
return Redis::get('message');
response()->json([]);
}
Redis stuff being published in JSON output:
{message: 'some message', user: 'john doe', room: 1}
Node Server
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var redis = require('redis');
server.listen(3000);
io.on('connection', function (socket) {
console.log("client connected");
var redisClient = redis.createClient();
redisClient.subscribe('message');
redisClient.on("message", function(channel, data) {
data = JSON.parse(data);
socket.join(data.room, function() {
console.log('Joined room '+data.room);
});
console.log("new message add in queue "+ data.room + " channel");
socket.to(data.room).emit(channel, data);
});
socket.on('disconnect', function() {
redisClient.quit();
});
});
Client Side JS
var socket = io.connect('http://localhost:3000');
socket.on('message', function (data) {
//Just console the message and user right now.
console.log(data.message+" " + data.user);
});
I don't know if my problem is that I'm not specifying the room on the client. If so is there any way of emitting the data to the client without specifying the room in the client side code? Why can't I emit the message to the client?
I m actually trying to implement the pub/sub pattern using node-amqp (https://github.com/postwait/node-amqp).
I have some problems to implement it.
What I need :
Publish message from a user
Broadcast it to others user
Sending the message to offline users that will consume it the next time they'll be connected
What I've actually :
(function () {
var amqp = require('amqp');
var connection = amqp.createConnection({ host: 'http://127.0.0.1:5672/' });
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
server.listen(8888);
// Wait for connection to become established.
connection.on('ready', function () {
var sendMessage = function (queue, msg) {
connection.publish(queue, JSON.stringify(msg));
}
io.sockets.on('connection', function (socket) {
socket.on('message', function (msg) {
sendMessage('my-queue', msg);
});
connection.queue('my-queue', {autoDelete: false}, function (q) {
q.bind('#');
q.subscribe(function (message) {
socket.broadcast.emit('news',message);
});
});
});
});
})()
On the index.html page, I connect to the socket server
I have a button that send a message
I open two different browser on the index page, and my users are both connected
If I send a message to the server, it send it to the other users
If I send a second message to the server, it send the message to the user that sent the message.
It's switching, every pair message (because I have two users), the other users get the message, if it's an impair message, the current user sending the message receive the message.
What is this behaviour ?
Can you help me correcting my code to implement my needs a good way ?
NB : I use RabbitMQ with standard config on a windows 7 x64 computer
EDIT : I made a solution and every consumer can get the message with :
(function () {
var amqp = require('amqp');
var connection = amqp.createConnection({ host: 'http://127.0.0.1:5672/' });
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
server.listen(8888);
// Wait for connection to become established.
connection.on('ready', function () {
connection.exchange('logs', {type: 'fanout', autoDelete: false}, function (exchange) {
var sendMessage = function (queue, msg) {
exchange.publish(queue, JSON.stringify(msg));
}
io.sockets.on('connection', function (socket) {
socket.on('message', function (msg) {
sendMessage('', msg);
});
connection.queue(socket.id, {exclusive: true}, function (q) {
q.bind('logs', '');
q.subscribe(function (message) {
socket.emit('news', message);
});
});
});
});
});
})()
My last problem is that I cant manage offline messages now... Any solutions ? (bounty end tomorrow :-/)
The problem is RabbitMQ will send each message to a single user on purpose. That user acknowledges that it received the message (amqp does this for you automatically) and then the work is done as far as RabbitMQ is concerned, so it deletes the message.
The reason your users take turns receiving a message is that RabbitMQ tries to spread to load of incoming messages evenly over users.
Your question has been answered before here. Check it out for a solution to your problem!
You need to create separate queues for each of the consumers (in your case - users), and route messages to all of them from exchange. That way, when you publish a message, it will be placed in all users' queues, from which each of them will be able to consume it independently.
You have this:
http://www.rabbitmq.com/tutorials/tutorial-two-python.html
And you need this:
http://www.rabbitmq.com/tutorials/tutorial-three-python.html
I have some process:
var fetcher = new Fetcher({ url: 'http://www.example.com' });
setInterval(function() {
fetcher.getImageUrls().then(saveToDb, handleError, notifyProgress);
}, 10000);
I also have a website, I want to use socket.io for pushing updates
about the progress (using the notifyProgress method). I don't know
how to sync the website with the process.
note that i can't use events because the process can live anywhere (i can also duplicate the process with more instances)
How can i do that?
Thanks
You want to use Redis to create a PUB/SUB system.
You will publish to the channel your updates;
// notifyProgress.js
var Redis = require('redis'),
redis = Redis.createClient(6379, 127.0.0.1);
module.exports.publish = function (req, res, next) {
//publish to the mySpecialChannel channel.
redis.publish('mySpecialChannel', data);
};
your different servers/clusters will subscribe to the channel.
//socket server
var Redis = require('redis'),
redis = Redis.createClient(6379, 127.0.0.1),
app = express(),
server = require('http').createServer(app),
io = require('socket.io')(server);
redis.on('subscribe', function (channel, count) {
console.log('server subscribed to %s', channel);
});
redis.on('message', function (channel, message) {
if (channel === 'mySpecialChannel') {
//send info to your clients.
io.emit('update', message)
}
});
redis.subscribe('mySpecialChannel');
I'm trying to get Redis pub/sub working in a little Node app. Currently I'm using node-redis and I don't understand the API for pub/sub. It seems like I can subscribe to a channel by name and then I receive all messages for all channels in a generic 'message' event, like so:
var express = require('express')
, app = express()
, server = app.listen(4000)
, sio = require('socket.io')
, io = sio.listen(server)
, db = require('redis').createClient();
io.sockets.on('connection', function (socket) {
db.subscribe("foo");
db.subscribe("bar");
db.on("message", function(channel, message) {
socket.emit('message', message);
});
});
This forces me to either create a new client for each subscription or to use something like:
db.on("message", function(channel, message) {
socket.emit(channel, message);
});
and then listen to the right socket.io channel client side. Neither is ideal for me.
What I would like is to register a callback at the time of subscribing so, I receive messages for that channel only, like in this pseudo code snippet:
db.subscribe("foo", function(message) {
socket.emit("foo_message", message);
});
db.subscribe("bar", function(message) {
socket.emit("bar_message", message);
});
Does anybody know a clean solution for my problem or maybe another redis API that supports my wishes?