Extract callback function from payload - node.js

I am using Node.js for emitting event to socket via socket.emit(eventName[, ...args][, ack]).
On client side, an Arduino, I'm using the SocketIoClient.h library (link: https://github.com/timum-viw/socket.io-client).
So the server is sending an event and a callback function as
socket.emit("event",function(x){
console.log(x);
})
which is received on the client side in payload field as
clientSocket.on("event",event);
void event(const char * payload, size_t length);
How can I call this callback function from the client side, which is supposed to be present in the payload?

If I understood you correctly, you are trying to use the acknowledgement mechanism offered by Socket.IO (I inferred this from the tags of your question).
For more details, refer to
https://socket.io/docs/server-api/#socket-emit-eventname-args-ack
Acknowledgment for socket.io custom event
This mechanism is specific to the Socket.IO library and therefore can't be used if you are not using it on both the client and the server sides.
As an alternative, I would suggest to dedicate a specific event to the acknowledgement you wish to have. In other words, when your client receives your event "event", it will send a "received" event to the server as acknowledgement along with the data your callback should be called with.
For instance on your server you would have:
socket.on("received", function (x) {
console.log(x); //Will display "Yay! Got it!"
});
socket.emit("event");
and on the client something like
socket.on("event", function () {
socket.emit("received", "Yay! Got it!");
});
(I'm not familiar with the C library you use but the point is the underlying logic).

Related

Uncaught TypeError: socket.to is not a function

I want to emit some data to a room in socket.io.
According to the socket.io docs,
In one place (https://socket.io/docs/rooms-and-namespaces/#Joining-and-leaving) it is said,
io.to('some room').emit('some event');
And in another place (https://socket.io/docs/emit-cheatsheet/) it is said,
socket.to('some room').emit('some event', "description");
I tried both of these but got the error,
uncaught TypeError: io.to is not a function
and
uncaught TypeError: socket.to is not a function
All other socket.io functions i used worked except for this
I included
<script src="/socket.io/socket.io.js"></script>
in the head tag of the html file.
In the client side js file, i incuded
const socket = io.connect("http://localhost:3000/");
Also, I used socket.emit and it works the way it is supposed to.
Please tell me what is wrong with this..
If this Uncaught TypeError is happening on your client side, that's because io.to and socket.to are only server-side functions, and cannot be used on the client side. In the Client API part of the Socket.IO docs, it doesn't specify io.to and socket.to as valid API functions. Here is the client API docs.
And here is a snippet that you can use to emit to Socket.IO rooms:
Server
//Your code...
io.on("connection", socket => {
//Don't forget to do this!
socket.join("some room");
socket.on("some event", data => {
//Do socket.to if you want to emit to all clients
//except sender
socket.to("some room").emit("some event", data);
//Do io.to if you want to emit to all clients
//including sender
io.to("some room").emit("some event", data);
});
});
Client
//Remember to include socket.io.js file!
const socket = io.connect("http://localhost:3000");
socket.on("some event", data => { /* Whatever you want to do */ });
//To emit "some event"
//This will also emit to all clients in the room because of the way the server
//is set up
socket.emit("some event", "description");
If you need an explanation...
So what this does is, basically, since you can't emit to rooms on the client side (you can only emit to server), the client emits to the server, and the server emits the event to the room you want to emit to.
Hope this solves your problem :)
Step1: In the client-side js file, changes instead of io.connect("http://localhost:3000/") use given below line,
let io = require('socket.io').listen(server.listener);
Step2: You need to create a connection in (Both Client & serverSide) For the Testing purpose you can use check connection Establish or not Both End use can use Socket.io tester Chrome Extension.(https://chrome.google.com/webstore/detail/socketio-tester/cgmimdpepcncnjgclhnhghdooepibakm?hl=en)
step3: when a socket connection is Established in Both ends then you emit and listen to data Easily.
One thing when you listen to the data then sends Acknowledgement using Callback Function. I have Received data Successfully.
E.g.`
socket.on('sendMessage',async (chatdata,ack)=>{
ack(chatdata);
socket.to(receiverSocketId).emit('receiveMessage',chatdata);
});
`
yours, emitting a message is correct no need to change this one. But make sure and please check it again your socket connection is Establish successfully or not. another Shortcut way you can debug a code line by line you can easily resolve this problem.
I Hope using this approach you can resolve the Error, and it is help For a Future.
thanks:)

Is there good standard way to simulate Req/Res over Websocket?

I'm building my app entirely over websocket. While I see benefit of being able to send data to client without having client to request data to me. There are still benefits to req/res type of interaction as you can put all logic together.
Ex:
Take registration. You send data, server sends a OK or ERROR if something is wrong.
Right there it's three events! DataFromClient, RegistrationFailed, RegistrationSuccess. But with REST I could have made one POST request and handle if else in one function.
It shouldn't be too hard to create a library that allows you do to push notification + Req/Res type of interaction. It'd be even better if routes could be defined like express routes.
There is no "standard" way to implement request/response with webSocket. It is not part of the webSocket standard. It can certainly be done (more below on this), but there is no "standard" way of doing it.
The socket.io library which is built on top of webSocket has a response option built into any message it sends.
The sender does something like this:
socket.emit("msgName", someData, function(data) {
// data is the "response" to sending this message
console.log(data);
});
The recipient of a message that is expecting a response does something like this to cause the response to be sent:
socket.on("msgName", (someData, fn) => {
// send response
fn(someOtherData);
});
You could implement your own response scheme in webSocket. You'd have to add to your data format a uniqueID for each request so you could send that same uniqueID back in the response so the receiver would know which response belongs with which request.

Edit message in socket.io before it is sent to the user

I'd like to intercept certain messages being sent in the receiver point of view. This means, for example:
SENDER SIDE
User sends message
Server receives message
Message could be treated here but I don't want to work it here
RECEIVER SIDE
I want to treat it in the server before being emit
Message is emit
User receives message (for example, in browser) with socket.on('message',(...));
Does anyone have any idea which part of the code needs to be changed in socket.io to accomplish that? I've been searching the modules: adapter, client, parser... but found nothing relevant... Any thoughts on this one? I've been getting a bit desperate xp
server side:
socket.on("chat", clientMsg);
function clientMsg(data){
console.log("data received:" + data)
var msg = data; // set the msg to be sent
// treat the data server side or
// if wanting to treat the data from the user's side
// create another socket.on() inside this function. to treat it remotely (if needed)
// then, when finished send the message to all users with the treated data.
io.sockets.emit("chat", msg)
};

NodeJS ZeroMQ , no callback for send?

I have multiple nodejs servers located at different locations and i need to create a IPC over tcp sockets and i am using ZeroMQ for that . I need something like request/response or pub/sub in a async way with affirmation that message is sent , but seeing the node-zeromq modules i found all the send methods are synchronous and there is no way to confirm the message the sent through a callback
In short ,
I need something like socket.send(message,function(err,res){;});
but i found this socket.send(message)
Anyone knows how to do this using ZeroMQ or any other way i could IPC reliablly and with a affirmation as response ?
UPDATE : Ive found https://github.com/visionmedia/axon , Axon and its req/rep send method has a callback , would be great if anyone can shed more light about this .Suggestions ?
You could use the request/reply pattern instead of the pub/sub pattern with ZMQ. I believe when you make a request, there is a callback to listen for the response, as opposed to pub.send()...
zeromq.node does yet not support reply callbacks for the send message.
There is an issue discussed for several years now on GitHub where people argue that it would be a sensible modification.
I followed the suggestion on another question since I would really like to use Promises in the higher levels and therefore need callbacks for the REQ/REP mechanism. I.e. the callback is invoked from the 'message' event handler:
var socket, onRepHandler, replyCallback, send;
socket = zmq.socket('req');
onRepHandler = function (reply) {
// HACK
// This handler is a workaround until zeromq.node supports
// direct callback for REQ/REP:
// https://github.com/JustinTulloss/zeromq.node/issues/48
if (replyCallback) {
replyCallback(reply);
}
replyCallback = undefined;
};
socket.on('message', onRepHandler(msg));
socket.connect(address);
// Send method with callback
send = function (msg, repcb) {
if (replyCallback) {
throw new Error('Cannot send request before receiving reply of preceding request!');
}
replyCallback = repcb;
socket.send(msg);
}
It feels like a questionable hack but I hope the zeromq.node library gets updated eventually.

node.js + socket.io broadcast from server, rather than from a specific client?

I'm building a simple system like a realtime news feed, using node.js + socket.io.
Since this is a "read-only" system, clients connect and receive data, but clients never actually send any data of their own. The server generates the messages that needs to be sent to all clients, no client generates any messages; yet I do need to broadcast.
The documentation for socket.io's broadcast (end of page) says
To broadcast, simply add a broadcast flag to emit and send method calls. Broadcasting means sending a message to everyone else except for the socket that starts it.
So I currently capture the most recent client to connect, into a variable, then emit() to that socket and broadcast.emit() to that socket, such that this new client gets the new data and all the other clients. But it feels like the client's role here is nothing more than a workaround for what I thought socket.io already supported.
Is there a way to send data to all clients based on an event initiated by the server?
My current approach is roughly:
var socket;
io.sockets.on("connection", function (s) {
socket = s;
});
/* bunch of real logic, yadda yadda ... */
myServerSideNewsFeed.onNewEntry(function (msg) {
socket.emit("msg", { "msg" : msg });
socket.broadcast.emit("msg", { "msg" : msg });
});
Basically the events that cause data to require sending to the client are all server-side, not client-side.
Why not just do like below?
io.sockets.emit('hello',{msg:'abc'});
Since you are emitting events only server side, you should create a custom EventEmitter for your server.
var io = require('socket.io').listen(80);
events = require('events'),
serverEmitter = new events.EventEmitter();
io.sockets.on('connection', function (socket) {
// here you handle what happens on the 'newFeed' event
// which will be triggered by the server later on
serverEmitter.on('newFeed', function (data) {
// this message will be sent to all connected users
socket.emit(data);
});
});
// sometime in the future the server will emit one or more newFeed events
serverEmitter.emit('newFeed', data);
Note: newFeed is just an event example, you can have as many events as you like.
Important
The solution above is better also because in the future you might need to emit certain messages only to some clients, not all (thus need conditions). For something simpler (just emit a message to all clients no matter what), io.sockets.broadcast.emit() is a better fit indeed.

Resources