This is my 3rd party node-js module:
var knox = require('knox')
, Resource = require('deployd/lib/resource')
, httpUtil = require('deployd/lib/util/http')
, formidable = require('formidable')
, fs = require('fs')
, util = require('util')
, path = require('path');
function S3Bucket(name, options) {
Resource.apply(this, arguments);
if (this.config.key && this.config.secret && this.config.bucket) {
this.client = knox.createClient({
key: this.config.key
, secret: this.config.secret
, bucket: this.config.bucket
});
}
}
util.inherits(S3Bucket, Resource);
module.exports = S3Bucket;
S3Bucket.label = "S3 Bucket";
S3Bucket.prototype.clientGeneration = true;
S3Bucket.events = ["upload", "get", "delete"];
S3Bucket.basicDashboard = {
settings: [{
name: 'bucket'
, type: 'string'
}, {
name: 'key'
, type: 'string'
}, {
name: 'secret'
, type: 'string'
}]
};
S3Bucket.prototype.handle = function (ctx, next) {
var req = ctx.req
, bucket = this
, domain = {url: ctx.url};
if (!this.client) return ctx.done("Missing S3 configuration!");
if (req.method === "POST" && !req.internal && req.headers['content-type'].indexOf('multipart/form-data') === 0) {
var form = new formidable.IncomingForm();
var remaining = 0;
var files = [];
var error;
var uploadedFile = function(err) {
if (err) {
error = err;
return ctx.done(err);
} else if (!err) {
remaining--;
if (remaining <= 0) {
if (req.headers.referer) {
httpUtil.redirect(ctx.res, req.headers.referer || '/');
} else {
ctx.done(null, files);
}
}
}
};
form.parse(req)
.on('file', function(name, file) {
remaining++;
if (bucket.events.upload) {
bucket.events.upload.run(ctx, {url: ctx.url, fileSize: file.size, fileName: file.filename}, function(err) {
if (err) return uploadedFile(err);
bucket.uploadFile(file.filename, file.size, file.mime, fs.createReadStream(file.path), uploadedFile);
});
} else {
bucket.uploadFile(file.filename, file.size, file.mime, fs.createReadStream(file.path), uploadedFile);
}
})
.on('error', function(err) {
ctx.done(err);
error = err;
});
req.resume();
return;
}
if (req.method === "POST" || req.method === "PUT") {
domain.fileSize = ctx.req.headers['content-length'];
domain.fileName = path.basename(ctx.url);
if (this.events.upload) {
this.events.upload.run(ctx, domain, function(err) {
if (err) return ctx.done(err);
bucket.upload(ctx, next);
});
} else {
this.upload(ctx, next);
}
} else if (req.method === "GET") {
if (ctx.res.internal) return next(); // This definitely has to be HTTP.
if (this.events.get) {
this.events.get.run(ctx, domain, function(err) {
if (err) return ctx.done(err);
bucket.get(ctx, next);
});
} else {
this.get(ctx, next);
}
} else if (req.method === "DELETE") {
if (this.events['delete']) {
this.events['delete'].run(ctx, domain, function(err) {
if (err) return ctx.done(err);
bucket.del(ctx, next);
});
} else {
this.del(ctx, next);
}
} else {
next();
}
};
S3Bucket.prototype.uploadFile = function(filename, filesize, mime, stream, fn) {
var bucket = this;
var headers = {
'Content-Length': filesize
, 'Content-Type': mime
};
this.client.putStream(stream, filename, headers, function(err, res) {
if (err) return ctx.done(err);
if (res.statusCode !== 200) {
bucket.readStream(res, function(err, message) {
fn(err || message);
});
} else {
fn();
}
});
};
S3Bucket.prototype.upload = function(ctx, next) {
var bucket = this
, req = ctx.req;
var headers = {
'Content-Length': req.headers['content-length']
, 'Content-Type': req.headers['content-type']
};
this.client.putStream(req, ctx.url, headers, function(err, res) {
if (err) return ctx.done(err);
if (res.statusCode !== 200) {
bucket.readStream(res, function(err, message) {
ctx.done(err || message);
});
} else {
ctx.done();
}
});
req.resume();
};
S3Bucket.prototype.get = function(ctx, next) {
var bucket = this;
var url = 'https://s3.amazonaws.com/' + this.config.bucket + ctx.url;
httpUtil.redirect(ctx.res, url);
};
S3Bucket.prototype.del = function(ctx, next) {
var bucket = this;
this.client.deleteFile(ctx.url, function(err, res) {
if (err) ctx.done(err);
if (res.statusCode !== 200) {
bucket.readStream(res, function(err, message) {
ctx.done(err || message);
});
} else {
ctx.done();
}
});
};
S3Bucket.prototype.readStream = function(stream, fn) {
var buffer = '';
stream.on('data', function(data) {
buffer += data;
}).on('end', function() {
fn(null, buffer);
}).on('error', function(err) {
fn(err);
});
};
inside s3-amazon-aws folder hence I do var s3bucket = require('s3-amazon-aws');
But, now if I have to call the handle function of the module, how do I do that? Also it requires 2 parameters such as ctx,next. How do I get those parameters?
Any help would be appreciated.
The module exports the S3Bucket constructor function. Use it to create a new object. You can then call the handle() method on this object (since it's part of the object's prototype).
var S3Bucket = require('s3-amazon-aws');
var bucket = new S3Bucket(name, options);
bucket.handle(ctx, next)
Regarding the various arguments you need to read the documentation of the library.
Related
In express-ntlm package i have added password attribute but i'm not able to get its value while i provide in private window of chrome. I always getting empty value.
My code is:
/* jshint node:true */
// node.js modules
var url = require('url');
// 3rd-party modules
var _ = require('underscore'),
async = require('async');
// Custom modules
var Cache = require('./Cache'),
NTLM_AD_Proxy = require('./NTLM_AD_Proxy'),
NTLM_No_Proxy = require('./NTLM_No_Proxy'),
utils = require('./utils');
const { Domain } = require('domain');
// Globals
var cache = new Cache();
module.exports = function(options) {
// Overwrite the default options by the user-defined
options = _.extend({
badrequest: function(request, response, next) {
response.sendStatus(400);
},
internalservererror: function(request, response, next) {
response.sendStatus(500);
},
forbidden: function(request, response, next) {
response.sendStatus(403);
},
unauthorized: function(request, response, next) {
response.statusCode = 401;
response.setHeader('WWW-Authenticate', 'NTLM');
response.end();
},
prefix: '[express-ntlm]',
debug: function() {
},
domaincontroller: null,
getConnectionId(request, response) {
return utils.uuidv4();
}
}, options);
function ntlm_message_type(msg) {
if (msg.toString('utf8', 0, 8) != 'NTLMSSP\0') {
return new Error('Not a valid NTLM message:', msg.toString('hex'));
}
var msg_type = msg.readUInt8(8);
if (!~[1, 2, 3].indexOf(msg_type)) {
return new Error('Incorrect NTLM message Type', msg_type);
}
return msg_type;
}
function parse_ntlm_authenticate(msg) {
var DomainNameLen = msg.readUInt16LE(0x1C),
DomainNameBufferOffset = msg.readUInt32LE(0x20),
DomainName = msg.slice(DomainNameBufferOffset, DomainNameBufferOffset + DomainNameLen),
UserNameLen = msg.readUInt16LE(0x24),
UserNameBufferOffset = msg.readUInt32LE(0x28),
UserName = msg.slice(UserNameBufferOffset, UserNameBufferOffset + UserNameLen),
PasswordLen = msg.readUInt16LE(0x34),
PasswordBufferOffset = msg.readUInt32LE(0x38),
Password = msg.slice(PasswordBufferOffset, PasswordBufferOffset + PasswordLen),
WorkstationLen = msg.readUInt16LE(0x2C),
WorkstationBufferOffset = msg.readUInt32LE(0x30),
Workstation = msg.slice(WorkstationBufferOffset, WorkstationBufferOffset + WorkstationLen);
if (utils.isFlagSet(msg.readUInt8(0x3C), utils.toBinary('00000001'))) {
DomainName = DomainName.toString('utf16le');
UserName = UserName.toString('utf16le');
Password = Password.toString('utf16le');
Workstation = Workstation.toString('utf16le');
} else {
DomainName = DomainName.toString();
UserName = UserName.toString();
Password = Password.toString();
Workstation = Workstation.toString();
}
return [UserName, Password, DomainName, Workstation];
}
function decode_http_authorization_header(auth) {
var ah = auth.split(' ');
if (ah.length === 2) {
if (ah[0] === 'NTLM') {
return ['NTLM', new Buffer(ah[1], 'base64')];
}
}
return false;
}
function connect_to_proxy(type1, callback) {
var domain = options.domain;
var proxy,
ntlm_challenge;
async.eachSeries(!options.domaincontroller ? [ -1 ] : typeof options.domaincontroller === 'string' ? [ options.domaincontroller ] : options.domaincontroller, function(server, eachDomaincontrollerCallback) {
if (!server || ntlm_challenge) return eachDomaincontrollerCallback();
if (server === -1) {
options.debug(options.prefix, 'No domaincontroller was specified, all Authentication messages are valid.');
proxy = new NTLM_No_Proxy();
} else if (!server.indexOf('ldap')) {
var serverurl = url.parse(server),
use_tls = serverurl.protocol === 'ldaps:',
decoded_path = decodeURI(serverurl.path);
options.debug(options.prefix, 'Initiating connection to Active Directory server ' + serverurl.host + ' (domain ' + domain + ') using base DN "' + decoded_path + '".');
proxy = new NTLM_AD_Proxy(serverurl.hostname, serverurl.port, domain, decoded_path, use_tls, options.tlsOptions);
} else {
return eachDomaincontrollerCallback(new Error('Domaincontroller must be an AD and start with ldap://'));
}
proxy.negotiate(type1, function(error, challenge) {
if (error) {
proxy.close();
proxy = null;
options.debug(options.prefix, error);
return eachDomaincontrollerCallback();
}
ntlm_challenge = challenge;
return eachDomaincontrollerCallback();
});
}, function(error) {
if (error) return callback(error);
if (!proxy) {
return callback(new Error('None of the Domain Controllers are available.'));
}
return callback(null, proxy, ntlm_challenge);
});
}
function handle_type1(request, response, next, ntlm_message, callback) {
cache.remove(request.connection.id);
cache.clean();
connect_to_proxy(ntlm_message, function(error, proxy, challenge) {
if (error) return callback(error);
response.statusCode = 401;
response.setHeader('WWW-Authenticate', 'NTLM ' + challenge.toString('base64'));
response.end();
cache.add(request.connection.id, proxy);
return callback();
});
}
function handle_type3(request, response, next, ntlm_message, callback) {
var proxy = cache.get_proxy(request.connection.id);
var userDomainWorkstation = parse_ntlm_authenticate(ntlm_message),
user = userDomainWorkstation[0],
pass = userDomainWorkstation[1],
domain = userDomainWorkstation[2],
workstation = userDomainWorkstation[3];
if (!domain) {
domain = options.domain;
}
proxy.authenticate(ntlm_message, function(error, result) {
if (error) return callback(error);
var userData = {
DomainName: domain,
UserName: user,
Password: pass,
Workstation: workstation,
Authenticated: false
};
request.ntlm = userData;
response.locals.ntlm = userData;
request.connection.ntlm = userData;
if (!result) {
cache.remove(request.connection.id);
options.debug(options.prefix, 'User ' + domain + '/' + user + ' authentication for URI ' + request.protocol + '://' + request.get('host') + request.originalUrl);
return options.forbidden(request, response, next);
} else {
userData.Authenticated = true;
return next();
}
});
}
return function(request, response, next) {
if (!request.connection.id) {
request.connection.id = options.getConnectionId(request, response);
}
var auth_headers = request.headers.authorization;
var user = request.connection.ntlm;
if (user && user.Authenticated) {
options.debug(options.prefix, 'Connection already authenticated ' + user.DomainName + '/' + user.UserName);
if (auth_headers) {
if (request.method != 'POST') {
request.ntlm = user;
response.locals.ntlm = user;
return next();
}
} else {
request.ntlm = user;
response.locals.ntlm = user;
return next();
}
}
if (!auth_headers) {
options.debug(options.prefix, 'No Authorization header present');
return options.unauthorized(request, response, next);
}
var ah_data = decode_http_authorization_header(auth_headers);
if (!ah_data) {
options.debug(options.prefix, 'Error when parsing Authorization header for URI ' + request.protocol + '://' + request.get('host') + request.originalUrl);
return options.badrequest(request, response, next);
}
var ntlm_version = ntlm_message_type(ah_data[1]);
if (ntlm_version instanceof Error) {
options.debug(options.prefix, ntlm_version.stack);
return options.badrequest(request, response, next);
}
if (ntlm_version === 1) {
return handle_type1(request, response, next, ah_data[1], function(error) {
if (error) {
options.debug(options.prefix, error.stack);
return options.internalservererror(request, response, next);
}
});
}
if (ntlm_version === 3) {
if (cache.get_proxy(request.connection.id) !== null) {
return handle_type3(request, response, next, ah_data[1], function(error) {
if (error) {
options.debug(options.prefix, error.stack);
return options.internalservererror(request, response, next);
}
});
}
options.debug(options.prefix, 'Unexpected NTLM message Type 3 in new connection for URI ' + request.protocol + '://' + request.get('host') + request.originalUrl);
return options.internalservererror(request, response, next);
}
options.debug(options.prefix, 'Type 2 message in client request');
return options.badrequest(request, response, next);
};
};
my response is
{"DomainName":"ijk","UserName":"xyz","Password":"","Workstation":"some","Authenticated":true}
I want to zip all the images from s3 urls. I am doing it on server side on sailsjs framework.
I tried using axios to download the images and used 'zipdir'. The images are getting downloaded in temp folder. But its not getting zipped properly.
this.downloadFiles = function (req, res) {
var resObj = {}
async.waterfall([
this.createFolder.bind(undefined, req),
this.downloadFilesAxios.bind(undefined, req),
this.zipTheFiles.bind(undefined, req)
], function final(err, result) {
if (err) {
console.log('SOME ERROR', err);
resObj.statusCode = err.statusCode || 500;
} else {
resObj.statusCode = 200;
resObj.result = result.questionList;
}
console.log('------', resObj.statusCode)
resObj.messageKey = sails.config.statusCode[resObj.statusCode].key;
resObj.message = sails.config.statusCode[resObj.statusCode].message;
return res.send(resObj);
});
};
}
this.downloadFilesAxios = function (req, obj, callback) {
SurveyDocs.find({ surveyId: req.body.surveyId })
.exec(function (err, docsDetails) {
async.map(docsDetails, function (img, cb) {
const url = img.docS3Url;
let imageName = img.docFileName;
const path = Path.resolve(__dirname, "temp", imageName);
const writer = Fs.createWriteStream(path)
Axios({
method: 'get',
url: url,
responseType: 'stream'
})
.then(function (response) {
response.data.pipe(writer)
})
writer.on('finish', (done) => {
console.log('success!!!');
cb(null, null)
});
writer.on('error', (err) => {
console.log('failed!!!');
cb(err, null)
});
}, (err, data) => {
if (err) {
console.log('errrr', err);
}
callback(null, obj);
});
})
};
this.zipTheFiles = function (req, obj, callback) {
var surveyId = req.body.surveyId;
var tempDir = 'assets/zip/' + surveyId + '.zip'
zipdir('temp', { saveTo: tempDir }, function (err, buffer) {
callback(null, obj);
});
callback(null, obj);
}
Here I am getting a corrupt zip file. Please suggest the solution.
I tried out your example there are a few things you need to consider in order to make it work.
const async = require('async');
const fs = require('fs');
const path = require('path');
const zipDir = require('zip-dir');
const axios = require('axios');
let writer;
async.waterfall([
createFolder,
downLoadFileAxios,
zip
], function (err, result) {
if (err) {
console.log(err);
} else {
console.log('result :', result);
}
});
let's assume this method creates the temp folder
function createFolder(callback) {
setTimeout(function() {
callback(null, 'temp');
}, 1000);
}
Here the writeStream object and it's events should be put inside the then block. So that it writes the stream to the file correctly.
Another important thing here is you are not having a cath block attached the promise, so if any exception occurs it will be simply eaten up.
function downLoadFileAxios(dirPath, callback) {
// Hard coded the images url for the sake of simplicity
let files = [
'https://free-images.com/lg/be5e/climbing_helmets_climbing_equipment.jpg',
'https://free-images.com/lg/87ce/lilac_lilac_bush_lilac.jpg'
];
async.mapSeries(files, function(img, cb) {
let name = img.slice(img.lastIndexOf('/') + 1);
let imagePath = path.resolve(__dirname, "newDir", name);
writer = fs.createWriteStream(imagePath);
axios({
method: 'get',
url: img,
responseType: 'stream'
}).
then(function(response) {
response.data.pipe(writer);
writer.on('finish', (done) => {
console.log('success!!!');
cb(null, null)
});
writer.on('error', (err) => {
console.log('failed!!!');
cb(err, null)
});
})
.catch((err) => {
console.log(err);
})
}, function(err, result) {
if (err) {
console.log('errrr', err);
}
callback(null, 'done downloading');
})
}
function zip (dirPath, callback) {
let zipPath = path.resolve(__dirname, "assets", "file.zip");
// console.log(`got directory path : ${dirPath}`);
zipDir("newDir", {
saveTo: zipPath
}, function(err, buffer) {
if(err) {
callback(err, null);
} else {
callback(null, 'done');
}
});
}
This can be easily done using Async/Await like following.
const async = require('async');
const fs = require('fs');
const path = require('path');
const zipDir = require('zip-dir');
const axios = require('axios');
var writer;
// faking the directory creation part
async function createFolder(callback) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(true);
}, 2000);
});
}
//Executes in the specified order.
(async () => {
await createFolder();
await downLoadFile();
await zipTheFile();
})();
async function downLoadFile() {
let files = [
'https://free-images.com/lg/be5e/climbing_helmets_climbing_equipment.jpg',
'https://free-images.com/lg/87ce/lilac_lilac_bush_lilac.jpg'
];
for(let i= 0; i<files.length; i++) {
await downLoadFileAxios(files[i]);
}
}
async function downLoadFileAxios(url) {
let name = url.slice(url.lastIndexOf('/') + 1);
let imagePath = path.resolve(__dirname, "newDir", name);
let writer = fs.createWriteStream(imagePath);
const response = await axios({
url,
method: 'GET',
responseType: 'stream'
})
response.data.pipe(writer)
return new Promise((resolve, reject) => {
writer.on('finish', resolve)
writer.on('error', reject)
})
}
function zipTheFile () {
let zipPath = path.resolve(__dirname, "assets", "file.zip");
return new Promise((resolve, reject) => {
zipDir("newDir", {
saveTo: zipPath
}, function(err, buffer) {
if(err) {
return reject(err);
}
return resolve('done');
});
})
}
Hope this helps!.
I couldn't get contents of files from a folder using Nodejs
I am getting contents of one file using read function but not all files at once.
I hope this is correct.
const testFolder = './tests/';
const fs = require('fs');
fs.readdir(testFolder, (err, files) => {
files.forEach(file => {
fs.readFile(file, 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
console.log(data);
});
});
})
I got the answer. Here my solution.
function uAll() {
var absPath = __dirname + "/Assignment1/" + "../data/users/";
console.log(absPath);
fs.readdir(absPath, function (err, files) {
//handling error
if (err) {
return console.log('Unable to scan directory: ' + err);
}
//listing all files using forEach
files.forEach(function (file) {
// console.log(file);
var phone = file.split(".");
fops.read('users', phone[0], function (err, newObj) {
if (!err && newObj) { // Read is successful
console.log("Read User: ", newObj);
}
else { // Error in reading
console.log("User not found");
}
});
});
});
}
You did a good job. I just want to share my idea.
const lib = {};
lib.base = "/Assignment1/" + "../data/users/";
lib.read = function(dir, file, callback) {
fs.readFile(lib.base + dir + '/' + file + '.json', 'utf-8', function(
err,
data
) {
if (!err && data) {
const parsedData = helpers.parseJsonToObject(data);
callback(false, parsedData);
} else {
callback(err, data);
}
});
};
lib.list = function(dir, callback) {
fs.readdir(lib.base + dir + '/', function(err, data) {
if (!err && data && data.length > 0) {
let trimmedFileName = [];
data.forEach(fileName => {
trimmedFileName.push(fileName.replace('.json', ''));
});
callback(false, trimmedFileName);
} else {
callback(err, data);
}
});
};
I am currently encountering some issues where request.post() is not running. Somehow my code is skipping both the request.post() in the if and else statements. Could anyone advise what I did wrong or how to improve my code? It would great if someone also explains to me what I did wrong.
CurrentOrder.findOneAndUpdate(_id, orderBody, function (err, data) {
if (err) return next(err)
CurrentOrder.findOne(_id2, function(err, order) {
if (err) return next(err)
if(order.canadaTrackingStatus.length == 1 && orderBody.paymentStatus == 'paid'){
order.canadaTrackingStatus = [order.canadaTrackingStatus[0], {date: new Date(), status: '门店已揽收'}];
order.save(function(err) {
if (err) return next(err)
var modItems = merge_items(order.items)
var url = {OrderCode:order.orderNumericCode,Sender:{Name:order.senderName,Tel:order.senderPhone,ProvinceName:order.senderProvince,CityName:order.senderCity,ExpAreaName:order.senderCity,Address:order.senderAddress},Receiver:{Name:order.recipientName,Tel:order.recipientPhone,ProvinceName:order.recipientProvince,CityName:order.recipientCity,ExpAreaName:order.recipientCity,Address:order.recipientAddress},Content:modItems}
var newurl = encodeURI(JSON.stringify(url))
console.log(newurl)
request.post({
headers: { 'Content-Type':'content=text/html;charset=utf-8' },
url : `http://rrr.cn/order/create?EBusinessID=1afs190&AppKey=trytr5fasfasf68980hg23gff&Sign=a1a4e30c83c8c9e6d6fd1fasfasfac55dbc1f2f&RequestType=100232&RequestData=${newurl}`
},function(error,response,body){
var chinacode = JSON.parse(body).logisticcode
var newbody = Object.assign(order, {vipOrderNumericCode : chinacode})
CurrentOrder.findOneAndUpdate({_id:order._id}, newbody, function (err, data2) {
if(err) return next(err)
console.log('if')
})
})
});
}else if(order.canadaTrackingStatus.length == 1 && orderBody.paymentStatus == 'pending'){
order.canadaTrackingStatus = [order.canadaTrackingStatus[0]];
order.save(function(err) {
if (err) return next(err)
var modItems = merge_items(order.items)
var url = {OrderCode:order.orderNumericCode,Sender:{Name:order.senderName,Tel:order.senderPhone,ProvinceName:order.senderProvince,CityName:order.senderCity,ExpAreaName:order.senderCity,Address:order.senderAddress},Receiver:{Name:order.recipientName,Tel:order.recipientPhone,ProvinceName:order.recipientProvince,CityName:order.recipientCity,ExpAreaName:order.recipientCity,Address:order.recipientAddress},Content:modItems}
var newurl = encodeURI(JSON.stringify(url))
console.log(newurl)
request.post({
headers: { 'Content-Type':'content=text/html;charset=utf-8' },
url : `http://rrr.cn/order/create?EBusinessID=11987650&AppKey=trytr56809876980hg23gff&Sign=a1a4e30c83c8c9e6d6fd10987ac55dbc1f2f&RequestType=1002&RequestData=${newurl}`
},function(error,response,body){
var chinacode = JSON.parse(body).logisticcode
var newbody = Object.assign(order, {vipOrderNumericCode : chinacode})
CurrentOrder.findOneAndUpdate({_id:order._id}, newbody, function (err, data2) {
if(err) return next(err)
console.log('else')
})
})
});
}
});
if (req.user.userRole == 'admin') {
if (data.batch) res.redirect('/admin/view-batches')
else res.redirect('/admin/orders')
} else {
return res.redirect('/client/current')
}
})
I have been trying to wrap my head around Promises. For basic concepts I understand, but once it gets nested, I am a little bit confused. Any feedback is appreciated
Here is the code that I am trying to refactor into Promises (bluebird)
var getIndividualData = function(url, doneGetIndividualData) {
var $, data;
request(url, function(err, res, body) {
if (!err && res.statusCode === 200) {
$ = cheerio.load(body);
data = {
title: $("#itemTitle").children()["0"].next.data,
condition: $("#vi-itm-cond").text(),
price: $("#prcIsum_bidPrice").text(),
imgUrl: $("#icImg")[0].attribs.src,
createdAt: chance.date(),
likes: chance.integer({min: 0, max: 1000})
};
doneGetIndividualData(null, data);
} else {
doneGetIndividualData(err);
}
});
};
var getListing = function(url, doneGetListing) {
var $;
var links = [];
request(url, function(err, res, body) {
if (!err && res.statusCode === 200) {
$ = cheerio.load(body);
$('.vip').each(function(i, el) {
if (i < 15) {
links.push(el.attribs.href);
}
});
async
.concat(links, getIndividualData, function(err, result) {
return doneGetListing(null, result);
});
} else {
doneGetListing(err);
}
});
};
var putToMongo = function(err, result) {
if (devConfig.seedDB) {
mongoose.connect(devConfig.mongo.uri);
Item.find({}).remove(function(err, items) {
Item.create(result, function(err, items) {
console.log('done');
process.kill();
});
});
}
};
async
.concat(urls, getListing, putToMongo);
The first thing to do is wrap request in something that returns a promise. Many promise libraries have utilities for "promisifying" async functions, but I don't think that'll work here because request passes two success values into its callback:
var requestAsync = function(url) {
return new Promise(function (resolve, reject) {
request(function (err, res, body) {
if (err) {
reject(err);
}
resolve({ res: res, body: body});
});
});
};
Once that's done, it gets a lot easier:
var getIndividualData = function(url) {
return requestAsync(url).then(function (result) {
if (result.res.statusCode === 200) {
var $ = cheerio.load(result.body);
return {
title: $("#itemTitle").children()["0"].next.data,
condition: $("#vi-itm-cond").text(),
price: $("#prcIsum_bidPrice").text(),
imgUrl: $("#icImg")[0].attribs.src,
createdAt: chance.date(),
likes: chance.integer({min: 0, max: 1000})
};
}
throw new Error("Individual data status code: " + result.res.statusCode);
});
};
var getListing = function(url, doneGetListing) {
return requestAsync(url).then(function (result) {
if (result.res.statusCode === 200) {
var $ = cheerio.load(result.body),
promises = $('.vip').filter(function (i) {
return i < 15;
}).map(function (i, el) {
return getIndividualData(el.attribs.href);
});
return Promise.all(promises);
}
throw new Error("Listing status code: " + result.res.statusCode);
});
};
var putToMongo = function(result) {
if (devConfig.seedDB) {
mongoose.connect(devConfig.mongo.uri);
Item.find({}).remove(function(err, items) {
Item.create(result, function(err, items) {
console.log('done');
process.kill();
});
});
}
};
Promise.all(urls.map(getListing))
.then(putToMongo)
.catch(function (err) {
// handle error
});