Slack API dealing with two API's - node.js

I am trying to call a function after getting the response from API calls. Like this
function saveScore(bot,result,message){
getFirstScore(bot,result).then(function(fscore){ //API -1
if(fscore){
getSecondScore(bot,result,null).then(function(sscore){ //API -2
if(fscore && sscore){
var finalScores = "First score is " + fscore + " :innocent:" + "\n Second score is "+ sscore +" :blush: ";
var remindAttachment = util.reminderAttachment("",finalScores);
listAllScores(bot,message,remindAttachment);
}
},function(error){
console.log('sscore error: ' + error);
});
}
},function(error){
console.log('fscore error: ' + error);
});
}
function listAllScores(bot,message,remindAttachment){
sendInstructions = function(response, convo){
convo.say(remindAttachment);
convo.say("Take it to the next level:");
convo.next();
setTimeout(function(){
listScores(bot,message);
},2000);
}
bot.startPrivateConversation(message, sendInstructions);
}
Here, I want to call listScores(bot,message); function after convo.say(remindAttachment);. But right now it is loading listScores(bot,message); first. So, I am setting timeout(not a good approach) for listScores(bot,message); to load after sometime.
Is there any better way to call listScores(bot,message); function after convo.say(remindAttachment);
Edit
function listAllScores(bot,message,remindAttachment){
sendInstructions = function(response, convo){
convo.say(remindAttachment, function(error){
console.log("error ::::::::::::::::::::",error);
if(error!=null) {
listScores(bot,message);
}
});
}
bot.startPrivateConversation(message, sendInstructions);
}

modify this convo.say() function to have callback as a function parameter and then inside that callback call "listScores(bot,message)" function.
like this
convo.say(remindAttachment, function(error) {
if(error!=null) {
listScores(bot,message)
}
})

Related

How can I unit test node.js functions with Mocha?

I am trying to test a function that looks like:
function sendVerifySms(patientId, data) {
var smsNumber = data.smsNumber;
var verifyCode = ((Math.random() * 1000000) | 0).toString();
var sql = "UPDATE [patient]";
sql += " SET phone_sms_verify_code = '" + verifyCode + "',";
// verification must take place within a one hour period
sql += " phone_sms_verify_code_expire = '" + moment.utc().add(1, 'hour').formatSqlDatetime() + "',";
sql += " phone_sms_verified = 0,"
sql += " phone_sms = '" + escapeSql(smsNumber) + "'";
sql += " WHERE id = " + escapeSql(patientId.toString());
return sqlServer.query(sql).then(function(result) {
twilioClient.sendMessage({
to: smsNumber,
from: twilioUser.verifyNumber,
body: verifyCode
}).then(function(res) {
console.log('sent verification');
return verifyCode;
}).fail(function(err) {
console.log('error sending verification');
console.log(err);
return err;
});
}).fail(function(err) {
console.log(err);
return err;
});
}
Easy enough, right? Well, first I need to decide what EXACTLY I'm testing for.
That the sql command matches the format given some data
That the twilioClient.sendMessage has been called.
Here is what I have for my test so far:
var should = require('should');
var methods;
var mockery = require('mockery');
var sinon = require('sinon');
describe('RPC Methods', function() {
before(function() {
mockery.enable();
mockery.registerMock('msnodesql', {
open: function() {
return true;
}
});
mockery.registerMock('../../db/sqlserver', {
query: function() {
return {
then: function() {
return true;
}
}
}
});
methods = require('../../../rpc/methods');
});
it('should send a verify SMS', function() {
var data = {
}
methods.sendVerifySms(1, data);
should(1).equal(1);
});
});
So now I'm a bit lost from here. I have a ton of require and since I want to isolate my individual functions for testing, I figured something like mockery would work. Where do I go from here?
If anything is unclear, please post a comment and I'll clarify.
Thanks!
With mocha tests you have an optional done callback that makes testing async functions easier, like this:
it('should send a verify SMS', function(done) {
var data = {};
var code = 1;
methods.sendVerifySms(code, data)
.then(function(actualCode) {
should(actualCode).equal(code);
done();
});
});
I would also have some feedback to offer on the async function you're testing. First I'd say you don't have to nest promise chains the way you are, and in this case its probably better that you didn't. If you simply return a promise from within a promise callback, you can chain it at the same level, like this:
return sqlServer.query(sql).then(function(result) {
return twilioClient.sendMessage({
to: smsNumber,
from: twilioUser.verifyNumber,
body: verifyCode
});
}).then(function(res) {
console.log('sent verification');
return verifyCode;
}).fail(function(err) {
console.log(err);
throw err;
});
Second, in the error handler you had before you were simply returning the err. This is probably a bad idea because it tells the consumer of your promise that everything is hunky dory and that they should proceed as such. Throwing an error on the other hand will allow that consumer to handle the error however they want in their own .fail block.

Trouble dealing with asynchronous non-blocking model

I'm having trouble with getting around asynchronous model of node, I have this function:
function getstream() {
console.log('calling testAvail, Avail value is:' + available);
testAvailability();
console.log('Available:'+available);
if (available || SelfSharing) {
// Do something
setDefaults();
return;
}
}
Which calls testAvailability() function defined as:
function testAvailability()
{
console.log('entered test');
var stat;
var socket = io.connect('http://somedomain.com');
socket.on('error', function() {
console.log('There was an error at server end please try again');
// chrome.runtime.reload();
setTimeout(chrome.runtime.reload(),3000);
//here i change options
//socket = io.connect(host, options);
});
socket.emit('available');
socket.on('available', function (status) {
console.log('got status from server which is:'+ status);
available=status;
console.log("inside the socket.on"+available);
console.log('leaving test, do you see any got status above?');
});
}
I want getstream() to continue from where it left after testAvailability() is done and available variable has it's value set.
You need to pass a callback to testAvailability and then call it inside socket's available event:
function testAvailability(callback)
{
console.log('entered test');
var stat;
var socket = io.connect('http://somedomain.com');
socket.on('error', function() {
console.log('There was an error at server end please try again');
// chrome.runtime.reload();
setTimeout(chrome.runtime.reload(),3000);
//here i change options
//socket = io.connect(host, options);
});
socket.emit('available');
socket.on('available', function (status) {
console.log('got status from server which is:'+ status);
available=status;
console.log("inside the socket.on"+available);
console.log('leaving test, do you see any got status above?');
callback(); <-- CALL YOUR CALLBACK FUNCTION HERE
});
}
Then change your getstream function so that it passes a callback to testAvailability and move the rest of the function inside that callback:
function getstream() {
console.log('calling testAvail, Avail value is:' + available);
testAvailability(function() {
console.log('Available:'+available);
if (available || SelfSharing) {
// Do something
setDefaults();
}
});
}
A couple of things to note:
getstream is now asynchronous. If something else is waiting for it to complete, you'll need to change it so that it takes a callback function as well.
I see that you're doing some sort of retry in socket's error event. That might be ok in this case, it depends on your app but, typically, you'll want to pass the error back as the first parameter of the callback when an error occurs.
Here we go:
function getstream() {
console.log('calling testAvail, Avail value is:' + available);
testAvailability(function(available){
console.log('Available:'+available);
if (available || SelfSharing) {
// Do something
setDefaults();
return;
}
});
}
function testAvailability(callback) {
console.log('entered test');
var stat;
var socket = io.connect('http://somedomain.com');
socket.on('error', function() {
console.log('There was an error at server end please try again');
// chrome.runtime.reload();
setTimeout(chrome.runtime.reload(),3000);
//here i change options
//socket = io.connect(host, options);
callback(false);
});
socket.emit('available');
socket.on('available', function (status) {
console.log('got status from server which is:'+ status);
console.log('leaving test, do you see any got status above?');
callback(true);
});
}

fromNodeCallback callback methods order of defintion

Im learning bacon.js
i wrote test script like that.
var bacon = require('../nodejs/node_modules/baconjs').Bacon;
function TestClass(URL,port,username,password)
{
this.funcCheck = function( data , rescallback)
{
console.log(" data: " + data);
if(data.length > 4)
{
rescallback(null,data.substring(0, 2));
}
else
{
console.log("Calling callback with error data: " + "error");
rescallback("Too short",null);
}
}
}
var tclass = new TestClass();
var names = ['Geroge','Valentine', 'Oz','Nickolas'];
var results = [];
var read = bacon.fromNodeCallback( tclass.funcCheck, bacon.fromArray(names) )
stream.onValue(function(value)
{
console.log(" onValue " + value);
results.push( value);
});
stream.onError( function(error)
{
console.log(" OnError " + error);
// results.push( err);
});
console.log(" results " + results);
The problem is that onError never get called, despite the fact that "Oz" is less than 4 characters and i know that rescallback get called with 1 parameter that is not null.
I can see log printout.
The other thing is that if i change defition of onError and put it before onValue, onError will be called exactly 1 time, and onValue will never be called.
Im sure im missing something very basic but i dont know what exactly.
What im doing wrong?
Thanks

Nodejs, How to copy several file in nodejs without crash

I tried to copy several file with node js.
Here is my an example of what i'm trying to do :
var request = require('request');
va photos [{ 'url': 'http://xxxx.com/im1', 'name' : 'name1' }, { 'url': 'http://xxxx.com/im12', 'name' : 'name2' },
for (var i = 0; i < photos.length; i++) {
request(photos[i].source).pipe(fs.createWriteStream(photos[i].name));
}
After maybe 1000 call i have a socket hang out error.
Following #Timothy Strimple advice i decided to use async module.
My code is now something like this :
async.whilst(function () { return !stop; },
function (callback) {
console.log("get next 20 image");
JM.api('/' + album.id + '/photos', { after: next }, function (resf) {
if (!resf || resf.error) {
console.log(!resf ? 'error occurred' : resf.error);
}
console.log("albums" + album.id + " " + resf.data.length + " dir" + dir);
async.eachSeries(resf.data, function (photo, done) {
request(photo.source).pipe(fs.createWriteStream(dir + "/" +photo.name));
console.log("copy of image " + img_basename);
}, function (err) {
if (err) {
console.log('An images failed to copy');
} else {
console.log('All 20 image have been copied successfully');
}
if (resf.paging && resf.paging.cursors) {
console.log("suite de l'album à venir");
next = resf.paging.cursors.after;
setTimeout(function () { callback(); }, 5000);
}
else {
console.log("Fin de l'album");
stop = true;
setTimeout(function () { callback(); }, 5000);
}
});
});
},
function (err) {
if (err) {
console.log('An images failed to process');
albumcallback();
} else {
console.log('All images in this group have been processed successfully');
albumcallback();
}
}
);// end while
I still having a crash after maybe 1 00 file copied. I'm sure that async.whilst and async.eachSeries are weel because my log show that each call is on series. But i have a crash. I temporary solved the proble by ading a wait after each copy like this :
request(photo.source).pipe(fs.createWriteStream(dir + "/" + img_basename));
console.log("copy of image " + img_basename);
setTimeout(function () { done(); }, 5000);
Is it a limit of request module ? How to change this fea line to make sure that each connection are closed before continung the program ?
You probably need to move to an asynchronous loop. Something like eachLimit from the async module would probably be ideal.
async.eachLimit(photos, 10, function(photo, done) {
var r = request(photos[i].source).pipe(fs.createWriteStream(photos[i].name));
r.on('finish', done);
}, function(err) {
// All images done or there was an error
});
Now it will process all the items in your photos list, but it will only process 10 of them concurrently. This will prevent it from spinning up hundreds or thousands of concurrent outgoing connections.
The request call and pipe call are asyncrhon. So i have to rewrite this line : request(photos[i].source).pipe(fs.createWriteStream(photos[i].name));
See here :
Downloading N number of remote files using Node.js synchronously

How to send mongodb data async from inner functions to outside callback function from a for loop?

NEW POST:
Here is the sample of the working async code without a db.
The problem is, if i replace the vars (data1_nodb,...) with the db.collection.find();
function, all needed db vars received at the end and the for() loop ends not
correct. I hope that explains my problem a bit better. OA
var calc = new Array();
function mach1(callback){
error_buy = 0;
// some vars
for(var x_c99 = 0; x_c99 < array_temp_check0.length;x_c99++){
// some vars
calc[x_c99] = new Array();
calc[x_c99][0]= new Array();
calc[x_c99][0][0] = "dummy1";
calc[x_c99][0][1] = "dummy2";
calc[x_c99][0][2] = "dummy3";
calc[x_c99][0][3] = "dummy4";
calc[x_c99][0][4] = "dummy5";
function start_query(callback) {
data1_nodb = "data1";
data2_nodb = "data2";
data3_nodb = "data3";
data4_nodb = "data4";
calc[x_c99][0][0] = data1_nodb;
calc[x_c99][0][1] = data2_nodb;
calc[x_c99][0][2] = data3_nodb;
callback(data1_nodb,data2_nodb,etc..);
}
start_query(function() {
console.log("start_query OK!");
function start_query2(callback) {
data4_nodb = "data5";
data5_nodb = "data6";
data6_nodb = "data7";
calc[x_c99][0][3] = data4_nodb;
calc[x_c99][0][4] = data5_nodb;
callback(data5_nodb,data6_nodb,etc..);
}
start_query2(function() {
console.log("start_query2 OK!");
function start_query3(callback) {
for(...){
// do something
}
callback(vars...);
}
start_query3(function() {
console.log("start_query3 OK!");
});
});
});
}
callback(calc);
};
function mach2(callback){
mach1(function() {
console.log("mach1 OK!");
for(...){
// do something
}
});
callback(calc,error_buy);
};
mach2(function() {
console.log("mach2 OK 2!");
});
OLD POST:
i try to read data from the mongodb and send them back with a callback to the next
function, that needs the infos from the db to proceed.
Without the mongodb read functions it works perfect but now i dont know how
i can send the db vars out of the two inner functions to the first callback function.
Hope someone can help me...
Thanks
var error = 0; var var1 = "yessir";
function start_query(callback) {
var db_name = "db1";
db[db_name].find({name:var1},{data1:1, data2:1, data3:1, data4:1}, function(err, data_catch,callback) {
if( err || !data_catch ) {
console.log("Problem finding data_catch:" + err);
} else {
data_catch.forEach( function(data_catch_finder,callback) {
data1_db = data_catch_finder.data1;
data2_db = data_catch_finder.data2;
data3_db = data_catch_finder.data3;
data4_db = data_catch_finder.data4;
if(data1_db == "" || data2_db == "" || data3_db == "" || data4_db == ""){error = 1; console.log("Error: data_catch_finder");}
callback(data1_db, data2_db, data3_db, data4_db, error);
});
}
});
callback(data1, data2, data3, data4, error);
}
//########################################################################
start_query(function() {
function start_query2(callback) {
console.log("DATA1 from callback:" + data1_db);
console.log("DATA2 from callback:" + data2_db);
console.log("DATA3 from callback:" + data3_db);
console.log("DATA4 from callback:" + data4_db);
var var_no_db = "testing";
//do something else and callback
callback(var_no_db);
}
start_query2(function() {
console.log("Var from callback start_query2:" + var_no_db);
console.log("The end");
});
});
your callback signature are issuing callback as a parameter.
As far as I can understand your code, you need to keep reference of the first callback, the one you receive here: function start_query(callback).
In every callback function you made the mistake to bind the variable name callback to the parameter from the mongo driver (a simple undefined i think).
You can fix it removing every reference of callback from the signature of your inner functions.
a simple example:
function async (cb) {
// params: Error, data
cb(null, 'moo');
}
function foo(callback) {
async(function(err, data, callback){
console.log(callback); // undefined
});
console.log(callback); // Moo
}
foo('Moo');
Take a look at Eloquent Javascript to better understand the JS context switching;
edit
The only way to wait the results of an async function is recall the first callback inside the last nested callback.
function ugly_nested (callback) {
dbquery('...', function(err, data_01) {
if (!! err) return callback(err);
dbquery('...', function(err, data_02) {
if (!! err) return callback(err);
dbquery('...', function(err, data_03) {
if (!! err) return callback(err);
callback(null, data_01, data_02, data_03);
});
});
});
}
ugly_nested(function(err, data01, data02, data03) {
if (!! err) throw err;
manage_data(data01, data02, data03);
});
The FOR loop is synchronous, but, the database calls are asynchronous, so, the for loop will end before the database returns his results. If you really need that for loop you can try out one of the nice flow control libraries out there

Resources