Convert a function with callback in a promise (Node.js) (OpenTok) [duplicate] - javascript

This question already has answers here:
How do I convert an existing callback API to promises?
(24 answers)
Closed 6 years ago.
MY ACTUAL CODE (THAT WORKS!)
I've created a function with callback to create sessions and generate tokens for OpenTok, that exports itself to application.
The function
//Dependencies
var opentok = require('./ot').opentok;
var apiKey = require('./ot').apiKey;
var apiSecret = require('./ot').apiSecret;
//Define variables
var sessionId;
var token;
//Define create newSession function
var newSession = function(callbackS){
//Create Session (That allows to OpenTok)
opentok.createSession({mediaMode:"relayed"}, function(err, session){
if(err) throw err;
else {
//Define session object
var objSession = {};
//Obtain sessionId
objSession.sessionId = session.sessionId;
//Call generate token function
newTok(objSession,callbackS);
}
});
}
//Define generate token function
var newTok = function(obj, fn){
//Generate token (that allows to OpenTok)
token = opentok.generateToken(obj.sessionId);
//Store object (obj.tokenId) in token variable
obj.tokenId = token;
//Define "obj" in function context
fn(obj);
}
//Export new Session with sessionId and token
module.exports.credentials = newSession;
The APP
// Dependencies
var express = require('express');
var server_port = process.env.PORT || 3000;
var apiKey = require('./ot').apiKey; //Obtain default apiKey
var credentials = require('./credentials').credentials(fun);
//function that was export from "credentials" (the function)
function fun(obj) {
//Define app
var app = express();
//Use "public" static folder
app.use(express.static(__dirname + '/public'));
//Initialize the app
init();
//Routing
app.get('/', function(req, res) {
//Rendering variables in views
res.render('index.ejs', {
apiKey: apiKey,
sessionId: obj.sessionId,
token: obj.tokenId
});
});
//Define Init
function init() {
app.listen(server_port, function() {
console.log('The app is running in localhost:' + server_port);
});
}
}
THAT I WANT:
How I could convert my function that creates sessions and generates tokens in a promise that I can use into my app?
UPDATE (08/01/2016) (14:53 VET)
I've exported the function module in my app as follow:
// Dependencies
var express = require('express');
var server_port = process.env.PORT || 3000;
var apiKey = require('./ot').apiKey; //Obtain default apiKey
var credentialsPromise = require('./credentialsPromise').credentialsPromise(); //Obtain the promise
console.log(credentialsPromise);
And throw in console:
Promise { <pending> }
How I should use my promise in my app?

The minimal approach is as follows (see *** comments):
var newSession = function(){
// *** Return a promise
return new Promsie(function(resolve, reject) {
opentok.createSession({mediaMode:"relayed"}, function(err, session){
// *** Reject on error
if (err) {
reject(err);
} else {
var objSession = {};
objSession.sessionId = session.sessionId;
// *** Have newTok call `resolve` with the object when done
newTok(objSession, resolve);
}
});
});
};
Note that I didn't promise-ify newTok, though we could. It's not clear why newTok accepts a callback when nothing in it is asynchronous and it's a private function.
Using it looks like this:
newSession(/*...parameters...*/).then(
function(result) {
// All is good, use result
},
function(err) {
// Error occurred, see `err`
}
);

Related

Why is this an unreachable code?

I'm calling the function getKeywords from another function and got an Unrecheable code detected section and don't understand why. Any help?
var env = require('dotenv').config();
var request = require('request')
var getKeywords = function(){
request.get('URI', //URI IS CORRECT IN MY CODE
function(err, httpResponse, body){
if(err){ //UNREACHABLE CODE DETECTED
console.error("request.post Error:", err);
return false;
} //UNREACHABLE CODE DETECTED
else{
console.log('Im here');
return JSON.parse(httpResponse.body).keywords;
}
});
}
module.export = getKeywords;
Here is the calling code.
var getKeywords = require('./getKeywords.js');
var keywords = new getKeywords();
var env = require('dotenv').config();
var difflib = require('difflib');
var postMention = require('./postMention.js');
var detection = function(obj, i){
var keyword = keywords[i];
var mentionObject = {
//some json
//postMention(mentionObject);
}
}
module.exports = detection;
Some tools have the ability to analyze every call to your function. It may be possible that all the places in your code that call the function you never set err parameter to true.

getting a value from redis using node js

What am I doing wrong in the code below? The left_label and right_label variables seem to always be "true", when I know I have them in the Redis set to some string. I'm assuming it's because the client.get function is successful and returns true, but how do I get it to return the actual value?
var http = require('http');
var redis = require('redis');
var client = redis.createClient(6379, 127.0.0.1);
var server = http.createServer(function (request, response) {
var left_label = client.get('left', function(err, reply) {
console.log(reply);
return reply;
});
var right_label = client.get('right', function(err, reply) {
console.log(reply);
return reply;
});
response.writeHead(200, {"Content-Type": "text/html"});
var swig = require('swig');
var html = swig.renderFile('/var/www/nodejs/index.html', {
left: left_label,
right: right_label
});
response.end(html);
});
server.listen(8000);
console.log("Server running at http://127.0.0.1:8000/");
The get call is asynchronous and must be handled that way.
A suggestion would be to combine it with a promise library such as bluebird as suggested in the NPM documentation for the redis module.
That way, we can promisify the redis module and use it in a more simple way.
var redis = require('redis');
bluebird.promisifyAll(redis.RedisClient.prototype);
and use the new async version of the get function, as below.
function getLabelValues(){
var left_promise = client.getAsync("left").then(function(reply) {
return reply;
});
var right_promise = client.getAsync("right").then(function(reply) {
return reply;
});
return Promise.all([left_label, right_label]);
}
getLabelValues().then(function(results){
//This is run when the promises are resolved
//access the return data like below
var left_label = results[0];
var right_label = results[1];
});

Node JS Controller - invoking a function that has a callback

My controller is a soap client as shown below
var _ = require('lodash'),
memoize = require('memoize'),
soap = require('soap'),
http = require('http');
var wsdlUrl = 'http://www.proxixnetwork.com/gsert/PxPointGeocode.asmx?WSDL';
var geocode = function(req,res){
var sessionId = null;
soap.createClient(wsdlUrl, function(err,client){
var args = {"username":'user123', "password":'password123'};
client.PxPointGeocode.PxPointGeocodeSoap.Authenticate(args,function(err,result){
res.jsonp(result.AuthenticateResult.SessionID);
})
});
}
exports.authenticate = geocode;
This soap service provides a session id that will be used in subsequent requests. Hence, I wanted to use 'memoize' to cache the method.
I defined a method that wraps around the soap call and 'memoize'ing it but the problem is that the call to soapClient is not happening.
I do not know how to make the call from router wait for the soap call
Note: Also tried async library's waterfall but did not work.
var _ = require('lodash'),
memoize = require('memoize'),
soap = require('soap'),
http = require('http'),
wsdlUrl = 'http://www.proxixnetwork.com/gsert/PxPointGeocode.asmx?WSDL';
var getSession = function () {
var args = {"username": 'user123', "password": 'password123'};
var sessionId = null;
soap.createClient(wsdlUrl, function (err, client) {
console.log('Inside proxix client'); //not printing
client.PxPointGeocode.PxPointGeocodeSoap.Authenticate(args, function (err, result) {
sessionId= result.AuthenticateResult.SessionID;
//if I use res.jsonp() - the call could be made
})
});
return sessionId;
};
var cached = memoize(getSession);
var geocode = function (req, res) {
var sesssionObj = cached();
res.jsonp(sessionObj);
}
exports.authenticate = geocode;
The two issues I'm seeing are :
memoize is a caching mechanism but is in no way going to change the ansynchronous nature of your function. Returning sessionId will not work because it is not set before it gets to that line. You need to use a callback.
You have not specified which arguments you want memoize to use for the caching, nor where you are getting those values. I'm going to assume for this example that it's username, password and wsdlUrl. and that they are set directly in req.
.
var _ = require('lodash'),
memoize = require('memoize'),
soap = require('soap'),
http = require('http');
var getSessionId = function(username,password,wsdlUrl,callback){
soap.createClient(wsdlUrl, function(err,client){
var args = {"username":username, "password":password};
client.PxPointGeocode.PxPointGeocodeSoap.Authenticate(args,function(err,result){
if(err){
return callback(err);
}
callback(null,result.AuthenticateResult.SessionID);
})
});
});
var getSessionIdCached = memoize(getSessionId,{async:true});
var geocode = function(req,res){
getSessionIdCached(req.username,req.password,req.wsdlUrl,function(err,sessionId){
if(err){
//do some error handling, and probably return
}
res.jsonp(sessionId);
});
});
exports.authenticate = geocode;

Creating a javascript object and binding this

I'm trying to build my first node app. My app.js file is shown below. I want to access this from aother module by doing 'app = require('app')'. I then want to access app.app, app.dbConn and app.models
The problem is that when I require this module, app.models is not present on the resulting object.
var express = require('express');
var path = require('path');
var orm = require('orm');
var settings = require('./config/settings');
var mainRouter = require('./config/routes');
var environment = require('./config/environment');
var db = require('./config/db');
var auth = require('./modules/auth');
module.exports = new function(){
this.app = express();
// middlewares must be added in order - start with the basics
environment(this.app);
if (process.env.TESTING) { dbSettings = settings.dbTesting; }
else { dbSettings = settings.db; }
// add models to the request early in the middleware chain
this.dbConn = orm.connect(dbSettings, function(err){
if (err) return console.error('DB Connection error: ' + err);
else{
this.models = db.init(this.dbConn);
this.app.use(function(req,res,next){
req.models = this.models;
next();
});
passport = auth.init(this.models);
authRouter = auth.router(passport)
this.app.use('/users', authRouter);
this.app.use(mainRouter);
}
}.bind(this));
this.app.listen(settings.port);
console.log('Server started... listening on port ' + settings.port)
}
The only way to implement what I wanted was with a function that takes a callback, in the end I rewrote my code thus:
var express = require('express');
var path = require('path');
var orm = require('orm');
var settings = require('./config/settings');
var mainRouter = require('./config/routes');
var environment = require('./config/environment');
var db = require('./config/db');
var auth = require('./modules/auth');
var app;
module.exports = function(cb){
app = express();
// middlewares must be added in order - start with the basics
environment(app);
if (process.env.TESTING) { dbSettings = settings.dbTesting; }
else { dbSettings = settings.db; }
// add models to the request early in the middleware chain
dbConn = orm.connect(dbSettings, function(err){
if (err) return console.error('DB Connection error: ' + err);
else{
models = db.init(dbConn);
app.use(function(req,res,next){
req.models = models;
next();
});
passport = auth.init(this.models);
authRouter = auth.router(passport)
app.use('/users', authRouter);
app.use(mainRouter);
cb({
dbConn: dbConn,
app: app,
models: models
});
}
});
}
if (!process.env.TESTING) {
module.exports(function(server){
server.app.listen(settings.port);
console.log('Server started... listening on port ' + settings.port)
});
}
app.models is defined only once database connection is completed: you cannot use it right away after requiring the module. You should provide an entry point that accepts a function to call once the connection is ready and call this function inside the orm.connect callback.
Even the "server started" message is a bit misleading as it's shown before the server can actually do anything because the function passed to orm.connect has not been called yet.
app.models is never defined so it is never available.
Instead, try
app.set('models', db.init(this.dbConn);

How to execute the function return the value to called function across node js files

I have 3 node js files :
mysqlconnection.js to store the database connection properties:
var mysql = require('mysql');
var cjson = require('cjson');
var yaml_config = require('node-yaml-config');
// project files
var config = yaml_config.load(__dirname + '/billingv2.yaml');
exports.execute = function(callback){
var connection = mysql.createConnection(
{
host : config.host,
user : config.user,
password : config.password,
database : config.database,
}
);
connection.connect();
return callback(null,connection);
}
subscriptionRestService.js to handle the REST api calls:
var express = require('express');
var app = express();
app.use(express.bodyParser());
var fs = require('fs');
// Project files
var mysql = require('./mysqlRestService.js');
// Get Resource Subscription data by Resourceuri
app.post('/pricingdetails', function(req, res) {
var workload = req.body;
if(workload.elements && workload.elements.length > 0)
{
var arr = [];
for(var index in workload.elements)
{
arr[index] = workload.elements[index].uri;
}
var resourceIdentifiers = arr.join(',');
}
console.log(resourceIdentifiers);
mysql.getPricingDetail(function(resourceIdentifiers,callback){
});
});
mysqlRestService.js to handle mysql queries/stored procedures:
// packages
var mysql = require('mysql');
var cjson = require('cjson');
var fs = require('fs');
var yaml_config = require('node-yaml-config');
// project files
var dbconnection = require('./mysqlconnection');
exports.getPricingDetail = function (resourceIdentifiers,callback){
console.log('entered into mysql function');
console.log(resourceIdentifiers);
var pricingDetail = {};
dbconnection.execute(function(err,response){
if(err){
throw err;
}
else
{
var selectqueryString = "call SP_ExposePricingDetailforUI('" + resourceIdentifiers + "')";
response.query(selectqueryString, function(err,pricingDetail){
if(err) {
throw err;
}
else
{
console.log(pricingDetail);
pricingDetail = pricingDetail;
}
});
}
});
//console.log('printing pricing details');
//console.log(pricingDetail);
};
problems faced
Unable to send the variable resourceIdentifiers from subscriptionRestService to mysqlRestService.js
Unable to return the pricingdetail from mysqlRestService.js to calling function in subscriptionRestService.
Any guidance greatly appreciated.
Unable to send the variable resourceIdentifiers from subscriptionRestService to mysqlRestService.js
Well, you didn't send it. It currently is a parameter of your callback function in the invocation, not an argument for the parameter of getPricingDetails. Use
mysql.getPricingDetail(resourceIdentifiers, function callback(result){
// use result here
});
Unable to return the pricingdetail from mysqlRestService.js to calling function in subscriptionRestService.
I've got no idea what pricingDetail = pricingDetail; was supposed to do. You have to call (invoke) back the callback here! Use
callback(pricingDetail);

Categories

Resources