I have a redis connection subscribed to a channel with a get request
app.get('/wait', function (req, res) {
redisSub.on('message', function(channel, msg) {
console.log('rcv: ' + msg);
});
});
And later with a different get request I send the message
app.get('/done/:msg', function (req, res) {
redisPub.publish('message', req.params.msg);
});
The problem is that I want that request to stop listening for messages once it gets it. Or else when I go through again it will still be listening and will get the next message again. I'm not sure how to remove the listener from itself once the message is received.
Not tested but this should work,
var callback = function(channel, msg) {
console.log('rcv: ' + msg);
redisSub.removeListener('message', callback);
}
redisSub.on('message', callback);
Related
I am setting up a web socket server with socket.io and it seems like that messages are sent at least twice. Sometimes even trice. (very rarely even 4+ times) They are never sent once though. How should I setup my handlers or my client code so every message is received exactly once all the time?
My client is in swift and my server in node.js. I am running Ubuntu 16.04 on the server itself.
Node.js:
// Here is an array of all connections to the server
var connections = {};
io.sockets.on('connection', newConnection);
function newConnection(socket) {
socket.on('add-user', function(user) {
connections[user.id] = {
"socket": socket.id
};
});
socket.on('chat-message', function(message) {
console.log(message);
if (connections[message.receiver]) {
console.log("Send to: " + connections[message.receiver].socket);
// Here are some varients of the emit command. Seems like they all do the same
//io.sockets.connected[connections[message.receiver].socket].emit("chat-message", message);
//io.to(connections[message.receiver].socket).emit("chat-message", message);
socket.broadcast.to(connections[message.receiver].socket).emit("chat-message", message);
} else {
console.log("Send push notification")
}
});
//Removing the socket on disconnect
socket.on('disconnect', function() {
console.log("The client disconnected");
for (var id in connections) {
if (connections[id].socket === socket.id) {
delete connections[id];
}
}
})
}
The "console.log(message);" in the messages handler is only called once. That's the confusing part for me. If the handler is called twice, why is this only printed once? Still, on the handler in my swift code, the handler for received messages is called multiple times.
I'm trying to send news to my client. On connect, it works great, but for some reason on broadcast2 it wont get any response client sided, even know its the same piece of code, and even that broadcast2's console.log is working.
Q: How can i make sure broadcast2 emit will work?
This works:
socket.on('message', function (data) {
console.log('message gotten');
socket.emit('news', { message: 'xxxx' });
});
this wont work:
socket.on('broadcast2', function (data) {
console.log("broadcast revieced");
socket.emit('news', { message: 'xxxx' });
});
this is node.js response:
total code in node.js
socket.on('message', function (data) {
console.log('message gotten');
});
socket.on('another-message', function (data) {
socket.emit('not-news', { hello: 'world' });
});
socket.on('broadcast2', function (data) {
console.log("broadcast revieced");
socket.emit('news', { message: 'xxxx' });
});
and this on the client side:
var socket = io.connect('mysite:8080');
function sender() {
console.log('sending tester');
socket.emit('sendertester', 2);
}
socket.on('connect',function(){
});
socket.on('tester', function(msg){
console.log("callback");
});
socket.on('news', function(message) {
console.log("INCOMMING NEWS");
console.log(message);
});
UPDATE 1:
The broadcast2 socket, sent by PHP:
function broadcast($message,$broadcast = 'broadcast2') {
$client = new Client(new Version1X('myurlhidden:8080'));
$client->initialize();
$client->emit($broadcast, ['message' => $message]);
$client->close();
}
UPDATE 2:
**Question two: Cause my broadcast2 is sent before the client sided is loaded, and then the client connects to the node, could that be the cause?
But in the same time, im already preloading the class that holds the broadcast2 emitter.
Using codeigniter framework.**
UPDATE 3
I was trying to check my theory on update 2, by having two users logged in, while user one trying to perform the trigger. user two gets no output, so i suppose that theory is busted.
The server cannot send a message to any socket before it is connected. You have to wait until you have something listening to receive what you are sending.
I wouldn't call close after the emit either, as you may close the connection before the client has received the message, emit doesn't wait for the client to receive the data before returning its asynchronous.
Instead let the clients close the connections when they terminate.
I have set up sockets on my client and server, but I can't seem to get my data to come into my client. It seems they are connecting properly, I just can't get any data to come through. There are no error messages either.
Here is my server code:
io.on('connection', function (socket) {
console.log('a user connected');
socket.on('custom-message', function () {
console.log("Hitting messages socket");
Message.find(function(err, messages){
if(err){
socket.emit('custom-message', err)
} else {
socket.emit('custom-message', messages);
}
})
});
});
Here is the function in the client that connects to the socket:
loadMessagesFromServer: function(){
console.log("About to load messages")
socket.on('custom-message', function(msg){
console.log("connected in client", msg)
});
},
Like I said it is a pretty simple example, I just can't seem to get the data in loadMessagesFromServer .. And there are no erros, the only way I have been debugging is trying different things..
You are listening on the event messages. So you need to emit the same event not socket.emit('messages: err', err). Try with socket.emit("messages", error). Moreover, in your server-side code, you need first to receive a message event and only then your socket will emit the messages. Remove the socket.on(custom-messages). Why do you need it?
Server-side code
io.on('connection', function (socket) {
/* Here a client connection is established. The on("connection")
* event will be triggered as many times as`io.connect("the-uri")`
* is triggered (and succeeded) in the client`
*/
// Listening for the post event
socket.on("post", function(messages){
console.log("client posted data:", messages)
// Find messages and emit result
Message.find(function(err, messages){
if(err){
socket.emit('error', err)
} else {
socket.emit("message", messages);
}
});
});
});
Client-side code
registerOnMessageFromServerListener: function(){
socket.on("message", function(msg){
console.log("received message:", msg);
});
registerOnErrorFromServerListener: function(){
socket.on("error", function(error){
console.log("an error occured:", error);
});
registerOnMessageFromServerListener();
registerOnErrorFromServerListener();
socket.emit("post", "a-message");
Also make sure that you call the loadMessagesFromServer before you establish the socket connection
I wondered if someone could help figure out what I am doing wrong:
My client web page initiates a connection with my server, and listens to a long running process whose state is getting updated in the db by a worker process on another thread, emitting updates back to the browser. I define a socket.io connection in the app.post() method. This is handled by the poll() function below (scroll down a bit past the invite checking code)
However, when a new web client connects, it's messages get added to the previous client's as if there were just one channel. Why isn't there a separate unique channel for each browser?
//Create server
var express = require('express'),
app = express(),
http = require('http'),
server = http.createServer(app),
io = require('socket.io').listen(server);
io.set('log level', 1); // reduce logging
io.configure(function () {
io.set("transports", ["xhr-polling"]);
io.set("polling duration", 10);
});
app.post('/api/users', function (req, res) {
if (!req.body.auth.accessToken) {
req.body.auth.accessToken = req.body.auth.authResponse.accessToken;
} //fb return object is different depending on whether it is a first login or subsequent
logger.log('debug', '/api/users:POST', req.body);
io.sockets.on('connection', function (socket) {
socket = socket;
socket.emit('update', {
status: 200 //send initialization ping
});
//check if user has valid invite, if not try to invite
db.getTotalUserInvites(function (err_inv, res_total) {
db.getUserInvite(req.body.fid, function (err_check, res_check) {
logger.log('debug', 'Total invites issued=' + res_total);
//process report - all we need is accesToken, processReport will do the rest
mine_fb.processUser(req.body.auth.accessToken, socket, function (User,socket) { //pass channel properly
db.getReportStatus(User.fid,socket, function (result,socket) {
logger.log('debug', 'report status', result);
if (result) {
if (socket && (result.report_status == -1)) {
logger.log('debug', 'report already processed. retrieving uniq_id ' + result.uniq_id);
socket.emit('update', {
status: -1,
uniq_id: result.uniq_id
});
return true;
} else {
if (socket && (result.report_status >= 0)) {
logger.log('debug', 'we are in the middle of processing report ' + result.uniq_id);
//in this case we become a listener and not a speaker
function poll(socket) {
db.getReportStatus(User.fid, socket,function (r,socket) {
socket.emit('update', { //!!!! THIS EMITS TO ALL CONNECTED BROWSERS
status: r.report_status,
uniq_id: r.uniq_id
}); //...socket
if ((r.report_status >= 0) && (socket)) {
logger.log('debug', 'polling...');
_.delay(poll, 2000, socket);
}
}); //get rerpot
}; //end poll
socket.on('disconnect', function () {
socket=null;
});
poll(socket);
} // else we're in the middle
} //done checking status
} //end of seq
});
return res.send();
});
});
});
});
});
While it is not clear how to help you I can tell what's going on in your code:
app.post('/api/users', function (req, res) {
// some code
io.sockets.on('connection', function (socket) {
// some code
});
});
Whenever a user POSTs something to /api/users a new handler is attached to io.sockets (that's what .on does). But these handlers are never removed, so each time a new connection is established all attached handlers fire. That's where your broadcasting comes from.
You have to separate app.post(...) from io.sockets.on('connection',...) (they should be independent, both defined at module level, not nested). I'm sure it won't be easy (you will probably have to authenticate a user twice for example) but that's the only reasonable way.
You shouldn't put your io.sockets.on('connection', function (socket) inside the app.post scope.
Just put it outside and try again, it will probably work correctly.
Listening to connexion should be done once when the server starts, not each time a client hits some URL.
My server emits events properly, but the emit callback never works. In the following, nothing is logged on my console:
Server:
io.sockets.emit('delete hint', {id: id}, function(data){
console.log('callback');
});
Client:
socket.on('delete hint', function(data){
// display a message before deleting
$('#' + data.id).fadeOut(function(){
$(this).remove();
});
});
I've also tried the client side code as function(data, fn) in case the callback needed to be included on the receiving function.
I'm using windows and my command prompt shows the following when socket.io is emitting the event:
websocket writing 5:::{"name":"delete hint", "args":[{"id":"1"}, null]}
I can't figure out what the problem is, what am I doing wrong?
A callback is executed on the sender computer when the receiver computer calls it
Have a look at this code:
Server:
io.sockets.on('connection', connectionFunc);
function connectionFunc (socket) {
socket.emit('delete hint', "data for client", callThis);
}
//this function is executed when client calls it
function callThis (dataFromClient){
console.log("Call back fired: " + dataFromClient);
}
Client:
socket.on('delete hint', function(data, callback) {
console.log("i received: "+ data);
// call back will fire only when u the next line runs
callback("the callThis function on server will run");
});
You can do this the opposite way.
You need to call the callback.
socket.on('delete hint', function(data, cb){
// display a message before deleting
$('#' + data.id).fadeOut(function(){
$(this).remove();
cb(null, 'done');
});
});