Socket.io sending multiple message for a single request - socket.io

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);
});

Related

how to control multiple ajax requests in laravel 5.2

I am working on an application where different ajax requests fires depending upon different actions.
For example, there is a chat window having send button. When i click on that button an empty message is sent with ajax, successfully. It work nice. But when I hit the send button too many times, at start some requests respond 200 (ok) but then it respond 500 (internal server error). Due to this the other requests that are going continuously like updateLastActivity also disturb.
The preview of the error in developer's tool is:
Whoops like something went wrong.
Note: When I make this chat system in core PHP, it work fine. There is no internal server error when I send too may requests.
Here is the code I am using
//the following code is used to send the message
$(document).on('click','.send_message_bt',function(event){
event.preventDefault();
var id=$(this).data('id');
var name=$(this).data('name');
var message=$("#message_field-"+id).val();
$.ajax({
//headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') },
headers: { 'X-CSRF-TOKEN': {!! json_encode(csrf_token()) !!} },
url:'{{route('user.sendmessage')}}',
type:'POST',
data:{
id:id,
message:message
},
success:function(data,status){
//clear the message field value
$("#message_field-"+id).val('');
//update the chat history
fetchChatHistory(id,name);
},
error:function(response){
if(response.status==401){
alert('You are not logged in!');
window.location=window.location.href;
}
}
});
});
here is the back end code
public function sendMessage(Request $request){
$message=new Userchatmessage();
$message->message=$request->message;
$message->sender_id=Auth::user()->id;
$message->receiver_id=$request->id;
$message->save();
return response('success');
}
How to fix this issue.
I guess it's not a problem with Laravel or anything, but with your browser. Each browser has a maximum amount of simultaneous connections it will open for a certain domain.
Read more about this problem here and here.
If you want to make a realtime chat application, consider using something like NodeJS and Socket.io.
Async and await can help. Let an async function
async function doAjax(){
await runFirstAjaxCall();
await runAfterFirstAjaxCallSuccess();
....
....
}
doAjax();

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 : can a socket IO client emit function register a call back function

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.

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.

Resources