async function wont break node.js (.mjs) - node.js

I'm trying to pause this function using the breakTheLoop var but it wont work.
This is the code if anyone could help me out
`
async afk(message) {
var breakTheLoop = false;
while (!breakTheLoop) {
await new Promise(resolve => setTimeout(resolve, 500));
this.bot.setControlState('forward', true);
await this.bot.waitForTicks(1);
//this.bot.setControlState('sprint', true);
this.bot.setControlState('jump', true);
let arm = Math.random() < 0.5 ? 'right' : 'left';
await this.bot.swingArm(arm);
let yaw = 2*Math.random()*Math.PI - (0.5*Math.PI);
let pitch = Math.random()*Math.PI - (0.5*Math.PI);
await this.bot.look(yaw,pitch,false);
await this.bot.waitForTicks(11);
if (message === '!afkoff') {
return breakTheLoop = true;
}
}}
This is the function i use to call to the async function
chatLog(username, message) {
if (!botNames.includes(username)) {
this.log(chalk.ansi256(98)(`<${username}>`), message)
if(message === '!afk')this.afk(), this.bot.chat("I'm AFK!");
}
}
I'm new to js so any help would be appreciated.
Expected the loop to stop but it just keeps going i've tried multiple answers on here.

Related

Best practice using promises chaining in node JS

I'm little bit confusing in promises. first, I have some ugly code like this:
async function presence(ctx) {
try {
var prsenceData = [];
var isSuccess = Boolean(false);
var ckFilePath = "./somepath/cookie.json";
if (!fs.existsSync(ckFilePath)) {
await menuLogin.login(ctx).then(login => {
isSuccess = Boolean(login[0].status);
myCk.saveCookies(login[0].cookies, ckFilePath);
if (!isSuccess) {
myCk.deleteCookies(ckFilePath);
return false;
}
});
} else {
await myCk.checkToDelete(ckFilePath).then(isDel => {
if (isDel) {
return false;
}
});
}
await presenceNow.check(fs.existsSync(ckFilePath), ctx).then(data => {
for (let id = 0; id < data[0].pesan.length; id++) {
console.log(data[0].pesan[id]);
}
for (let id = 0; id < data[0].id.length; id++) {
presenceData.push(data[0].id);
}
if (data[0].pesan.length == 0 && fs.existsSync(ckFilePath)) {
myCk.deleteCookies(ckFilePath);
}
});
} catch (e) {
console.log(e);
}
return presenceData;
}
Can anyone explain why presenceNow.check() function is not calling if my ckFilePath does not exist? but if myCkFilePath is exist, my code run so well. And maybe anyone can show me the better code for that case? thanks.
Mixing async/await and promise chains like this is something of a code smell that the author lacked an understand of async/await. It's also something of a mixed metaphor.
If you refactor it to actually use async/await you get something like this that's a lot easier to understand.
My suspicion is that your presenceNow.check() method is not being called because the function is taking returning via one of the two return paths above it:
the file exists and myCk.checkToDelete() returns true, or
the file does not exist, and the login is unsuccessful.
const fs = require('fs/promises');
async function presence(ctx) {
var presenceData = [];
var isSuccess = false;
var ckFilePath = "./somepath/cookie.json";
let ckFilePathExists = await fs.access(ckFilePath);
if (ckFilePathExists) {
const isDel = await myCk.checkToDelete(ckFilePath);
if (isDel) {
return false;
}
} else {
const login = await menuLogin.login(ctx);
const isSuccess = login[0].status
myCk.saveCookies(login[0].cookies, ckFilePath);
if (!isSuccess) {
myCk.deleteCookies(ckFilePath);
return false;
}
}
ckFilePathExists = await fs.access(ckFilePath)
const data = await presenceNow.check(ckFilePathExists, ctx);
for (let id = 0; id < data[0].pesan.length; id++) {
console.log(data[0].pesan[id]);
}
for (let id = 0; id < data[0].id.length; id++) {
presenceData.push(data[0].id);
}
if (data[0].pesan.length == 0 && await fs.access(ckFilePath) ) {
myCk.deleteCookies(ckFilePath);
}
return presenceData;
}

Async call to Authorize.net not working as expected in node.js

Im setting an Authorize.com charge as per their API reference at https://developer.authorize.net/api/reference/index.html in Node.js.
I can place both ACH and CC transactions just fine, but Im facing a problem with the response from Authorize. Their response takes about 1 second.
After all the parameters such as CC number, expiration date, etc are filled out, I execute a function as follows (ctrl.execute(function () {}):
var ctrl = new ApiControllers.CreateTransactionController(createRequest.getJSON());
ctrl.execute(function () {
var apiResponse = ctrl.getResponse();
var response = new ApiContracts.CreateTransactionResponse(apiResponse);
if (response != null) {
if (response.getMessages().getResultCode() == ApiContracts.MessageTypeEnum.OK) {
if (response.getTransactionResponse().getMessages() != null) {
//transaction approved
AuthorizeResult.status = 1;
}
else {
//transaction rejected
if (response.getTransactionResponse().getErrors() != null) {
AuthorizeResult.status = 0;
}
}
}
else {
if (response.getTransactionResponse() != null && response.getTransactionResponse().getErrors() != null) {
AuthorizeResult.status = 0;
}
else {
AuthorizeResult.status = 0;
}
}
}
else {
AuthorizeResult.status = 0;
}
After I get a result from Authorize, I need to run this code, which Im unable to do, and if I place the code inside the function, I get an error:
SyntaxError: await is only valid in async function
at wrapSafe (internal/modules/cjs/loader.js:988:16)
at Module._compile (internal/modules/cjs/loader.js:1036:27)
sqlString = `
insert into AuthorizeBillings (memberid, datetime, authorizeid, messagecode, status, amount, billingtype, errorcode)
values (#memberid, #datetime, #authorizeid, #messagecode, #status, #amount, #billingtype, #errorcode )`
try {
const pool = await utils.poolPromise
const recordset = await pool.request()
.input('memberid', utils.sql.Int, memberid)
.....
.....
.input('errorcode', utils.sql.NVarChar, AuthorizeResult.errorcode)
.query(sqlString)
} catch (err) {
console.log(err)
}
I tried to run this function await but I had no luck. What I need is to continue the code execution AFTER this function returned a value, which I am not able to accomplish properly.
Thanks.
This probably isn't a proper answer... But maybe it will help you out. In order to use await, you have to declare the function as async. So, something like this will allow async workflow:
async function AuthorizeTrans() { // Notice async declaration
var ctrl = new ApiControllers.CreateTransactionController(createRequest.getJSON());
var AuthorizeResult = {
memberid: memberid,
.....
.....
errorcode: ""
}
const res = await ctrl.execute(); // You can now use await
var apiResponse = await res.getResponse();
....... // Rest of code...
SqlExecute(params);
}
async function SqlExecute(params) {
sqlString = `
insert into AuthorizeBillings (memberid, datetime, authorizeid, messagecode, status, amount, billingtype, errorcode)
values (#memberid, #datetime, #authorizeid, #messagecode, #status, #amount, #billingtype, #errorcode )`
try {
const pool = await utils.poolPromise
const recordset = await pool.request()
.input('memberid', utils.sql.Int, memberid)
.....
.....
.input('errorcode', utils.sql.NVarChar, AuthorizeResult.errorcode)
.query(sqlString)
} catch (err) {
console.log(err)
}
}
If you follow the logic from that syntax, you should be on the right track.

Discord.js - counter of sent messages, DM to all members of guild

So, I have a working example of code, that sends a DM to all members of a guild.
However, I want the whole thing to end with a message, sort of: "Successfully sent XX messages".
const sentMessages = 0;
if (!message.member.hasPermission(`ADMINISTRATOR`)) {
message.channel.send(`You don't have permission to use this command!`);
message.client.channels.cache.get(logchannel).send(`${message.author} tried using DMALL! ` + dato.toLocaleTimeString() + dato.toLocaleDateString());
return;
} else {
const delay = (msec) => new Promise((resolve) => setTimeout(resolve, msec));
const sendMessage = args.join(" ");
message.channel.send(`Sending messages, please wait...`);
await delay(1000);
let interval = 500; // how much time should the delay between two iterations be (in milliseconds)?
let promise = Promise.resolve();
message.guild.members.cache.forEach(function (user) {
promise = promise.then(function () {
if (user.id != message.client.user.id) {
user.send(sendMessage);
sentMessages++;
return new Promise(function (resolve) {
setTimeout(resolve, interval);
});
}
});
message.channel.send(`Successfully sent ${sentMessages} messages!`);
});
The message at the end (Successfully...) keeps returning 0, no matter when or where I place it.
If I put a line like: message.channel.send(`Sent: ${sentMessages}); below sentMessages++; I get an incrementing number like I expect.
What and where am I doing this wrong?
Ended up turning to a friend who is much better at coding than me.
He came up with a totally different way of getting there:
if (!message.member.hasPermission(`ADMINISTRATOR`)) {
message.channel.send(`You don't have permission to use this command!`);
message.client.channels.cache.get(logchannel).send(`${message.author} tried using DMALL in **${message.guild.name}**!` + dato.toLocaleTimeString() + dato.toLocaleDateString());
return;
} else {
const delay = (msec) => new Promise((resolve) => setTimeout(resolve, msec));
const sendMessage = args.join(" ");
message.channel.send(`Sending messages, please wait...`);
await delay(1000);
const interval = 500;
let array;
try {
const all = await message.guild.members.fetch();
array = all.array();
} catch {
array = message.guild.members.cache.array();
}
let sentMessages = 0;
for (var i = 0; i < array.length; i++) {
const user = array[i];
if (!user.bot) {
try {
await user.send(sendMessage);
sentMessages++;
await delay(interval);
} catch { }
}
}
message.client.channels.cache.get(logchannel).send(`${message.author} sent a DM to all members of: **${message.guild.name}**!` + dato.toLocaleTimeString() + dato.toLocaleDateString());
message.channel.send(`Finished sending messages to all users, ${sentMessages} messages sent!`);
}
This code is tested and found to be working like a charm
Use let sentMessages = 0 instead of const sentMessages = 0
Constants can't be updated or reassigned, so sentMessages++ won't do anything
Just do not do this if you do not want to be bannes from Discord, it is forbidden to send private message to all members of a guild.

Do node js worker never times out?

I have an iteration that can take up to hours to complete.
Example:
do{
//this is an api action
let response = await fetch_some_data;
// other database action
await perform_operation();
next = response.next;
}while(next);
I am assuming that the operation doesn't times out. But I don't know it exactly.
Any kind of explanation of nodejs satisfying this condition is highly appreciated. Thanks.
Update:
The actual development code is as under:
const Shopify = require('shopify-api-node');
const shopServices = require('../../../../services/shop_services/shop');
const { create } = require('../../../../controllers/products/Products');
exports.initiate = async (redis_client) => {
redis_client.lpop(['sync'], async function (err, reply) {
if (reply === null) {
console.log("Queue Empty");
return true;
}
let data = JSON.parse(reply),
shopservices = new shopServices(data),
shop_data = await shopservices.get()
.catch(error => {
console.log(error);
});
const shopify = new Shopify({
shopName: shop_data.name,
accessToken: shop_data.access_token,
apiVersion: '2020-04',
autoLimit: false,
timeout: 60 * 1000
});
let params = { limit: 250 };
do {
try {
let response = await shopify.product.list(params);
if (await create(response, shop_data)) {
console.log(`${data.current}`);
};
data.current += data.offset;
params = response.nextPageParameters;
} catch (error) {
console.log("here");
console.log(error);
params = false;
};
} while (params);
});
}
Everything is working fine till now. I am just making sure that the execution will ever happen in node or not. This function is call by a cron every minute, and data for processing is provided by queue data.

nodejs retry function if failed X times

I want my function to execute X(=3) times until success.
In my situation I'm running kinesis.putRecord (from AWS API), and if it fails - I want to run it again until it succeeds, but not more than 3 tries.
I'm new to NodeJS, and the code I wrote smells bad.
const putRecordsPromise = function(params){
return new Promise((resolve, reject) => {
kinesis.putRecord(params, function (err, data) {
resolve(err)
});
})
}
async function waterfall(params){
try{
let triesCounter = 0;
while(triesCounter < 2){
console.log(`try #${triesCounter}`)
let recordsAnswer = await putRecordsPromise(params)
if(!recordsAnswer){
console.log("success")
break;
}
triesCounter += 1;
}
// continue ...
} catch(err){
console.error(err)
}
}
waterfall(params)
I promise the err result. Afterwards, If the err is empty, then all good. otherwise, continue running the same command.
I'm sure there is a smarter way to do this. Any help would be appreciated.
I think, all the Aws functions can return a Promise out of the box, then you can just put the call into try/catch:
let triesCounter = 0;
while(triesCounter < 2){
console.log(`try #${triesCounter}`)
try {
await kinesis.putRecord(params).promise();
break; // 'return' would work here as well
} catch (err) {
console.log(err);
}
triesCounter ++;
}
In functional style:
...
await tryUntilSucceed(() => kinesis.putRecord(params).promise());
...
async function tryUntilSucceed(promiseFn, maxTries=3) {
try {
return await promiseFn();
} catch (e) {
if (maxTries > 0) {
return tryUntilSucceed(promiseFn, maxTries - 1);
}
throw e;
}
}
Make a little module, say try-and-try-again.js:
exports = module.exports = tryAndTryAgain;
function tryAndTryAgain( maxTries, thisContext , fn, ...argv) {
let success = false;
for (let i = i ; i < maxTries && !success ; ++i ) {
let rc = fn.apply(thisContext, args);
success = rc == 0 ? true : false;
}
return success;
}
Then you can use it anywhere:
const tryAndTryAgain = require('./try-and-try-again');
function somethingThatMightNeedARetry() { ... }
const succeeded = tryAndTryAgain( 3 , null, somethingThatMightNeedARetry, 'arg-1', 'arg-2', 'arg-3' );
There is an npm package called async-retry that is pretty handy. It acts as a wrapper for your function and retries if anything throws (with some exceptions that you can handle, see their example below).
// Packages
const retry = require('async-retry')
const fetch = require('node-fetch')
await retry(async bail => {
// if anything throws, we retry
const res = await fetch('https://google.com')
if (403 === res.status) {
// don't retry upon 403
bail(new Error('Unauthorized'))
return
}
const data = await res.text()
return data.substr(0, 500)
}, {
retries: 5
})

Resources