socket.io : can a socket IO client emit function register a call back function - socket.io

I am trying to send a message to the server and at the same time save that message to an array in the client. I wanted to know before i start if socketio.emit takes in a call back, something like this :
socket.emit('startRecording', {someData: 'value'}, function (response) {})

socket.io does support an ACK callback from sending a message. It is described here in the socket.io doc. Here's the example of how it would be used from the doc:
// client code
socket.emit('ferret', 'tobi', (data) => {
console.log(data); // data will be 'woot'
});
// server code
io.on('connection', (socket) => {
socket.on('ferret', (name, fn) => {
// send ACK response
fn('woot');
});
});
If the last argument you pass .emit() is a callback, then that callback will be called if/when the server provides an ACK response as show in the example above. This allows you to use a request/response for a given message where you get a specific response from sending a message.

Related

Twilio awaits response, I don't want server to respond

I am using a Slack webhook to process incoming SMS messages from Twilio. However, the way I have it set up, It seems that Twilio is expecting the web server (slack) to respond to it. This causes errors to be generated in Twilio, and I obviously don't want errors because I'll be getting emails.
I am using the twilio-ruby gem in Ruby to send out the SMS messages, and using the slack-ruby-client to monitor incoming messages from Slack.
How do I stop Twilio from trying to expect a response from the web server when it POSTS to the Slack webhook? Is that even possible or do I have this all configured incorrectly?
EDIT
Here's the function that I have which sends the forwarded SMS to Slack:
const https = require("https");
// Make sure to declare SLACK_WEBHOOK_PATH in your Environment
// variables at
// https://www.twilio.com/console/runtime/functions/configure
exports.handler = (context, event, callback) => {
// Extract the bits of the message we want
const { To, From, Body } = event;
// Construct a payload for slack's incoming webhooks
const slackBody = JSON.stringify({
text: `!asi SMS\nFrom: ${From}\nMessage: ${Body}`
});
// Form our request specification
const options = {
host: "hooks.slack.com",
port: 443,
path: context.SLACK_WEBHOOK_PATH,
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": slackBody.length
}
};
// send the request
const post = https.request(options, res => {
// only respond once we're done, or Twilio's functions
// may kill our execution before we finish.
res.on("end", () => {
// respond with an empty message
callback(null, new Twilio.twiml.MessagingResponse());
});
});
post.write(slackBody);
post.end();
};
Twilio developer evangelist here.
Twilio is always going to expect at least a 200 response or will timeout at 15 seconds for incoming message webhooks.
You could avoid the error messages by using something in between Twilio and Slack, like Zapier (example in this blog post) or using a Twilio Function (as described here) or with Twilio Studio (from the documentation here).
Hope one of those ideas helps!
Update
Further to my earlier answer, and given the code you used to make the call, I have an update.
When making a request using Node's built in https module you will not get the end event until you have read the data. This is what is causing the timeout between Twilio and the Twilio Function, you are never responding to it because you don't consume the data from the request.
In a quick test I found that just listening for the data event meant that the end event did fire. So update your function to:
const post = https.request(options, res => {
// only respond once we're done, or Twilio's functions
// may kill our execution before we finish.
res.on("data", () => {});
res.on("end", () => {
// respond with an empty message
callback(null, new Twilio.twiml.MessagingResponse());
});
});
And it should work.

Socket.emit() outside socket.on()

Do we always have to use socket.emit() inside a socket.on() like that:
io.sockets.on('connection', function (socket) {
console.log('User connected !');
retrieveDictionnary((dictionnary) =>{
socket.emit('dictionnarySend', dictionnary);
}
}
I want to create on my client side a function which ask information to the server when I click on a button:
translateServer(parameter, control){
this.socket.emit('translate', [parameter,control]);
}
But it seems that it's not working, the server never receive this message.
Thank you !
The pattern you are using above is the recommended way of interacting with a socket (ie acquiring a socket instance when the 'connection' event fires, and then calling emit() from that socket instance, etc).
If I understand your client-side requirements correctly, you are wanting to send data to the server via web sockets - are you sure the socket that you have established a web socket connection between the client and server?
For instance, if you add the following to your client-side code, you should see a success message in your console:
const socket = io.connect('YOUR SERVER ADDRESS');
socket.on('connect', () => {
console.log('connected to server!');
// [UPDATE]
// This assumes you have a <button> element on your page. When
// clicked, a message will be sent to the server via sockets
document.querySelector('button').addEventListener('click', (event) => {
// Prevent button click reloading page
event.preventDefault();
// Send message to server via socket
socket.emit('MESSAGE_ID', 'test message from client' + new Date());
});
});
Update
This shows your original server code, expanded with the detail needed to receive and print data sent from client via sockets:
io.sockets.on('connection', function (socket) {
console.log('User connected !');
// Register a server handler for any messages from client on MESSAGE_ID channel
socket.on('MESSAGE_ID', (message) => {
// Print the message received from client in console
console.log('message from client', message);
})
retrieveDictionnary((dictionnary) =>{
socket.emit('dictionnarySend', dictionnary);
}
}

socket.io - how to access unhandled messages?

How can you detect that you received a message on a socket.io connection that you do not have a handler for?
example:
// client
socket.emit('test', 'message');
// server
io.on('connection', function (socket) {
console.log('connection received...');
// logs all messages
socket.conn.on('message', function(data) {
console.log('this gets every message.');
console.log('how do I get just the ones without explicit handlers?');
});
socket.on('other' function(data) {
console.log('expected message');
});
}
By accessing the internals of the socket object you can determine what events it is currently listening for. You can use this server-side code to see if the current message is being handled.
io.on('connection', (socket) => {
console.log('A user connected.');
socket.on('disconnect', () => {
console.log('A user disconnected.');
});
socket.on('chat', (msg) => {
console.log('message: ' + msg);
io.emit('chat', msg);
});
socket.conn.on('message', (msg) => {
if(!Object.keys(socket._events).includes(msg.split('"')[1])) {
console.log(`WARNING: Unhandled Event: ${msg}`);
}
});
}
Once connected I am handling two events, 'disconnect' and 'chat'. After that I define a handler that catches all messages with socket.conn.on(...).
The message it receives is going to be a string that looks something like this: '2["myEventName","param1","param2"]'. By splitting it along the double quotes we can get the event name.
We then peek into the internals of socket to find all the keys of socket._events, which happen to be the event name strings. If this collection of strings includes our event name, then another handler will take care of it, and we don't have to.
You can test it from the console in the browser. Run socket.emit('some other event') there and you should see your warning come up in the server console.
IMPORTANT NOTE: Normally you should not attempt to externally modify any object member starting with an underscore. Also, expect that any data in it is unstable. The underscore indicates it is for internal use in that object, class or function. Though this object is not stable, it should be up to date enough for us to use it, and we aren't modifying it directly.
Tested with SocketIO version 2.2.0 on Chrome.
I didn't find a way to do it like socket.io, but using a simple js function to transform message into json it's doing the same job. Here you can try this:
function formatMessage(packetType, data) {
var message = {'packetType': packetType, 'data': data}
return JSON.stringify(message)
}
With:
socket.on('message', function(packet){
packet = JSON.parse(packet)
switch (packet.packetType) {
case 'init':
...
and
socket.send(formatMessage('init', {message}));
I would do so, of course it is the abstract code ... you would have to implement all the listeners and the logic to get the ids of the users to work
Client
var currentUser = {
id: ? // The id of current user
};
var socketMessage = {
idFrom: currentUser.id,
idTo: ?, // Some user id value
message: 'Hello there'
};
socket.emit('message', socketMessage);
socket.on('emitedMessage' + currentUser.id, function(message) {
// TODO: handle message
});
Server
io.on('connection', function (socket) {
// Handle emit messages
socket.on('message', function(socketMessage) {
// With this line you send the message to a specific user
socket.emit('emitedMessage-' + socketMessage.idTo, {
from: socketMessage.idFrom,
message: socketMessage.message
});
});
});
More info: http://socket.io/docs/

Single Cross Domain AJAX Request needed

Trying to implement sending sms features in my ecommerce store.
I use service called esteria.lv and they provided me with API link that looks like this: http://api1.esteria.lv/send?api-key=api_key&sender=example.com&number=11223344&text=message
If the message is sent then it outputs message ID, now it outputs error number 3(unable to authenticate).
To get it working with my ecommerce store, I found this resource: http://www.ajax-cross-origin.com/examples/cross-origin.htm, and made this code:
$(function() {
$( '#btn' ).click(function(){
$.ajax({
crossOrigin: true,
url: 'http://api1.esteria.lv/send?api-key=api_key&sender=example.com&number=11223344&text=message',
success: function(data) {
$( '#test' ).html(data);
}
});
});
});
It works, but the problem is, it sends 6 messages (requests) instead of just one. I need just 1 request and one sent sms. Anyone have any suggestions?
To answer your comment, this is what you should do.
In your javascript you should have an ajax call to your server
// collect sms data
$.ajax({
url: 'yourserver/handlesms',
method: 'post',
data: {
sender: 'email#mail.com',
number: '1234567',
message: 'Test message'
}
}).then(function (data) {
alert("Message sent!");
});
In your server you should have an handler for sending the sms, something like (I don't know what's your platform, I'll just write a really simple php example)
$data = $_POST;
$apiKey = '12345643223213ds';
$endpoint = 'http://api1.esteria.lv/send';
// Create new curl request
$ch = curl_init($endpoint);
// curl settings, add your data, api key etc...
$result = curl_exec($ch);
// Result will contain the response from your api call
// Then you can send a result back to your client (js)
echo json_encode(['status' => 'Message sent!']);
This is just an example, the server code depends on your platform.
In this case you don't have any cross origin request (all the js request will be sent to your server, that then is in charge of contacting your sms provider and send the messages.
The problem that's executed 6 times I think depends on something else but it's hard to say without looking at the rest of the code (you can try debugging the click event on #btn and see how many times is executed every time you click on the button.

Socket.io sending multiple message for a single request

I am using Socket.io in a NodeJS + Typescript project, where the client sends a message to ther server and the same message and send back to the client using socket. However, every time I send a new message to the server, the number of times the server sends the message back increments by 1 - which is not how I've programmed it to work. For example, the first time I send a message "x" - the server returns the message "x". The next time I send a message, the server returns that message twice. The next time it happens three times, until the page is refreshed, when it goes back to one. I don't know whats going wrong. Here's the code:
Client:
$("#send").click(function(){
alert("Sending : " + $("#text").val());
socket.emit("toServer", {
message: $("#text").val()
});
socket.on('toClient', function (data) {
alert (data.message);
});
});
Server (app.ts):
function startSocket() {
var io = require('socket.io').listen(server, {log : false});
io.sockets.on('connection', function (socket) {
socket.on('toServer', function (data) {
console.log(data);
socket.emit('toClient', data);
});
});
}
startSocket();
By registering the event handler inside the click event you would create a new registration each time the click occurred. This would lead to all of these event handlers (depending on the number of times you clicked) to fire when the server sends the message.
In short : the server is sending it only once, you were receiving it multiple times.
Putting the socket receive function outside of the button click event works.
$("#send").click(function(){
alert("Sending : " + $("#text").val());
socket.emit("toServer", {
message: $("#text").val()
});
});
socket.on('toClient', function (data) {
alert (data.message);
});

Resources