Alternating messages on chatbot creation - node.js

I'm doing a chatbot with Node JS for Instagram using this library available on github(https://github.com/Androz2091/insta.js.git). I'm currently testing the feature through the online replit platform, I'm getting the message from the instagram user and sending it through a url to the reply service
I have a difficulty that would be the bot's answer. It must follow a message structure, however, this structure is often toggled.
I send in the chat:
-Hi
The bot responds in the console:
-Hello!
-How can I help you?
but in the chat he responds like this:
-How can I help you?
-Hello!
Below is the code I used to go through the arrays I receive and send the messages
I tried using a switch case to try to solve the problem, but it still remains the same.
node-fetch(`instagram?mensage=${message}&user=${message.author.fullName}&session=${client.user}`)
.then(res => res.json())
.then(json => {
for (var i = 0; i < json.length; i++) {
message.chat.sendMessage(json[i].text || json[i].title);
console.log(json[i].text || json[i].title)
for (var key in json[i]) {
/* switch case
switch(json[i][key]){
case json[i].text:
message.chat.sendMessage(json[i].text);
break;
case json[i].title:
message.chat.sendMessage(json[i].title);
break;
}*/
if (json[i][key].length == 3) {
for (var j = 0; j < json[i][key].length; j++) {
message.chat.sendMessage(json[i][key][j].label);
console.log(json[i][key][j].label);
}
}
Does anyone know why this happens?
I already thank you.

sendMessage returns Promise, but you are using it as a normal function.
You can read about javascript promises here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises.
In your code, it should look something like this
...
.then(async json => {
for (var i = 0; i < json.length; i++) {
await message.chat.sendMessage(json[i].text || json[i].title);
...
}
});

Related

is there a way to make my code non case sensitive

I'm trying to make a bot able to read an input automatically, no need for a command and then check the input against a list of defined words. I have managed to get this working but i'm having trouble in such a way that if anything varies from the word on the list, the bot ignores it. Code is as follows, all help is appreciated:
bot.on('message', message => {
for (i = 0; i < blacklist.length; i++)
{
//var check = blacklist[i].trim();
if (blacklist[i].trim().length > 0){
var lookup = '\\b'+blacklist[i]+'\\b';
var re = new RegExp(lookup);
var foundpos = message.content.search(re)
if(foundpos >=0) {
message.delete();
break;
}}}
for(i in blacklist) {
console.log(blacklist[i]);
}
})

It's sends 4 times the amount of members

So I want my bot in a certain server to send a dm to a random member every 10 minutes. And when my bot has sent everyone from the server a dm it sends a complete message.
But when i start the bot it sends 4 times the amount of members
if (message.content.startsWith(botconfig.prefix + 'dmall')) {
console.log("demo");
var list = message.guild.members.array();
sendMessage(list);
}
});
function sendMessage(list) {
setTimeout(function () {
for (i = 0; i < list.length; i++) {
console.log(list.length);
}
console.log("I'm done, mate!");
sendMessage(list);
}, 10 * 1000);
}
CONSOLE:
demo
4 (is the amount of the members)
4
4
4
I'm done mate!
This part of your code:
for (i = 0; i < list.length; i++) {
console.log(list.length);
}
tells Javascript to run the statement:
console.log(list.length);
list.length times. If list.length is 4 which it appears to be here, then you will see in the console
4
4
4
4
That's what the code was instructed to do.
I don't see any reason why you'd put that in a loop unless you want to output each array element separately. So, if you want to just output the length once, then replace this:
for (i = 0; i < list.length; i++) {
console.log(list.length);
}
with this:
console.log(list.length);
In addition, if you were to use a for loop, you MUST declare all variables that you use. So, this:
for (i = 0; i < list.length; i++) {
is very dangerous. It relies on a higher scoped i which can easily conflict with other higher scoped i variables and create hard-to-figure out bugs. Every for loop should declare it's own loop variable as in:
for (let i = 0; i < list.length; i++) {
If you run your code in strict mode (which you should), the above for loop declaration would likely cause an error (which is a good thing because you'd immediately see the coding error and fix it).
There are a couple of things wrong here.
For of: JavaScript variable scoping messing you up (Different example here
Second of all: setTimeout is not the same as setInterval.
Completely fixing your issue would be:
// Use the discord API
let users = ['justme']
function getUsers() {
// Mutate just to display a new one each time
users = [...users, users.length.toString()];
return users
}
function notifyUsers() {
// Retrieve all users now
const currentUsers = getUsers()
// Send a message to each user
currentUsers.forEach(user => sendMessage(user))
console.log('I have sent everyone a message')
}
function sendMessage(user) {
console.log(`Sending message to ${user}`)
}
// Start the application by looping every <whatever>
setInterval(() => notifyUsers(), 1000)

calling websocket send function from within .then() in nodejs

i have a promise that resolves a JSON object with some config data. i want to access this data upon pressing the "send config" button in my HTML client. the communication is done through a websocket connection in nodejs. so the websocket server receives a message that says "send config" from the client and the server is supposed to respond with the config.
code:
showMsg = function (MSGOBJ) {
var parsedOBJ = JSON.parse(MSGOBJ);
//console.log(parsedOBJ.content);
for (var i = 0; i < connections.length; i++) {
switch(parsedOBJ.type) {
case "text":
console.log("Received: " + parsedOBJ.content)
connections[i].sendUTF('{ "type":"text", "content":"Server ready."}')
break;
case "config":
console.log("Received:1 " + parsedOBJ.content)
console.log("Sending config" )
var getConfig = KRequests.getKConfig;
var configOBJ;
getConfig.then(function(result) {
configOBJ = result
});
connections[i].send('{ "type":"config", "content":'+JSON.stringify(configOBJ)+'}');
break;
}
}
}
i know configOBJ would be undefined if i use it outside of the chain, but just to give you an idea of what i want to do. and also if i move the send() inside the chain, it would cause this error: "UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'send' of undefined"
You have two issue one is that you should use:
getConfig.then(function(result) {
console.log(connections[i])
connections[i].send('{ "type":"config", "content":'+JSON.stringify(configOBJ)+'}');
});
The other is that:
for (var i = 0; i < connections.length; i++) {
should be:
for (let i = 0; i < connections.length; i++) {
Or if you don't have let which you should if you are using a recent node that supports more than ES5. You will have to use a IIFE like this:
for (var i = 0; i < connections.length; i++) {
(function (i) {
// put the loop body here
})(i);
}

Node.js thermal printer issue in loop printing

I am developing a web application in Laravel, which sends a list of articles via JSON to a process running on Node.js (i use websocket library), which must for each of these items call a print function (i use escpos library).
When i print one or two items there are no problem, and all its OK. But when i send 3 or more items, the printer print the first ok, but with the rest it have problems. I think when i send 3 or more items, the printer is too slow and can't end the jobs.
This is the part of my code in Node.js that print the items:
for (var i = 0; i < msg.items.length; i++) {
for (var j = 0; j < msg.items[i].quantity; j++) {
print(msg.items[i]);
}
}
(Note i use 2 loop because a item can have a quantity > 1 and i have to print 1 ticket for each item and quantity)
And this is the code of the printing library (irrelevant but i leave it to clarify)
function print(item){
escpos.Image.load(__dirname + '/logo3.png', function(image){
printer
.raster(image)
.control('LF')
.style('b')
.size(2, 2)
.text(item.code)
.control('LF')
.control('LF')
.barcode(item.ean, "EAN8")
.cut();
});
I hope you can help me, thank you in advance.
I found a solution to the problem. I decided to use asynchronous requests with a timeout to wait for the printer to complete each task, along with promises. The code fragment:
function asyncFunction (item, cb) {
setTimeout(() => {
print_product(item);
console.log("Print " + item.code);
cb();
}, 1200);
}
let requests = products.reduce((promiseChain, item) => {
return promiseChain.then(() => new Promise((resolve) => {
asyncFunction(item, resolve);
}));
}, Promise.resolve());

handling asynchronous call backs in nodejs

I am newbie to nodejs.It's very hard to handle callbacks at nodejs level. I have code like this,
getItems(request,function(jsonObject){
var itemData={};
var itemDetails=new Array();
for(var i=0;i < jsonObject.length;i++){
getItemDetails(jsonObject[i].value.item_id,function(jsonObject){
itemDetails.push(jsonObject);
});
}
itemData["itemDetails"]=itemDetails;
response.contentType("application/json");
response.send({"data":itemData});
});
while executing the above code, the for loop is continuing with out getting callback from getItemDetails method and response sent to client. My requirement is the loop will wait until getting the call back from the getItemDetails then response should send.
I have tried with process.nextTick(), but i am unable to find where i have to use that process.nextTick().. Please anybody provide suggestions.
Thanks in advance.
You need to send the response only after you get all the items, so modify your code like so:
getItems(request,function(jsonObject) {
var itemData = {},
itemDetails = [],
itemsLeft = len = jsonObject.length,
i;
function sendResponse(itemDetails) {
itemData["itemDetails"] = itemDetails;
response.contentType("application/json");
response.send({ "data": itemData });
}
for (i = 0; i < len; i++) {
getItemDetails(jsonObject[i].value.item_id, function(jsonObject) {
itemDetails.push(jsonObject);
// send response after all callbacks have been executed
if (!--itemsLeft) {
sendResponse(itemDetails);
}
});
}
});
Note: I've used itemLeft here since it's a more generic way to solve these kind of problems, but Ianzz approach is also ok since you can compare the length of the two arrays.
You can't get the loop to wait, but you can modify your code to get the behavior you are expecting:
getItems(request,function(outerJsonObject){
var itemData={};
var itemDetails=new Array();
for(var i=0;i < outerJsonObject.length;i++){
getItemDetails(jsonObject[i].value.item_id,function(innerJsonObject){
itemDetails.push(innerJsonObject);
if (itemDetails.length == outerJsonObject.length) {
// got all item details
itemData["itemDetails"]=itemDetails;
response.contentType("application/json");
response.send({"data":itemData});
}
});
}
});

Resources