Execute function for every helper and events - node.js

I'm trying to build an automatic error reporting system for my meteor app but there is one little thing I'm not able to do right now. I would like to know if it is possible to create some sort of wrapper that would execute each time a helper or an event is called, for any template.
I've searched in blaze.js to see how they handle it and possibly edit it but I guess altering this file is not the way to go.
I found nothing about that, and at this point, I'm not sure it is even possible.
EDIT: I found some sort of a solution but it's far from perfect.
I've created a globalHelper :
Template.registerHelper('checkError', (tmplName, helperName, ...args) => {
try {
return Template[tmplName].__helpers.get(helperName).apply(this, args);
} catch(error) {
let trace = error.stack.split('\n').map(function (line) { return line.trim(); })
let obj = {
text: "" + error,
date: parseInt(Date.now() / 1000),
function: trace[0].split('#')[0],
template: tmpl,
trace: trace.slice(0, trace.length - 1)
}
Meteor.call("logNewCrash", obj, function(err, res) {
if (!err) {
Bert.alert("Une erreur est survenue et à été communiquée à un administrateur. Elle sera traitée dans les plus brefs délais.", "danger");
}
})
}
});
It works as expected but I need to call this helper instead of the original ones, for exemple :
<template name=templateName1>
{{#if checkError 'templateName1' 'helperName1' arg1 arg2}}
<!--do something-->
{{/if}}
</template>
with the following helper :
helperName1(arg1, arg2) {
if (arg1 == arg2)
return true;
return false;
}
EDIT 2 :
So I dropped my previous work to create a meteor package.
I successfully overrode Blaze._wrapCatchingExceptions like so :
Blaze._wrapCatchingExceptions = function (f, where) {
if (typeof f !== 'function')
return f;
return function () {
try {
return f.apply(this, arguments);
} catch (error) {
let trace = error.stack.split('\n').map(function (line) { return line.trim(); })
let obj = {
text: "" + error,
date: parseInt(Date.now() / 1000),
function: trace[0].split('#')[0],
template: Template.instance().view.name.split('.')[0],
trace: trace.slice(0, trace.length -1)
}
Meteor.call(configuration.method, obj, function(err, res) {
if (!err) {
Bert.alert(res.msg, "danger");
}
});
Blaze._reportException(error, 'Exception in ' + where + ':');
}
};
};
However, some errors aren't handled by Blaze but by Tracker. This is where it's getting frustrating, I can't get my Tracker override to work.
I tried to override Tracker._runFlush and _throwOrLogbut either I got a Maximum stack size exceeded or my function is just not called at all.
I probably was doing it wrong.
What am I missing ?
Thanks

Related

Node.js: Multiple inputs from user in an interactive CLI

I'm trying to create a simple interactive CLI with Node.js, that collects input from the user by "talking" to them asking questions.
I'm working with the 'readline' module that forces me to use the callback mechanism, currently results in the weird cascade below.
As I'm new to Node.js and to the callback idea, I really feel I'm doing something wrong but not sure how to make it better.
How can I reformat my function so it will be more elegant?
(I know the function below won't return anything, it's just for my temp debugging)
function getUserInput(dbData) {
readline.question('What would you like to edit?\n\n\t(1) Cars\t(2) Data owners\n', choice => {
if (choice == 1) {
readline.question('Choose operation:\n\n\t(1) Add new\n', op => {
if (op == 1) {
let newCar = {};
console.log("--> Please fill in the required details (with Capital First Letter):\n\n");
readline.question("Car name: ", carName => {
newCar.name = carName;
readline.question("Car make: ", carMake => {
newCar.make = carMake;
readline.question("Team (DC/CSF): ", team => {
newCar.team = team;
readline.question("TC (1/2): ", tc => {
newCar.tc = tc;
readline.close();
console.log(newCar);
});
});
});
});
}
else {
console.log("Invalid choice!\n");
getUserInput(dbData);
}
});
}
else {
console.log("Invalid choice!\n");
getUserInput(dbData);
};
});

callback is not a funcion - JSON file read

I did some research but all the responses that i get didn't resolved my problem.
Basically, i have the following code:
public static load(lang: string, staReplace: boolean, callback?: (message: string, error?: string) => void) {
if (!TranslateSingleton.languageFile) {
TranslateSingleton.languageFile = new Map<string, Object>();
}
lang = lang.toLowerCase();
if (!TranslateSingleton.languageFile.has(lang) || staReplace === true) {
try {
let strBody: string = fs.readFileSync(AppConfig.APP_SERVER_DIRETORIO + '/languages/language-' + lang + '.json', 'utf8')
TranslateSingleton.languageFile.set(lang, JSON.parse(strBody));
callback('OK', null);
} catch (ex) {
AppLog.error('IDIOMA NÃO ENCONTRADO ==>', AppConfig.APP_SERVER_DIRETORIO + '/languages/language-' + lang + '.json');
callback(null, '## IDIOMA [' + lang + '] não disponível! ##');
}
}
}
And when the 'load' function is called, i always get the response:
1) In the TS TranslateSingleton file:
TranslateSingleton.load(lang, false, null);
2) In another controller:
TranslateSingleton.load(resultToken.lang, true, (resultMessage, errorMessage) => {
if (errorMessage) {
resolve(super.trataErro(res, errorMessage));
} else {
resolve(super.trataRetorno(req, res, resultMessage));
}
});
And, then, my response:
[2020-06-10T11:47:06.257] [ERROR] default - [APPLOG] IDIOMA NÃO ENCONTRADO ==> [ './../languages/language-pt-br.json' ]
[2020-06-10T11:47:06.259] [ERROR] default - [APPLOG] Erro ao recuperar a chave: "AUDITORIA.REGISTRO_AUDITORIA", [ TypeError: callback is not a function
at Function.TranslateSingleton.load (C:\Users\emmanuel.oliveira\Documents\AgenciaWeb\aw-server\bin\util\translate.js:24:17)
at TranslateSingleton.__ (C:\Users\emmanuel.oliveira\Documents\AgenciaWeb\aw-server\bin\util\translate.js:44:32)
at C:\Users\emmanuel.oliveira\Documents\AgenciaWeb\aw-server\bin\service\auditoria.service.js:423:62
at C:\Users\emmanuel.oliveira\Documents\AgenciaWeb\aw-server\bin\service\base\base.service.js:374:29
at custExecuteCb (C:\Users\emmanuel.oliveira\Documents\AgenciaWeb\aw-server\node_modules\oracledb\lib\connection.js:182:7) ]
Can someone give me a light in this?
I suppose you are getting the error on this line of code:
TranslateSingleton.load(lang, false, null);
Here you have basically passed null as the argument for the callback parameter.
Inside the function body on line callback('OK', null), this tries to invoke or call the function that you have passed as the callback argument. Since your argument is null, it cannot invoke since null is not a function, therefore it throws the error.
Solved this issue by taking the following steps:
1) Changed the calling function
TranslateSingleton.load(lang, false, (a, b) => { });
2) Changed the path to root directory (only for dev instance)
PRD -> ./
DEV -> ./../

Discord.js-commando: Stopping all commands if not in a specific channel

For testing I am trying to stop all commands, unless in a certain channel. I know how to do this for each command specifically, but I am trying to catch it inside of the main bot file, and return a message. I have tried two ways so far:
bot.on('command', async m => { (Also tried 'commandmessage')
console.log('COMMAND');
if (m.channel != 'bot-testing') {
return m.channel.send('You can\'t use commands here!');
}
});
Which doesn't work at all. Then I tried this:
bot.on('message', async m => {
m.isDM = (m.guild ? false : true);
if (m.content[0] != bot.commandPrefix) {
return;
} else {
if (m.channel != 'bot-testing') {
m.channel.send('You can\'t use commands here!');
}
}
});
Which kind of works, but doesn't stop the command.
It looks like you were super close - you just need to look at m.channel.name in your second if-statement (using method #2):
bot.on('message', async m => {
// ...
if (m.content[0] != bot.commandPrefix) {
return;
} else {
// [NEW: add .name prop here]
if (m.channel.name != 'bot-testing') {
m.channel.send('You can\'t use commands here!');
}
}
});

Nested asynchronous mongoDB calls in node js

I have quite a simple problem, but I can't find an elegant solution to fix this.
In the following code, I have two nested calls to a mongo DB. I use Monk to manage my calls.
The problem is : the for loop (1) loops before the nested insertion can happen. So the next find (2) instruction does not find the last inserted action.
The call order is 1-2-2-2-3-3-3 (for an actionList of size 3). So all my data is inserted.
My objective is to have the call order 1-2-3-2-3-2-3
Do you have any clue of how to manage such a problem, without making a big find on my database and manage my list server-side ? (Get all data, make myself the search, that is quite horrible to do, insert elements I want, then push it all to the db...)
for (var action of actionList)//(1)
{
collectionActions.find(//(2)
{eventid : action.eventid},
function(e,actionsFound)
{
if (actionsFound.length == 0)
{
collectionActions.insert(action, function(err, result)//(3)
{
console.log("insert action : " + action._id);
})
}
}
)
}
The native Promise object has an all method that could be leveraged to help.
Assuming find is a compliant promise, the following code would queue up all of the actions in an array through map and which would return a promise for each action that eventually returns messages to the final then for all.
A couple of notes: your code as it stands swallows all of the errors that might occur (I'm not sure that is want you want); this also assumes that insert returns a promise.
Promise.all([
// Iterate over actionList
actionList.map(function(action) {
// returns a promise with a then already attached
return collectionActions.find({
eventid: action.eventid
}).then(function(e, actionsFound) {
if (actionsFound.length == 0) {
// returns another promise that will resolve up to outer promises
return collectionActions.insert(action, function(err, result) {
// Finally resolve a value for outer promises
return 'insert action : ' + action._id;
});
} else {
// A different value to resolve with if the above promise
// is not required
return 'some other message for ' + action._id;
}
});
})
]).then(function(results) {
// Log out all values resolved by promises
console.log(results);
});
UPDATE: After the clarification of the question it sounds like you just need to chain the promises together rather than run them in parallel.
// Iterate over actionList
actionList.reduce(function(promise, action) {
// Chain promises together
return promise.then(function(results) {
return collectionActions.find({
eventid: action.eventid
}).then(function(e, actionsFound) {
if (actionsFound.length == 0) {
// returns another promise that will resolve up to outer promises
return collectionActions.insert(action, function(err, result) {
// Finally resolve a value for outer promises
return results.push('insert action : ' + action.sourceName);
});
} else {
// A different value to resolve with if the above promise
// is not required
return results.push('some other message for ' + action.sourceName);
}
});
});
}, Promise.resolve([])).then(function(results) {
// Log out all values resolved by promises
console.log(results);
});
I finally got my solution, by using a recursive function.
var currentIndex = 0;
var searchAndInsert = function(actionList)
{
var action = actionList[currentIndex];
if (typeof actionList[currentIndex] != "undefined")
{
collectionActions.find(
{eventid : action.eventid},
function(e,actions)
{
console.log("find ended")
if (actions.length == 0)
{
collectionActions.insert(action, function(err, result)
{
console.log("insert action : " + action.sourceName);
currentIndex++;
if (typeof actionList[currentIndex] != "undefined")
searchAndInsert(actionList);
})
}
else
{
currentIndex++;
if (typeof actionList[currentIndex] != "undefined")
searchAndInsert(actionList);
}
}
)
}
};

return value from a function with asynchronous commands

I'm writing a NodeJS v0.10 application with MariaSQL.
i want to create a function that returns the id of a row, and if the row doesn't exist, to create it and then return the id.
this is what I have so far:
TuxDb.prototype.createIfNEDrinkCompany = function(drinkCompany) {
this.client.query("insert into drink_company(drink_company_name) values(:drink_company) on duplicate key update drink_company_id=drink_company_id",
{'drink_company' : drinkCompany})
.on('result',function(res) {
res.on('end',function(info){
if (info.insertId > 0) {
return info.insertId;
} else {
this.client.query("select drink_company_id from drink_company where drink_company_name = :drink_company",{'drink_company' : drinkCompany})
.on('result',function(res){
res.on('row',function(row){
return row.drink_company_id;
});
});
}
});
});
}
now the problem is that since it's asynchronous, the function ends before the value is returned.
how can I resolve this issue ?
The standard way in nodejs of dealing with async code is to provide a callback function as a last argument to your method and call it whenever your asynchronous finishes. The callback function standard signature is (err, data) - you can read more about here: Understanding callbacks in Javascript and node.js
Rewriting your code:
TuxDb.prototype.createIfNEDrinkCompany = function(drinkCompany, callback) {
this.client.query("insert into drink_company(drink_company_name) values(:drink_company) on duplicate key update drink_company_id=drink_company_id",
{'drink_company' : drinkCompany})
.on('result',function(res) {
res.on('end',function(info){
if (info.insertId > 0) {
callback(null, row.drink_company_id);
} else {
this.client.query("select drink_company_id from drink_company where drink_company_name = :drink_company",{'drink_company' : drinkCompany})
.on('result',function(res){
res.on('row',function(row){
callback(null, row.drink_company_id);
});
});
}
});
});
}
and then in the code calling your method
db.createIfNEDrinkCompany(drinkCompany, function(err, id){
// do something with id here
})

Resources