Need integrate Note JS (note-telegram-bot-api) and MySQL - javascript

The main thing is that I have errors in nesting, but I can’t figure out how to fix it correctly (after if (data === '301') ). There is an exchange of a bot with a user according to the principle of a bot question - an answer in an arbitrary form of the user, then a variable is assigned to this answer, so that later this information can be easily transferred to the database, and then the next question is similar. All data is filled in correctly in the database, but if the user wants to leave another request (there is an engineerOptions97 button at the end), dubbing starts and all answers come out twice, then four times, and so on.
const TelegramApi = require('node-telegram-bot-api')
const {botOptions, engineerOptions, engineerOptions23, engineerOptions99, engineerOptions21, engineerOptions22, engineerOptions98, engineerOptions25, engineerOptions97, engineerOptions999, engineerOptions96} = require('./button')
const token = 'хх' //token here
const bot = new TelegramApi(token, {polling: true})
const start = () => {
var mysql = require('mysql');
var pool = mysql.createPool({
host: "localhost",
user: "root",
database: "node_bot",
password: "",
connectionLimit: "20",
queueLimit: "0",
waitForConnections: "true"
});
pool.getConnection(function(err, connection) {
if (err) throw err;
bot.on('callback_query', async msg => {
const data = msg.data;
const chatID = msg.message.chat.id;
const opts = {
reply_markup:{
},
parse_mode: 'Markdown'
};
var d = new Date()
var datestring = d.getFullYear() + "." + (d.getMonth()+1) + "." + d.getDate()
var timestring = d.getHours() + ":" + d.getMinutes()
if (data === '301') {
bot.sendMessage(chatID, `Where we need fix?`).then(function (result11) {
console.log(result11)
bot.on('message', async msg => {
var place = msg.text;
console.log(place);
bot.sendMessage(chatID, `What we need fix?`).then(function (result12) {
console.log(result12)
bot.on('message', reqtext => {
const texttext = reqtext.text;
console.log(texttext);
bot.sendMessage(chatID, `We understand thanks`, engineerOptions97)
pool.query("INSERT INTO `request` (`date`, `time`, `block`, `place`, `text`) VALUES ('"+datestring+"', '"+timestring+"', 'САНТЕХНИКИ', '"+place+"', '"+texttext+"')", function(err, results) {
connection.release();
if(err) console.log(err);
console.log(results);
});
})
})
})
})
}
return
})
});
}
start()
It works but not as clean as I would like. And my requests are duplicated

Related

Why I am unable to delete a database record using a NodeJS code?

Please check the below code
// This is a CRON job
// This function will walk through the FCM records everyday and remove records older than 2 months
const mysql = require('mysql2/promise');
const errorCodes = require('source/error-codes');
const PropertiesReader = require('properties-reader');
const prop = PropertiesReader('properties.properties');
const pool = mysql.createPool({
connectionLimit : 10,
host: prop.get('server.host'),
user: prop.get("server.username"),
password: prop.get("server.password"),
port: prop.get("server.port"),
database: prop.get("server.dbname")
});
exports.fcmManager = async (event, context) => {
const connection = await pool.getConnection();
context.callbackWaitsForEmptyEventLoop = false;
connection.config.namedPlaceholders = true;
try {
await connection.beginTransaction();
//Get the current datetime
const currentDateTime = new Date();
currentDateTime.setMonth(currentDateTime.getMonth() - 2);
console.log(currentDateTime.toLocaleDateString());
//Delete the records
const deleteFcmSql = "DELETE FROM fcm WHERE date_created < :date ";
const deleteFcmResult = await connection.query(deleteFcmSql, {date:currentDateTime});
} catch (error) {
console.log(error);
await connection.rollback();
return errorCodes.save_failed;
}
finally{
connection.release();
}
};
In my database I have a records which is created on 2022-07-20 05:01:41. So technically, this record needs to get deleted because this code console.log(currentDateTime.toLocaleDateString()); prints the date 7/21/2022.
However, nothing get deleted and no change is taking place in the database. What is wrong here?
I found the issue. Just had to add the following code line
await connection.commit();

Nodemailer doesn't seem to be freeing up TCP Ports after a mail has been sent

As the question says, I'm having an issue with our bulk mailing server.
So for abit of background, This emailing application of ours runs on a CRON job, sending out mails every hour.
Every 12 hours, We send out our biggest bulks, there are around 8 different groups and each group can have anywhere between 2000 - 4000 mails in each group that needs to be sent.
This application is built in Nodejs and uses Nodemailer to handle the sending of the mails.
What I've noticed for awhile now is that every so often the server would essentially "freeze" up and the memory usage of the app would slowly climb.
Windows Event log showed this error after the last bulk emailing was meant to run, "A request to allocate an ephemeral port number from the global TCP port space has failed due to all such ports being in use."
I've gone through the documentation on the Nodemailer website and applied the following changes
Using a pooled SMTP - This is still currently in the application
Set maxMessages to infinity - I've removed this as it didn't seem to help
Set maxConnections to 20 - Also removed because it made no difference
Using a dedicated queue manager - This was my final attempt, I went with RabbitMQ and have applied their Publish/Subscribe model.
RabbitMQ has improved the performance alot but it still hasn't resolved the issue.
Publish Function
const PublishMails = (mailObj) => {
return new Promise((resolve, reject) => {
var publishMailResult = {};
if (mailObj.length > 0) {
var connection = global.RabbitMQConnection;
connection.createChannel((err, channel) => {
if (err) {
publishMailResult.Result = false;
publishMailResult.Message = err.stack;
resolve(publishMailResult);
//return process.exit(1);
}
channel.assertQueue(config.RabbitMQ.Queue_EmailQueue, {
durable: true
}, err => {
if (err) {
publishMailResult.Result = false;
publishMailResult.Message = err.stack;
resolve(publishMailResult);
//return process.exit(1);
}
var mailData = {}
for (var x = 0; x < mailObj.length; x++) {
mailData.from = 'XXX#XXX.com';
mailData.to = mailObj[x].Email;
mailData.firstName = mailObj[x].FirstName;
mailData.login = mailObj[x].Login;
mailData.email = mailObj[x].Email;
mailData.mailID = mailObj[x].MailID;
mailData.sendID = mailObj[x].SendID;
mailData.subject = "Email Message";
mailData.template = 'EmailTempLate';
channel.sendToQueue(config.RabbitMQ.Queue_EmailQueue,
Buffer.from(JSON.stringify(mailData)), {
persistent: true,
contentType: 'application/json'
});
if (x === mailObj.length - 1) {
channel.close();
publishMailResult.Result = true;
publishMailResult.Message = "All mails successfully published.";
resolve(publishMailResult);
}
}
});
})
} else {
publishMailResult.Result = false;
publishMailResult.Message = "No mails were received - Mails Not Published.";
resolve(publishMailResult);
}
});
}
Subscribe function
const SubscribeMails = (mailObj) => {
return new Promise((resolve, reject) => {
if (mailObj.PublishMailResult.Result == true) {
var options = {
viewEngine: {
extname: '.html',
layoutsDir: 'views/email/',
defaultLayout: 'Email_Template'
},
viewPath: 'views/email',
extName: '.html'
};
var transporter = nodemailer.createTransport(smtpTransport({
host: 'XXX.XXX.XXX.XX',
port: 25,
pool: true
}));
transporter.use('stream', require('nodemailer-dkim').signer({
domainName: 'XXX.com',
keySelector: 'main',
privateKey: 'XXXX'
}));
transporter.use('compile', hbs(options));
var connection = global.RabbitMQConnection;
connection.createChannel((err, channel) => {
if (err) {
console.error(err.stack);
return process.exit(1);
}
channel.assertQueue(config.RabbitMQ.Queue_EmailQueue, {
durable: true
}, err => {
if (err) {
console.error(err.stack);
return process.exit(1);
}
channel.prefetch(1);
channel.consume(config.RabbitMQ.Queue_EmailQueue, data => {
if (data === null) {
return;
}
let mail = JSON.parse(data.content.toString());
transporter.sendMail({
from: mail.from,
to: mail.to,
subject: mail.subject,
template: mail.template,
context: {
FirstName: mail.firstName,
Email: mail.email,
MailID: mail.mailID,
SendID: mail.sendID,
}
}, (err, info) => {
if (err) {
console.error(err.stack);
return channel.nack(data);
}
channel.ack(data);
channel.checkQueue(config.RabbitMQ.Queue_EmailQueue, function (checkErr, queueData) {
if (queueData != null) {
if (queueData.messageCount == 0) {
channel.close();
transporter.close(); // Added in to test if this free's up TCP ports - Didn't help
}
}
});
});
});
resolve(true);
});
});
}
});
}
It really feels like I'm meant to be somehow closing these TCP connections manually but I haven't seen anything written about this in the documentation or haven't seen it mentioned on any example code I've seen.
I'm adding in the Cron job that starts this process to perhaps help debug this issue.
var cronPCSec = '0';
var cronPCMin = '58';
var cronPCHour = '*';
var cronPCDay = '*';
var cronPCMonth = '*';
var cronPCDayOfWeek = '0-6';
var cronPCfulltimes = "" + cronPCSec + " " + cronPCMin + " " + cronPCHour + " " + cronPCDay + " " + cronPCMonth + " " + cronPCDayOfWeek + "";
var MailerCronJob = new CronJob({
cronTime: cronPCfulltimes,
onTick: function () {
let objCronJob = {};
modelPC.GetMails().then(function (mail) {
return mail;
}).then(PublishMails).then(function (PublishResult) {
objCronJob.PublishMailResult = PublishResult;
return objCronJob;
}).then(SubscribeMails).then(function (result) {
console.log("Completed Successfully");
}).catch(err => {
console.log("Failed");
console.log(err)
});
},
start: false
});
MailerCronJob.start();
Thanks

I want a command that sends an embed with all the servers that the bot is in

I created a discord.js bot and after some time I wanted to add a servers list command
that sends a message with an embed for each server containing: Server Name, Member Count, Server Avatar (As The Embed Thumbnail), Server Owner ID and Most importantly I don't want anyone to be able to use this command except for me so maybe I add a constant with my ID?,
I can't really come up with a code for it, but anyways... here's the format of one of the commands:
if((args[0] === settings.prefix + "deletereactions" || args[0] === settings.prefix + "dr") && msg.member.hasPermission("ADMINISTRATOR")){
//deletereactions #channel
let channel = msg.mentions.channels.array()[0];
if(!channel) return;
let db = client1.db("rbot");
let collection = db.collection("reactions");
collection.deleteOne({channel : channel.id}, function(err){
if(err) console.log(err);
msg.reply("**✅ Done!**");
})
}
})
and here's my command handler:
const settings = require("./settings.json");
const Discord = require("discord.js");
const client = new Discord.Client();
const fs = require("fs");
const MongoClient = require("mongodb").MongoClient;
const url = "my_mongodb_url";
const mongoClient = new MongoClient(url, { useUnifiedTopology: true });
const moment = require("moment");
const { CommandCursor } = require("mongodb");
let client1;
client.login(settings.token);
client.on("ready", ready =>{
console.log("Ready");
mongoClient.connect(function(err, cli){
client1 = cli;
})
client.user.setActivity(`${settings.activity}`, { type: 'LISTENING' })
})
client.on("message", async msg =>{
let args = msg.content.split(' ');
if(msg.channel.type !== "text") return;
if(msg.channel.type === "text"){
let db = client1.db("rbot");
let collection = db.collection("reactions");
collection.findOne({channel : msg.channel.id}, function(err, result){
if(err) console.log(err);
if(result){
for(let i = 0; i < result.reactions.length; i++){
msg.react(result.reactions[i]).catch(err =>{
if(err) collection.deleteOne({channel : msg.channel.id}, function(err){
if(err) console.log(err);
})
});
In Your Command (Run Or Execute Function):
For 1 User:
if (message.author.id != "YOUR ID") return;
For 2+ Users:
let Owners = ["ID 1", "ID 2"];
if (!Owners.includes(message.author.id)) return;
Ex:
module.exports = {
name: "eval",
run: async (client, message, args) => {
if (message.author.id != "696969696969") return message.channel.send("Only Owners Can Use Eval Command!");
//...
}
};
Links:
User#id
Array

Node js promise chaining issue

I am trying to connect to Salesforce using node js / jsforce library and use promises. Unfortunately one of the methods is executing prior to getting connection.
i have method A : makeconnection which returns the connection
i have method B : which loads data from Salesforce based on the connection reference from method A
I have method C : which gets dependencies from Salesforce based on connection from method A
I would like the following order to be executed A ==> B ==> C
Unfortunately C seems to run first followed by A and B so the connection is null and it fails
roughly this is the code
let jsforce = require("jsforce");
const sfdcSoup = require("sfdc-soup");
const fs = require("fs");
let _ = require("lodash");
let trgarr = [];
let clsarr = [];
let entityarr = [];
function makeConnection() {
return new Promise((resolve,reject) => {
const conn = new jsforce.Connection({
loginUrl: "https://test.salesforce.com",
instanceUrl: "salesforce.com",
serverUrl: "xxx",
version: "50.0"
});
conn.login(username, password, function (err, userInfo) {
if (err) {
return console.error(err);
}
// console.log(conn.accessToken);
//console.log(conn.instanceUrl);
//console.log("User ID: " + userInfo.id);
//console.log("Org ID: " + userInfo.organizationId);
console.log("logged in");
});
resolve(conn);
});
}
function loadClasses(conn) {
return new Promise((resolve,reject) => {
const querystr =
"select apiVersion,name,body from apexClass where NamespacePrefix = null";
let query = conn
.query(querystr)
.on("record", function (rec) {
clsarr.push(rec);
})
.on("end", function () {
console.log("number of class is " + clsarr.length);
console.log("loaded all classes");
});
resolve(conn,clsarr);
});
}
async function getDependencies(conn) {
return new Promise((resolve,reject) => {
let entryPoint = {
name: "xxx",
type: "CustomField",
id: yyy
};
let connection = {
token: conn.accessToken,
url: "abc.com",
apiVersion: "50.0"
};
let usageApi = sfdcSoup.usageApi(connection, entryPoint);
usageApi.getUsage().then((response) => {
console.log(response.stats);
console.log(response.csv);
});
});
}
async function run() {
makeConnection().then(conn => loadClasses(conn)).then(conn=>getDependencies(conn));
}
run();
I keep getting an error that says UnhandledPromiseRejectionWarning: Error: Access token and URL are required on the connection object
The reason is connection needs to be obtained from method A and sent to Method C , which is not happening. Can you please guide where i might be wrong?
Also why is method C getting executed before A and B. why does my promise chaining not work as promised?
I am running the code in Vscode and using Node 14
Your 2 method have minor correction first method makeConnection, the resolve should be inside login after console.log("logged in")
And second loadClasses, the resolve should be inside 'end' event. Please check below 2 method.
function makeConnection() {
return new Promise((resolve,reject) => {
const conn = new jsforce.Connection({
loginUrl: "https://test.salesforce.com",
instanceUrl: "salesforce.com",
serverUrl: "xxx",
version: "50.0"
});
conn.login(username, password, function (err, userInfo) {
if (err) {
return console.error(err);
}
// console.log(conn.accessToken);
//console.log(conn.instanceUrl);
//console.log("User ID: " + userInfo.id);
//console.log("Org ID: " + userInfo.organizationId);
console.log("logged in");
resolve(conn);
});
});
}
function loadClasses(conn) {
return new Promise((resolve,reject) => {
const querystr =
"select apiVersion,name,body from apexClass where NamespacePrefix = null";
let query = conn
.query(querystr)
.on("record", function (rec) {
clsarr.push(rec);
})
.on("end", function () {
console.log("number of class is " + clsarr.length);
console.log("loaded all classes");
resolve(conn,clsarr);
});
});
}
you should use promise series if methods are depending on each other if methods do not depend then you should use a promise parallel.
READ MORE ABOUT PROMISE SERIES AND PARALLEL.

Storing the data to MongoDB collection to specific name

I create a script which receives the data from Binance API at sends it to MongoDB.
The scripts starts every hour with Node-Schedule package and as well it receive three different data's depending on their symbol (BTCUSDT, ETHUSDT, ATOMBTC). I also create a script which is automatically stores the receiving data to MongoDB collection.
Goal: I would like to store the specific data to specific collection. My though was to made a something like if statement and have the symbol name same as collection name. For example
if symbol name = collection name => save to collection
Is this way can help me out? I will have three symbols and three collections. Both of them will have same names.
Full Code
var today = new Date();
var date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate();
var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
var dateTime = date + ' ' + time;
var symbols = ["BTCUSDT", "ETHUSDT", "ATOMBTC"];
let cnt = 0;
const callIt = () => {
fetch(`https://api.binance.com/api/v3/klines?symbol=${symbols[cnt]}&interval=1h&limit=1`)
.then(res => res.json())
.then(data => {
const btcusdtdata = data.map(d => {
return {
Open: parseFloat(d[1]),
High: parseFloat(d[2]),
Low: parseFloat(d[3]),
Close: parseFloat(d[4]),
Volume: parseFloat(d[5])
}
});
console.log(btcusdtdata);
saveToBTCUSDT(btcusdtdata);
cnt++;
if (cnt < symbols.length) setTimeout(callIt, 3000)
})
.catch((err) => {
console.log(err);
})
};
const j = schedule.scheduleJob('0 * * * *', callIt)
const saveToBTCUSDT = function(BTCdata) {
const url = 'mongodb+srv://username:password#cluster0-1kunr.mongodb.net/<dbname>?retryWrites=true&w=majority';
MongoClient.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }, (err, db) => {
if (err) throw err;
const dbo = db.db('CryptoCurrencies');
const myobj = { Name: 'BTCUSDT', Array: BTCdata, Date: dateTime };
dbo.collection('BTCUSDT').insertOne(myobj, (error, res) => {
if (error) throw error;
console.log('1 document inserted');
db.close();
});
});
};
You can pass the current index (count) as a parameter and then address the desired collection with the index.
...
saveToBTCUSDT(btcusdtdata, cnt);
...
const saveToBTCUSDT = function(BTCdata, index) {
const url = 'mongodb+srv://username:password#cluster0-1kunr.mongodb.net/<dbname>?retryWrites=true&w=majority';
MongoClient.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }, (err, db) => {
if (err) throw err;
const dbo = db.db('CryptoCurrencies');
const myobj = { Name: symbols[index], Array: BTCdata, Date: dateTime };
dbo.collection( symbols[index] ).insertOne(myobj, (error, res) => {
if (error) throw error;
console.log('1 document inserted');
db.close();
});
});
};

Categories