Acknowledgment for socket.io custom event - javascript

I am looking for a method to acknowledge a socket.emit call.
socket.emit('message', msg);
I have seen a mechanism where the receiver would send another custom event as an acknowledgement, but this would add thousands of transports in my chat application. Please advice an efficient method.

The third argument to the emit method accepts a callback that will be passed to the server so that you can call in acknowledgement with any data you wish. It's actually really convenient and saves the effort of having paired call-response events.
I'm updating my answer with some code that I just tested.
First on the server side:
io.sockets.on('connection', function (sock) {
console.log('Connected client');
sock.emit('connected', {
connected: 'Yay!'
});
// the client passes 'callback' as a function. When we invoke the callback on the server
// the code on the client side will run
sock.on('testmessage', function (data, callback) {
console.log('Socket (server-side): received message:', data);
var responseData = {
string1: 'I like ',
string2: 'bananas ',
string3: ' dude!'
};
//console.log('connection data:', evData);
callback(responseData);
});
});
On the client side:
console.log('starting connection...');
var socket = io.connect('http://localhost:3000');
socket.on('error', function (evData) {
console.error('Connection Error:', evData);
});
// 'connected' is our custom message that let's us know the user is connected
socket.on('connected', function (data) {
console.log('Socket connected (client side):', data);
// Now that we are connected let's send our test call with callback
socket.emit('testmessage', {
payload: 'let us see if this worketh'
}, function (responseData) {
console.log('Callback called with data:', responseData);
});
});

Related

How to get the socket object of each connected user in nodejs?

I am using socket.io to emit notification for users.
I have a listener that watch for an event.
myEvent.watch ((res,err)=> {
if (!err) {
let id = res.userID;
let msg = res.msg;
//to implement
sendMessage(id, msg);
}
}
And I want to emit a message using socket.io to the concerned user.
I am thinking about storing socket object in memory by userID;
io.on('connection', function (socket) {
// memoryStroage is a key-value sotrage.
memoryStorage.put(socket.id, socket);
socket.on('message', function (data) {
console.log(data);
});
});
and then in the sendMessage service:
function sendMessage(id, msg) {
let socket = memoryStroage.get(id);
socket.emit('new-message', msg);
}
I want to is that a good way ?
You should use socket.io rooms.
Each Socket in Socket.IO is identified by a random, unguessable,
unique identifier Socket#id. For your convenience, each socket
automatically joins a room identified by this id.
So if you have the socket id, you can use:
function sendMessage(id, msg) {
io.to(id).emit('new-message', msg);
}
You can use a custom user id too, using socket.join
io.on('connection', function(socket) {
// memoryStroage is a key-value sotrage.
const userId = getUserId(socket); // Get logged user Id somehow
socket.join(`user-${userId}`);
/* ... */
});
function sendMessage(id, msg) {
io.to(`user-${id}`).emit('new-message', msg);
}

AWS Cognito Identity JS: Forget/Remember/Do Not Remember Device

I'm working with the AWS Cognito Identity JS SDK (https://github.com/aws/amazon-cognito-identity-js) and I'm trying to set up a few buttons to test the setDeviceStatusRemembered, setDeviceStatusNotRemembered, and forgetDevice functionality but I keep getting an error saying:
MissingRequiredParameter: Missing required key 'DeviceKey' in params
Here is an implementation of one of the functions:
forgetDevice = function(){
var cognitoUser = userPool.getCurrentUser();
if (cognitoUser != null) {
cognitoUser.getSession(function(err, session) {
if (err) {
alert(err);
signOut();
return;
}
console.log('session validity: ' + session.isValid());
cognitoUser.forgetDevice({
onSuccess: function (result) {
console.log('call result: ' + result);
},
onFailure: function(err) {
alert(err);
}
});
});
}
}
If I change up the function like this:
forgetDevice = function(cognitoUser){
cognitoUser.forgetDevice({
onSuccess: function (result) {
console.log('call result: ' + result);
},
onFailure: function(err) {
alert(err);
}
});
}
and I call the function from the cognitoUser.authenticateUser success callback function, passing cognitoUser as argument into the forgetDevice function above everything works perfectly.
From looking at the session object in the first implementation it appears that the session object does not contain the DeviceKey property so the cognitoUser.forgetDevice() call fails.
What I'm trying to figure out is, should I just be calling the setDeviceStatusRemembered, setDeviceStatusNotRemembered, and forgetDevice functions on login, or should I be able to call them any time within my application? Hopefully that makes sense. Any help would be greatly appreciated. Thanks!
Does this help:
Note that if device tracking is enabled for the user pool with a setting that user opt-in is required, you need to implement an onSuccess(result, userConfirmationNecessary) callback, collect user input and call either setDeviceStatusRemembered to remember the device or setDeviceStatusNotRemembered to not remember the device.
http://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-device-tracking.html
Also can you attempt calling getCachedDeviceKeyAndPassword to populate the deviceKey in the CognitoUser object?

Node.js BinaryServer: Send a message to the client on stream end?

I'm using a node.js BinaryServer for streaming binary data and I want a callback event from the server, after the client calls for the .Stream.end() function.
I can't seem to understand - How can I send a message or some kind of notification when the node.js server actually closes the stream connection ?
Node JS:
server.on('connection', function(client) {
client.on('stream', function (stream, meta) {
stream.on('end', function () {
fileWriter.end();
// <--- I want to send an event to the client here
});
});
});
client JS:
client = new BinaryClient(nodeURL);
window.Stream = client.createStream({ metaData });
....
window.Stream.end();
// <--- I want to recieve the callback message
On the server side, you can send streams to the client with .send. You can send a variety of data types, but a simple string will probably suffice in this case.
On the client side you can also listen to the 'stream' event to receive data back from the server.
Node JS:
server.on('connection', function(client) {
client.on('stream', function (stream, meta) {
stream.on('end', function () {
fileWriter.end();
client.send('finished');
});
});
});
client JS:
client = new BinaryClient(nodeURL);
client.on('stream', data => {
console.log(data); // do something with data
});
window.Stream = client.createStream({ metaData });
....
window.Stream.end();

Mocha: testing event receiver

I have been trying to test this code with no luck.
The logic:
This code will connect two clients -Client1 and Client2-, then Client1 will send a message to Client2 - thru a server. When the Server receives the message from Client1, it (the server) will respond to Client1 with an acknowledge message, and then, it will send the new message thru the 'newMessage' event.
The test:
Each client always listens to 'newMessage' event. In this test I want:
a. Connect Client1 and Client2 to server
b. Send a message from Client1 to Client2
c. When Client2 receives the 'newMessage' event, check the incoming data
I dont know if this is possible, all my approaches failed, but in fact, the application works.
describe('> Test case:\n', function () {
describe('> Connect Client1 & Client2', function () {
this.timeout(2000);
// Instantiate testing clients
var client1 = new virtualClient(),
client2 = new virtualClient();
beforeEach(function (done) {
// Connect the test clients
Promise.all([client1.connect( users[0] ), client2.connect( users[1] )]).then(function () {
// When both clients are connected, set a callback function to handle 'newMessage' event on Client2 (I wonder where to test this...)
client2.client.setNewMessageCallback(function(data) {
console.log("-----> Client2 received 'onNewMessage' broadcast");
// Can I use a it() here?
});
done();
}).catch(function (error) {
console.log(error);
});
});
describe('Client1 sends a message to room with Client2', function () {
// I now send a message from Client1 to Client2: this will make
// the server fire the 'newMessage' event and Client2 should
// receive it
it('- Client1 sends a message to Client2', function (done) {
client1.client.sendMessage(client2.data.user._id)
.then(function (response) {
// Should return an Object with properties 'roomId' and 'localRoomId'
response.should.be.an.instanceOf( Object );
done();
});
});
});
});
});

Why is my Meteor app logging to server but not client?

I'm building a meteor app that hooks into the twitter api and I've had no luck so far getting it to work. I'm using the twit package to make the call on the server side, and it logs the data to the server console, but when the client console goes to log it there is no data.
The client doesn't throw an error, it runs the console.log in the else statement for the result parameter, but it comes through as undefined. It's as if the result callback runs before the data comes back, but my understanding of the Meteor.call method is that it's supposed to wait until it hears back from the server before it runs.
What am I doing wrong here?
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to testing.";
};
Template.hello.recentFollows = function () {
return Session.get("recentFollows");
};
Template.hello.events({
'click #fetchButton': function () {
console.log("Recent tweets from stream!");
userName = "josiahgoff";
Meteor.call('getBananaTweets', function(err, result) {
if(err) {
console.log("error occurred on receiving data on server. ", err);
} else {
console.log("result: ", result);
Session.set("recentFollows", result);
}
});
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
Twit = new TwitMaker({
consumer_key: '******',
consumer_secret: '******',
access_token: '******',
access_token_secret: '******'
});
});
Meteor.methods({
getBananaTweets: function () {
Twit.get('search/tweets', { q: 'banana since:2011-11-11', count: 1 }, function(err, result) {
if (err) {
console.log("Error", err);
return err;
} else {
console.log(result);
return result;
}
});
}
});
}
You are using return in your server code in a place where it must not be used: in an asynchronous call-back. The Twit.get call returns immediately and the function ends (with no return value). So the client doesn't receive anything. Some time later the Twit.get comes back, but the return in that case goes nowhere.
This is a pretty common question. The solution is to wrap your Twit.get call into a fiber in some shape or form to make it synchronous. See for instance this answer: Iron Router Server Side Routing callback doesn't work

Categories

Resources