How to add a delay between function excutions - javascript

I am creating this little chatbox thing with socket.io, and I am wondering how I can add a delay between message sending to prevent spam and such.
Here is my code for sending a message.
// Sends a chat message
const sendMessage = () => {
let message = $inputMessage.val();
// Prevent markup from being injected into the message
message = cleanInput(message);
// if there is a non-empty message and a socket connection
if (message && connected) {
$inputMessage.val("");
addChatMessage({ username, message });
// tell server to execute 'new message' and send along one parameter
socket.emit("new message", message);
}
};

You could add a variable that tracks the time of the most recently sent message and a comparison of this variable and the current time; if the difference is too small, refuse to send it.
Minimal example:
window.lastMessageTime = 0;
function sendMessage(message) {
if(Date.now() - window.lastMessageTime < 5000)
return false;
window.lastMessageTime = Date.now();
// Proceed
};

Try using setTimeout to execute your main function. Javascript is not supporting any delays as it is single threaded.

Related

Telegram Bot Chain of Multiple Messages Sending NodeJS - Crashing

I am trying to send multiple messages to telegram bot through telegraf API in node backend. There are various conditions which when true, should send an telegram alert. The example of condition is:
if(condition is true) {
message = "Hey there";
sendToTGBot(message)
}
There are approximately 100 conditions which get checked within few seconds when the data is fetched as a stream from the API. So, the telegram bot limit gets hit when trying to process more than 30 messages in a second and the server crashes.
The code used to send messages from the bot is:
export const sendToTGBot = (alert) => {
bot.telegram.sendMessage(chat_id, alert);
}
I have also tried putting a delay using setTimeout() in the above code as:
export const sendToTGBot = (alert) => {
setTimeout(() => {
bot.telegram.sendMessage(chat_id, alert);
}, 500);
}
This code above puts the delay (I think so), but due to approximately 30-50 conditions getting true at once in a second. The function gets called that many times and after approx. 10-15 seconds all the alerts get sent simultaneously, again hitting the telegram bot limit.
Also, tried it like this:
export const sendToTGBot =
setTimeout((alert) => {
bot.telegram.sendMessage(chat_id, alert);
}, 500);
This results in a straight error.
Kindly help me with this problem. I have to send multiple alerts within a duration. The number of alerts simultaneously can increase. So, recommend me the best possible solution using JavaScript. Thanks.
You can do this by adding the messages in a queue/array, then utilize async await to loop it
let queue = [];
if(condition == true) {
message = "Hey there";
queue.push(message);
}
setInterval(async ()=>{
if(queue.length>0) {
await bot.telegram.sendMessage(chat_id, queue[0]);
queue.shift();
}
}, 1000)

Referencing a DM channel

I'm trying to create a command that allows users to create their password following prompts through DM. I'm able to send a message to the user, but not able to read a message sent back with a MessageCollector because I cannot find a way to reference the DM channel.
I have tried using another instance of bot.on("message", message) here, but that creates a leak in the system causing the second instance to never disappear.
I also can't let users use a command say !CreatePassword *** because this function is linked with many others in a strict order.
Maybe I'm doing something fundamentally wrong, or approaching the problem in a bad way, but I need a way to reference a DM channel.
This is the best iteration of my code so far.
function createAccount(receivedMessage, embedMessage)
{
const chan = new Discord.DMChannel(bot, receivedMessage.author);
const msgCollector = new Discord.MessageCollector(chan , m => m.author.id == receivedMessage.author.id);
msgCollector.on("collect", (message) =>
{
// Other Code
msgCollector.stop();
// Removing an embed message on the server, which doesn't have a problem.
embedMessage.delete();
})
}
I can show the rest of my code if necessary.
Thank you for your time. I've lost an entire night of sleep over this.
I would do it like this (I'll assume that receivedMessage is the message that triggered the command, correct me if I'm wrong)
async function createAccount(receivedMessage, embedMessage) {
// first send a message to the user, so that you're sure that the DM channel exists.
let firstMsg = await receivedMessage.author.send("Type your password here");
let filter = () => true; // you don't need it, since it's a DM.
let collected = await firstMsg.channel.awaitMessages(filter, {
maxMatches: 1, // you only need one message
time: 60000 // the time you want it to run for
}).catch(console.log);
if (collected && collected.size > 0) {
let password = collected.first().content.split(' ')[0]; // grab the password
collected.forEach(msg => msg.delete()); // delete every collected message (and so the password)
await firstMsg.edit("Password saved!"); // edit the first message you sent
} else await firstMsg.edit("Command timed out :("); // no message has been received
firstMsg.delete(30000); // delete it after 30 seconds
}

How can I detect disconnects on socket.io?

I am using socket.io in my project. I turned on reconnect feature. I want to if user disconnects from server show an alert (Your internet connection loss. Trying reconnect). And if the user reconnects again I want to show one more alert (Don't worry, you are connected).
How can I do it?
To detect on the client you use
// CLIENT CODE
socket.on('disconnect', function(){
// Do stuff (probably some jQuery)
});
It's the exact same code as above for a node.js server too.
If you want for some reason to detect a user disconnecting and display it to the others, you will need to use the server one to detect it the person leaving and then emit back out a message to the others using something like:
socket.on('disconnect', function(){
socket.broadcast.to(roomName).emit('user_leave', {user_name: "johnjoe123"});
});
Hope this helps
socket.io has a disconnect event, put this inside your connect block:
socket.on('disconnect', function () {
//do stuff
});
I handled this problem this way. I've made an emit sender on client which is calling heartbeat on server.
socket.on('heartbeat', function() {
// console.log('heartbeat called!');
hbeat[socket.id] = Date.now();
setTimeout(function() {
var now = Date.now();
if (now - hbeat[socket.id] > 5000) {
console.log('this socket id will be closed ' + socket.id);
if (addedUser) {
--onlineUsers;
removeFromLobby(socket.id);
try {
// this is the most important part
io.sockets.connected[socket.id].disconnect();
} catch (error) {
console.log(error)
}
}
}
now = null;
}, 6000);
});
I found this code function to call:
io.sockets.connected[socket.id].disconnect();
inpired on invicibleTrain iv made a online checker also
SERVER SIDE
const sockets={online:{},admins:{}}
// the disconnect function you create the way you wish to, example:
const disconnect=()=>{
socket.emit('disconected')
io.in(socket.id).disconnectSockets()
delete sockets.online[socket.uid]
}
io.on('connection',socket=>{
socket.emit('connection',socket.id)
// the checker if user is online
let drop
const dropCheck=()=>{
if(!socket) return; // if user connects twice before the check, simply stops process
socket.emit('dropCheck')
drop = setTimeout(()=>disconnect(),4000) // 4 secs to recieve answer
}
const setDrop=()=>setTimeout(()=>dropCheck(),60000) // 60 secs to restart the process
socket.on('dropCheck',()=>{
clearTimeout(drop) // cancells actual drop coutdown (if any)
setDrop() // sets a new
})
//sets the user ID inside the socket used for comunication
socket.on('uid',uid=>{
socket.online[uid] = {status:'busy',socket:socket.id}
setDrop()
})
})
CLIENT SIDE
const sio = io(`...httpAddress...`,{transports:['websocket']})
sio.on('connection',socket=>{
sio.emit('uid','user Id here..') // sends the the user ID: uid
sio.on('dropCheck',()=>{ // responds to the checker
sio.emit('dropCheck')
})
})
Explanation:
The user logs in and after 60 seconds dropCheck is called
the dropCheck emits a ping and set a timmer of 4 seconds
the user handle the emited ping and responds with another ping
a: if the response comes within 4 secs the 4 secs timmer is cancelled and refreshes the 60 seconds timmer (restarting the
process)
b: if the response fails or delay too much the disconnect() function is called

Socket.io message event firing multiple times

I was trying to learn node and started creating a mashup with socket.io
The message transportation have begin but I have run into some trouble.
The message event is firing multiple times leading to a single message appearing multiple times on the recipient's box. I have routed the socket to exports.chat and was wondering if that is causing the problem?
To narrow down the problem: the messages are firing the number of times = the sequence of connection of the client. That is, if a client connects second, his messages will fire twice. three times for the client connecting third.
Here is the code snippet:
exports.chat = function(io, pseudoArray, req, res){
res.render('chat', {title: 'ChatPanel.'});
var users = 0;
io.sockets.on('connection', function (socket) { // First connection
users += 1;
// reloadUsers(io, users);
socket.on('message', function (data) { // Broadcast the message to all
if(pseudoSet(socket)) {
var transmit = {date : new Date().toISOString(), pseudo : returnPseudo(socket), message : data};
socket.broadcast.emit('message', transmit);
console.log("user "+ transmit['pseudo'] +" said \""+data+"\"");
}
});
socket.set('pseudo', req.session.user, function(){
pseudoArray.push(req.session.user);
socket.emit('pseudoStatus', 'ok');
console.log("user " + req.session.user + " connected");
});
socket.on('disconnect', function () { // Disconnection of the client
users -= 1;
// reloadUsers();
if (pseudoSet(socket)) {
var pseudo;
socket.get('pseudo', function(err, name) {
pseudo = name;
});
var index = pseudoArray.indexOf(pseudo);
pseudo.slice(index - 1, 1);
}
});
});
};
The whole part of socket.io code has to go outside external.chat function. Socket IO has to bind with the http/app server, you should not handle it within each request.
the messages are firing the number of times = the sequence of connection of the client
What essentially happening is, each time a new request arrives you are registering a event handler for message, hence it is fired as many times as the you have accessed chat URL.
io.socket.on('message', function (data) {...})
So I had the same problem. The solution is to close all your listeners on the socket.on('disconnect') event, this is what my code looks like -
socket.on('disconnect', function () {
socket.removeAllListeners('send message');
socket.removeAllListeners('disconnect');
io.removeAllListeners('connection');
});
Might not need to call it on disconnect, not sure but I do it anyway.
I think this misbehavior is because you are attempting to use one of the handful of built-in/reserved event names "message" as an application-specific message. To confirm, change your event name to "message2" or something else and see if the problem goes away. I believe at least "connect", "disconnect", and "message" are reserved. https://github.com/LearnBoost/socket.io/wiki/Exposed-events
Link: https://socket.io/docs/v3/listening-to-events/#socketoffeventname-listener
Please use socket.off method to removes the specified listener from the listener array for the event named eventName.
socket.off("message").on("message", this.UpdateChat);
Restarting the server can be responsible for several identical event listeners on the client side. If the client has not reloaded (restarted) you have to make sure that the old event listeners are deleted on the client side when establishing a new connection. You can do that with
io.socket.removeAllListeners()
SOCKET.IO v3.x
I don't really know why reserve event in socket.io are firing up multiple times, hence I make a logic that fits to our needs and address this problem,
I simply create a global mutable value that could change everytime the 'disconnect' fire up, here's the logic I did
let ACTIVE_USERS = []; //assume the propery of an object is { name, socket_id }
const connections = (socket) => {
socket.on("disconnect", (reason) => {
//lets check how many times it fires up
console.log('YOW', reason);
//mutate the ACTIVE_USERS
ACTIVE_USERS = ACTIVE_USERS .filter(user => {
//lets figure it out if this thing helps us
if(user.socket_id === socket.id){
console.log('HEY!!!');
socket.broadcast.emit('disconnected-user',[
message: `${user.name} has been disconnected`
})
}
})
});
}
and the result of it is here

How can I pick out a particular server message from a websocket connection?

I have a WebSocket connection set up for a basic web chat server.
Now, whenever a message is received, it is sent to a function which outputs it on the screen.
socket.onmessage = function(msg){output(msg);}
However, there are certain technical commands which the user can send to the server through the connection which elicit a technical response, not meant to be output on the screen.
How can I grab the server response which immediately follows one of these technical messages?
Do I put a separate socket.onmessage right after the block of code which sends the technical message? I imagine that would take all future messages. I just want the next one.
Ideas?
WebSockets is asynchronous so trying to get the 'next' message received is not the right solution. There can be multiple message in flight in both directions at the same time. Also, most actions in Javascript are triggered by asynchronous events (timeout firing, or user clicking on something) which means you don't have synchronous control over when sends will happen. Also, the onmessage handler is a persistent setting: once it is set it receives all messages until it is unset. You need to have some sort of way of distinguishing control messages from data messages in the message it self. And if you need to correlate responses with sent messages then you will also need some kind of message sequence number (or other form of unique message ID).
For example, this sends a control message to the server and has a message handler which can distinguish between control and message and other messages:
var nextSeqNum = 0;
...
msg = {id: nextSeqNum, mtype: "control", data: "some data"};
waitForMsg = nextSeqNum;
nextSeqNum += 1;
ws.send(JSON.stringify(msg));
...
ws.onmessage = function (e) {
msg = JSON.parse(e.data);
if (msg.mtype === "control") {
if (msg.id === waitForMsg) {
// We got a response to our message
} else {
// We got an async control message from the server
}
} else {
output(msg.data);
}
};
You can packetise the data, I mean, by a special character/s, form a string like this :
"DataNotToBeShown"+"$$"+"DataToBeShown"; //if $$ is separating character
And then, you can split the string in javascript like this :
var recv=msg.data.split('$$');
So, the data not be shown is in recv[0] and data to be shown, in recv[1]. Then use however you want.

Categories