callback is not a funcion - JSON file read - node.js

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 -> ./../

Related

Execute function for every helper and events

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

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!');
}
}
});

How do I stop a table script from processing?

I am creating an insert script that does some business logic.
Basically, I want to check to see if a value in the inserted item exists in a table. But, it seems like if I find a problem Request.Send() doesn't stop execution and get an error.
I think there is an async issue here. I'm not 100% sure how to solve.
Is there a way to stop execution of the script?
if (item.memberType === 'Family' && item.primaryFamilyMember) {
table
.where({
memberNumber: item.primaryFamilyMember,
memberType: 'Family',
primaryFamilyMember: null })
.read({
success: function(results) {
if (results.length == 0) {
request.respond(statusCodes.BAD_REQUEST,
'Invalid Primary Family Member specified.');
console.error('Invalid Primary Family Member specified:' + item.primaryFamilyMember);
validInsert = false;
} else {
item.memberType = results[0].memberType;
item.memberLevel = results[0].memberLevel;
item.dateOfExpiry = results[0].dateOfExpiry;
}
}
});
}
if (validInsert) {
var today = new Date();
var prefix = today.getFullYear().toString().substr(2,2) + ('0' + (today.getMonth() + 1)).slice(-2);
table.includeTotalCount().where(function(prefix){
return this.memberNumber.substring(0, 4) === prefix;
}, prefix)
.take(0).read({
success: function (results) {
if (isNaN(results.totalCount)) {
results.totalCount = 0;
}
item.memberNumber = prefix + ('00' + (results.totalCount + 1)).slice(-3);
request.execute();
}
});
}
Yes, validInsert is declared at the top of the insert function.
I assume what's happening is the if(validInsert) runs before the read callback. But if so, i'm not sure why I'm getting "Error: Execute cannot be called after respond has been called." That implies the callback is running first.
Also, the record is being inserted when it shouldn't be even though the 400 error is sent back to the client.
This is an express app right? Should I just call response.end() after the error occurs?
Yes, there are definitely asyn issues in that code. To solve get rid of your validInsert flag and simply move the if (validInsert) section into the success callback (or make it a function called from the success callback). For example:
success: function(results) {
if (results.length == 0) {
request.respond(statusCodes.BAD_REQUEST,
'Invalid Primary Family Member specified.');
console.error('Invalid Primary Family Member specified:' + item.primaryFamilyMember);
} else {
item.memberType = results[0].memberType;
item.memberLevel = results[0].memberLevel;
item.dateOfExpiry = results[0].dateOfExpiry;
var today = new Date();
var prefix = today.getFullYear().toString().substr(2,2) + ('0' + (today.getMonth() + 1)).slice(-2);
...
//respond successfully
}
}

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
})

Service that returns data from an asynchronous method

I am using Sails' ORM (Waterline). I have written a geturl service that should return the url of several models/actions in my app. I am currently calling this service inside my templates.
(As I am alone to develop this, don't hesitate to warn me if this design pattern is wrong)
Now it occurs that Waterline's .find() method is asynchronous (as it should). I always use callbacks to do things when inserting or fetching things in database.
Now I have seen everywhere that I cannot return any data from asynchronous methods. As a consequence I am puzzled because I want to create this [damned] service to centralize the URL management.
Here is my current code:
module.exports = {
variete: function(id_objet) {
var string = '/default_url';
return onvariete(id_objet, function (err, url) {
if (err) {
sails.log.error('Error : ', err);
} else {
return url;
}
});
}
};
function onvariete(id_objet, next) {
var url = '/';
return Variete.findOne({id:id_objet}).exec(function (err, v) {
sails.log.info('URL Variety : '+ v.nom + ' / ' +id_objet + ' / ' + v.slug);
if (err) {
sails.log.error('Error : ' + v.nom + ' / ' + err);
// Do nothing.
return next(new Error('Variete error'), undefined);
} else if (!v) {
return next(new Error('Variete not found'), undefined);
} else if (!v.slug) {
// variete doesn't have a slug field
// we redirect to /v/:id
url += 'v/' + v.id;
return next (null, url);
} else {
// Ok variete has got a slug field
sails.log.info('GOT A SLUG! ' + v.slug);
url += 'variete/' + v.slug;
return next (null, url);
}
});
}
I made a static object that embeds my geturl service, and then inside a Jade template:
a(href="#{s.geturl.variete(ann.variete.id)}" title="#{ann.variete.name}") #{ann.variete.name}
And I can get something like:
<a title="Tomate Coeur de Boeuf" href="undefined">Tomate Coeur de Boeuf</a>
Thank you by advance.
The solution vas to write a .url(bool) instance method. See how to write instance methods in Sails / Waterline.
This way I directly access this method from my template : a(href="#{ann.variete.url()}" title="#{ann.variete.name}") #{ann.variete.name}.
Done!

Resources