Node.js shortened url - javascript

I have just started learning to code about 5 days ago and what I'm struggling to achieve, is to have an rssfeed-to-twitter script that posts a shortened url instead of a full website/article feed url. I found a node.js module called TinyURL that could do that but i struggle to get it to work. Here's the full script:
var simpleTwitter = require('simple-twitter');
var fs = require('fs');
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type' : 'text/plain'});
res.end('RSS Twitter Bot\n');
}).listen(5693);
var timeInterval = 300000; // run every 30m
var timerVar = setInterval (function () {runBot()}, timeInterval);
function runBot(){
var lastCompleted = Date.parse(new Date(0));
console.log(lastCompleted);
try {
var lastcompletedData = fs.readFileSync('./lastCompleted.json', 'utf8');
var timeData = JSON.parse(lastcompletedData);
var lastCompletedFromFile = Date.parse(new Date(timeData.lastCompleted));
if ( isNaN(lastCompletedFromFile) == false ) {
lastCompleted = lastCompletedFromFile;
}
} catch (e) {
console.log(e);
}
fs.readFile('./config.json', 'utf8', function (err, data) {
if (err) console.log(err); // we'll not consider error handling for now
var configData = JSON.parse(data);
console.log(configData);
var twitter = new simpleTwitter( configData.consumerKey //consumer key from twitter api
, configData.consumerSecret //consumer secret key from twitter api
, configData.accessToken //access token from twitter api
, configData.accessTokenSecret //access token secret from twitter api
, 3600);
var dateNow = Date.parse(new Date());
var FeedParser = require('feedparser');
var request = require('request');
var req = request(configData.feedUrl);
var feedparser = new FeedParser();
req.on('error', function (error) {
console.log(error);
});
req.on('response', function (res){
var stream = this;
if (res.statusCode != 200 ) return this.emit('error', new Error('Bad status code'));
stream.pipe(feedparser);
});
feedparser.on('error', function(error) {
console.log(error);
});
feedparser.on('readable', function() {
var stream = this;
var meta = this.meta;
var item;
while (item = stream.read()) {
var itemDate = Date.parse(item.date);
//check to not publish older articles
if (itemDate > lastCompleted){
var titleLength = item.title.length;
var itemTitle = item.title;
var itemLink = item.link;
if (titleLength > 100) {
itemTitle = itemTitle.substring(0, 100);
}
twitter.post('statuses/update'
, {'status' : itemTitle + ' ' + itemLink + " " + configData.tags}
, function (error, data) {
console.dir(data);
});
console.log(itemTitle + ' ' + item.link + configData.tags);
}
}
//TO KNOW WHEN FROM TO START POSTING
var dateCompleted = new Date();
console.log('loop completed at ' + dateCompleted);
var outputData = {
lastCompleted : dateCompleted
}
var outputFilename = './lastCompleted.json';
fs.writeFile(outputFilename, JSON.stringify(outputData, null, 4), function(err) {
if(err) {
console.log(err);
} else {
console.log("JSON saved to " + outputFilename);
}
});
});
});
}
And this is the TinyURL node.js module
var TinyURL = require('tinyurl');
TinyURL.shorten('http://google.com', function(res) {
console.log(res); //Returns a tinyurl
});
Changing the 'http://google.com' string to itemLink var works just fine and prints it in the terminal as expected.
TinyURL.shorten(itemLink, function(res) {
console.log(res); //Returns a tinyurl
});
What i'm trying to achieve is:
twitter.post('statuses/update', {'status' : itemTitle + ' ' + tinyurlLink + " " + configData.tags}
How can i get the response turned into a e.g var tinyurlLink to replace the itemLink var? Any help would be much appreciated!

As suggested by #zerkms sending a tweet from inside the TinyURL.shorten worked!

Related

images won't properly display on tls server

When I go to an image all I get is a square box
This is running latest node as of today I've tried opening the binary file in utf8 and tried not specifying the encoding
var fs = require("fs");
var net = require("net");
var tls = require("tls");
var config = require("config");
var clients = [];
mount = ";";
function get(data) {
var r = /GET\s(.+)\sHTTP/gms;
var rt = r.exec(data)
if (rt != null) { return rt[1] }
}
function handle_data(data, socket) {
if (get(data) == "/") {
var read = fs.readFile("index.html", function(err, data) {
if (err){
console.log(err);
}
var data = data.toString();
var content = data.replace("{port}", config.JCasterPort).replace("{mount}", mount);
var length = content.length
var header = config.HTTP_RESP.replace("{length}", length).replace("{cts}", content).replace("{type}", "text/html");
socket.write(header)
});
}
if (get(data) == "/img/content-bg.png") {
var read = fs.readFile("img/content-bg.png", "utf8", function(err, data) {
if (err){
console.log(err);
}
var data = data.toString();
var content = data;
var length = content.length
var header = config.HTTP_RESP.replace("{length}", length).replace("{cts}", content).replace("{type}", "image/png");
socket.write(header)
});
}
if (get(data) == "/img/background.gif") {
var read = fs.readFile("img/background.gif", "utf8", function(err, data) {
if (err){
console.log(err);
}
var data = data.toString();
var content = data;
var length = content.length
var header = config.HTTP_RESP.replace("{length}", length).replace("{cts}", content).replace("{type}", "image/gif");
socket.write(header)
});
}
if (get(data) == "/img/background.jpg") {
var read = fs.readFile("img/background.jpg", function(err, data) {
if (err){
console.log(err);
}
var data = data.toString()
var content = data;
var length = content.length
var header = config.HTTP_RESP.replace("{length}", length).replace("{cts}", content).replace("{type}", "image/jpg");
socket.write(header)
});
}
}
if (config.JCasterSSL) {
var key = config.JCasterKey;
var cert = config.JCasterCert;
var options = {
key: fs.readFileSync(key),
cert: fs.readFileSync(cert)
};
var server = tls.createServer(options, function(socket) {
socket.on("data", function(data) {
var data = data.toString();
handle_data(data, socket)
});
});
server.listen(config.JCasterPort, function(){
console.log("Listening on port: " + config.JCasterPort)
});
} else {
}
//HTTP_RESP = HTTP/1.1 200 OK\r\nContent-Type: {type}\r\nContent-Length: {length}\r\n\r\n{cts}
My goal is to display the images I know I can use the built in http/https library but I need it to be able to broadcast audio data
the only thing I haven't tried was encoding to ASCII

Node.js http.request Express multiple requests with single res.render

I have successfully figured out node.js/Express code for making a single http.request to my server. However, the next step is to make multiple requests which use the same res.render statement at the end.
Here is my successful working code:
module.exports = function (app) {
// MODULES - INCLUDES
var xml2js = require('xml2js');
var parser = new xml2js.Parser();
// FORM - SUBMIT - CUCMMAPPER
app.post('/cucmmapper/submit', function (req, res) {
// FORM - DATA COLLECTION
var cucmpub = req.body.cucmpub;
var cucmversion = req.body.cucmversion;
var username = req.body.username;
var password = req.body.password;
// JS - VARIABLE DEFINITION
var authentication = username + ":" + password;
var soapreplyx = '';
var cssx = '';
var spacer = '-----';
var rmline1 = '';
var rmline2 = '';
var rmline3 = '';
var rmline4 = '';
var rmbottomup1 = '';
var rmbottomup2 = '';
var rmbottomup3 = '';
// HTTP.REQUEST - BUILD CALL
var https = require("https");
var headers = {
'SoapAction': 'CUCM:DB ver=' + cucmversion + ' listCss',
'Authorization': 'Basic ' + new Buffer(authentication).toString('base64'),
'Content-Type': 'text/xml; charset=utf-8'
};
// SOAP - AXL CALL
var soapBody = new Buffer('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/11.5">' +
'<soapenv:Header/>' +
'<soapenv:Body>' +
'<ns:listCss sequence="?">' +
'<searchCriteria>' +
'<name>%</name>' +
'</searchCriteria>' +
'<returnedTags uuid="?">' +
'<name>?</name>' +
'<description>?</description>' +
'<clause>?</clause>' +
'</returnedTags>' +
'</ns:listCss>' +
'</soapenv:Body>' +
'</soapenv:Envelope>');
// HTTP.REQUEST - OPTIONS
var options = {
host: cucmpub, // IP ADDRESS OF CUCM PUBLISHER
port: 8443, // DEFAULT CISCO SSL PORT
path: '/axl/', // AXL URL
method: 'POST', // AXL REQUIREMENT OF POST
headers: headers, // HEADER VAR
rejectUnauthorized: false // REQUIRED TO ACCEPT SELF-SIGNED CERTS
};
// HTTP.REQUEST - Doesn't seem to need this line, but it might be useful anyway for pooling?
options.agent = new https.Agent(options);
// HTTP.REQUEST - OPEN SESSION
let soapRequest = https.request(options, soapResponse => {
soapResponse.setEncoding('utf8');
soapResponse.on('data', chunk => {
soapreplyx += chunk
});
// HTTP.REQUEST - RESULTS + RENDER
soapResponse.on('end', () => {
// EDIT - SCRUB XML OUTPUT
var rmline1 = soapreplyx.replace(/<\?xml\sversion='1\.0'\sencoding='utf-8'\?>/g, '');
var rmline2 = rmline1.replace(/<soapenv:Envelope\sxmlns:soapenv="http:\/\/schemas.xmlsoap.org\/soap\/envelope\/">/g, '');
var rmline3 = rmline2.replace(/<soapenv:Body>/g, '');
var rmline4 = rmline3.replace(/<ns:listCssResponse\sxmlns:ns="http:\/\/www\.cisco\.com\/AXL\/API\/[0-9]*\.[0-9]">/g, '');
var rmbottomup1 = rmline4.replace(/<\/soapenv:Envelope>/g, '');
var rmbottomup2 = rmbottomup1.replace(/<\/soapenv:Body>/g, '');
var xmlscrubbed = rmbottomup2.replace(/<\/ns:listCssResponse>/g, '');
// console.log(xmlscrubbed);
// console.log(spacer);
// XML2JS - TESTING
parser.parseString(xmlscrubbed, function (err, result) {
var cssx = result['return']['css'];
// console.log(cssx);
// console.log(spacer);
res.render('cucmmapper-results.html', {
title: 'CUCM Toolbox',
cucmpub: cucmpub,
cssx: cssx,
soapreply: soapreplyx,
xmlscrubbed: xmlscrubbed
});
});
});
});
// SOAP - SEND AXL CALL
soapRequest.write(soapBody);
soapRequest.end();
});
}
My guess is that I have to setup several things to make this work:
Another "var soapBody" with my new request (I can do this).
Another "let soapRequest" (I'm good with this too).
Another "soapRequest.write" statement (Again, easy enough).
Split the "res.render" statement out of the specific "let soapRequest" statement and gather all the variable (this is where I'm stuck).
My guess is that I need to use async. However, I can't for the life of me wrap my head around how to get that "res.render" to work with async.
Here is the closest I can come to an answer. However, the "cssx" and "partitionsx" variable are not translated over to the "function complete". They both still show up as null.
module.exports = function (app) {
// MODULES - INCLUDES
var xml2js = require('xml2js');
var parser = new xml2js.Parser();
// FORM - SUBMIT - CUCMMAPPER
app.post('/cucmmapper/submit', function (req, res) {
// FORM - DATA COLLECTION
var cucmpub = req.body.cucmpub;
var cucmversion = req.body.cucmversion;
var username = req.body.username;
var password = req.body.password;
// JS - VARIABLE DEFINITION - GLOBAL
var authentication = username + ":" + password;
var soapreplyx = '';
var cssx = null;
var spacer = '-----';
var rmline1 = '';
var rmline2 = '';
var rmline3 = '';
var rmline4 = '';
var rmbottomup1 = '';
var rmbottomup2 = '';
var rmbottomup3 = '';
var soapreplyp = '';
var partitionsx = null;
var rmline1p = '';
var rmline2p = '';
var rmline3p = '';
var rmline4p = '';
var rmbottomup1p = '';
var rmbottomup2p = '';
var rmbottomup3p = '';
// HTTP.REQUEST - BUILD CALL - GLOBAL
var https = require("https");
var headers = {
'SoapAction': 'CUCM:DB ver=' + cucmversion + ' listCss',
'Authorization': 'Basic ' + new Buffer(authentication).toString('base64'),
'Content-Type': 'text/xml; charset=utf-8'
};
// SOAP - AXL CALL - CSS
var soapBody = new Buffer('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/11.5">' +
'<soapenv:Header/>' +
'<soapenv:Body>' +
'<ns:listCss sequence="?">' +
'<searchCriteria>' +
'<name>%</name>' +
'</searchCriteria>' +
'<returnedTags uuid="?">' +
'<name>?</name>' +
'<description>?</description>' +
'<clause>?</clause>' +
'</returnedTags>' +
'</ns:listCss>' +
'</soapenv:Body>' +
'</soapenv:Envelope>');
// SOAP - AXL CALL - PARTITIONS
var soapBody2 = new Buffer('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/11.5">' +
'<soapenv:Header/>' +
'<soapenv:Body>' +
'<ns:listRpite{artotopm} sequence="?">' +
'<searchCriteria>' +
'<name>%</name>' +
'</searchCriteria>' +
'<returnedTags uuid="?">' +
'<name>?</name>' +
'</returnedTags>' +
'</ns:listRoutePartition>' +
'</soapenv:Body>' +
'</soapenv:Envelope>');
// HTTP.REQUEST - OPTIONS - GLOBAL
var options = {
host: cucmpub, // IP ADDRESS OF CUCM PUBLISHER
port: 8443, // DEFAULT CISCO SSL PORT
path: '/axl/', // AXL URL
method: 'POST', // AXL REQUIREMENT OF POST
headers: headers, // HEADER VAR
rejectUnauthorized: false // REQUIRED TO ACCEPT SELF-SIGNED CERTS
};
// HTTP.REQUEST - GLOBAL (Doesn't seem to need this line, but it might be useful anyway for pooling?)
options.agent = new https.Agent(options);
// HTTP.REQUEST - OPEN SESSION - CSS
var soapRequest = https.request(options, soapResponse => {
soapResponse.setEncoding('utf8');
soapResponse.on('data', chunk => {
soapreplyx += chunk
});
// HTTP.REQUEST - RESULTS + RENDER
soapResponse.on('end', () => {
// EDIT - SCRUB XML OUTPUT
var rmline1 = soapreplyx.replace(/<\?xml\sversion='1\.0'\sencoding='utf-8'\?>/g, '');
var rmline2 = rmline1.replace(/<soapenv:Envelope\sxmlns:soapenv="http:\/\/schemas.xmlsoap.org\/soap\/envelope\/">/g, '');
var rmline3 = rmline2.replace(/<soapenv:Body>/g, '');
var rmline4 = rmline3.replace(/<ns:listCssResponse\sxmlns:ns="http:\/\/www\.cisco\.com\/AXL\/API\/[0-9]*\.[0-9]">/g, '');
var rmbottomup1 = rmline4.replace(/<\/soapenv:Envelope>/g, '');
var rmbottomup2 = rmbottomup1.replace(/<\/soapenv:Body>/g, '');
var xmlscrubbed = rmbottomup2.replace(/<\/ns:listCssResponse>/g, '');
// console.log(xmlscrubbed);
// console.log(spacer);
// XML2JS - TESTING
parser.parseString(xmlscrubbed, function (err, result) {
var cssx = result['return']['css'];
// console.log(cssx);
// console.log(spacer);
complete();
});
});
});
// SOAP - SEND AXL CALL - CSS
soapRequest.write(soapBody);
soapRequest.end();
// SOAP - SEND AXL CALL - PARTITIONS
var soapRequest2 = https.request(options, soapResponse2 => {
soapResponse2.setEncoding('utf8');
soapResponse2.on('data', chunk => {
soapreplyp += chunk
});
// HTTP.REQUEST - RESULTS + RENDER
soapResponse2.on('end', () => {
// EDIT - SCRUB XML OUTPUT
var rmline1p = soapreplyy.replace(/<\?xml\sversion='1\.0'\sencoding='utf-8'\?>/g, '');
var rmline2p = rmline1.replace(/<soapenv:Envelope\sxmlns:soapenv="http:\/\/schemas.xmlsoap.org\/soap\/envelope\/">/g, '');
var rmline3p = rmline2.replace(/<soapenv:Body>/g, '');
var rmline4p = rmline3.replace(/<ns:listCssResponse\sxmlns:ns="http:\/\/www\.cisco\.com\/AXL\/API\/[0-9]*\.[0-9]">/g, '');
var rmbottomup1p = rmline4.replace(/<\/soapenv:Envelope>/g, '');
var rmbottomup2p = rmbottomup1.replace(/<\/soapenv:Body>/g, '');
var xmlscrubbedp = rmbottomup2.replace(/<\/ns:listCssResponse>/g, '');
console.log(xmlscrubbedp);
console.log(spacer);
// XML2JS - TESTING
parser.parseString(xmlscrubbedp, function (err, result) {
var partitionsx = result['return']['css'];
// console.log(partitionsx);
// console.log(spacer);
complete();
});
});
});
// SOAP - SEND AXL CALL - PARTITIONS
soapRequest2.write(soapBody2);
soapRequest2.end();
// PAGE - RENDER
function complete() {
if (cssx !== null && partitionsx !== null) {
res.render('cucmmapper-results.html', {
title: 'CUCM Toolbox',
cucmpub: cucmpub,
cssx: cssx,
partitionsx: partitionsx,
})
} else {
res.render('cucmerror.html', {
title: 'CUCM Toolbox',
})
}
};
});
}
Any help or suggestions would be greatly appreciated.
OK, so the thing to remember is that there is always one request mapped to one response in HTTP. So you can't send multiple requests and expect to get just one response from that.
Instead, you need to have the server keep track of what's been posted (perhaps in a database on a production app), and respond to each request in turn. One way might be to respond with partial documents, or respond with other codes that indicate the submission was accepted but that you need to send another request to push more info, that sort of thing.
But again, you can't strictly accept multiple requests without responding and then respond only after all requests are given.

Getting hostname of URL in loop - Nodejs

So I'm currently trying to make an http status code checker. But for some reason the response hostname is returning undefined, yet i can retrieve the response statusCode. Am I grabbing it properly?
var fs = require('fs');
var http = require('http');
var stdin = process.openStdin();
stdin.addListener('data', function (userInput) {
var urlListPath = userInput.toString().trim();
fs.readFile(urlListPath, function (err, data) {
if (err) {
return console.log(err);
}
var urlArray = data.toString().split("\n");
urlArray = urlArray.filter(Boolean);
for (var i = 0; i < urlArray.length; i++){
http.get({hostname: urlArray[i]}, function(res){
console.log(res.hostname + ' | ' + res.statusCode + ' | ' + res.statusMessage);
});
}
});
});
Solved by wrapping in a function as #bluesman suggested:
var fs = require('fs');
var http = require('http');
var stdin = process.openStdin();
stdin.addListener('data', function (userInput) {
var urlListPath = userInput.toString().trim();
fs.readFile(urlListPath, function (err, data) {
if (err) {
return console.log(err);
}
var urlArray = data.toString().split("\n");
urlArray = urlArray.filter(Boolean);
for (var i = 0; i < urlArray.length; i++){
getHttpInfo(urlArray[i]);
}
});
});
function getHttpInfo(url){
http.get({hostname: url}, function(res){
console.log(url + ' : ' + res.statusCode + ' | ' + res.statusMessage);
});
}

Node.js callback confusion

I am trying to implement an autocompleter on a nodejs app using nowjs.
everyone.now.sendAutocomplete = function(search) {
var response = getAutocomplete(search);
console.log("response");
console.log(response);
};
which calls:
function getAutocomplete(search) {
console.log(search);
var artist = new Array();
request({uri: 'http://musicbrainz.org/ws/2/artist/?query=' + search + '&limit=4', headers: "Musicbrainz Application Version 1"}, function(error, response, body) {
par.parseString(body, function(err, result) {
var count = result['artist-list']['#']['count'];
var artists = result['artist-list']['artist'];
// var artist = new Array();
if (count > 1) {
artists.forEach(function(a) {
var att = a['#'];
var id = att['id'];
var name = a['name'];
var dis = a['disambiguation'];
if (dis) {
var display = name + " (" + dis + " )";
} else {
display = name;
}
artist.push({'id':id, 'name': name, 'disambiguation':dis,
'label':display, 'value':name, 'category':"Artists"});
});
//everyone.now.receiveResponse(artist);
console.log("artist");
console.log(artist);
return artist;
} else {
console.log(artists);
var att = artists['#'];
var id = att['id'];
var name = artists['name'];
var dis = artists['disambiguation'];
var resp = [{'id':id, 'name': name, 'disambiguation':dis,
'label':name, 'value':name, 'category':"Artists"}];
return resp;
// everyone.now.receiveResponse([{'id':id, 'name': name, 'disambiguation':dis,
// 'label':name, 'value':name, 'category':"Artists"}]);
}
});
});
}
However, console.log(response) says that response is undefined. I am new to node so the answer is probably simple, but still can't figure it out.
You are treating the async call as synchronous. Your getAutocomplete needs to take a callback function to get the response. You're using that a lot already, in your request call and your parseString call.
Like this:
everyone.now.sendAutocomplete = function(search) {
getAutocomplete(search, function (response) {
console.log("response");
console.log(response);
});
};
And instead of return:
function getAutocomplete(search, callback) {
// ...
callback(result);
// ...
}

How can I get node.js to return data once all operations are complete

I am just learning server-side JavaScript so please bear with any glaring mistakes I've made.
I am trying to write a file parser that operates on HTML files in a directory and returns a JSON string once all files have been parsed. I started it with a single file and it works fine. it loads the resource from Apache running on the same machine, injects jquery, does the parsing and returns my JSON.
var request = require('request'),
jsdom = require('jsdom'),
sys = require('sys'),
http = require('http');
http.createServer(function (req, res) {
request({uri:'http://localhost/tfrohe/Car3E.html'}, function (error, response, body) {
if (!error && response.statusCode == 200) {
var window = jsdom.jsdom(body).createWindow();
jsdom.jQueryify(window, 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js', function (window, jquery) {
// jQuery is now loaded on the jsdom window created from 'body'
var emps = {};
jquery("tr td img").parent().parent().each(function(){
var step = 0;
jquery(this).children().each(function(index){
if (jquery(this).children('img').attr('src') !== undefined) {
step++;
var name = jquery(this).parent().next().next().children('td:nth-child('+step+')').children().children().text();
var name_parts = name.split(",");
var last = name_parts[0];
var name_parts = name_parts[1].split(/\u00a0/g);
var first = name_parts[2];
emps[last + ",_" + first] = jquery(this).children('img').attr('src');
}
});
});
emps = JSON.stringify(emps);
//console.log(emps);
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(emps);
});
} else {
res.writeHead(200, {"Content-Type": "text/plain"});
res.end("empty");
//console.log(response.statusCode);
}
});
}).listen(8124);
Now I am trying to extend this to using the regular file system (fs) and get all HTML files in the directory and parse them the same way and return a single combined JSON object once all files have been parsed. Here is what I have so far but it does not work.
var sys = require("sys"),
fs = require("fs"),
jsdom = require("jsdom"),
emps = {};
//path = '/home/inet/www/media/employees/';
readDirectory = function(path) {
fs.readdir(path, function(err, files) {
var htmlfiles = [];
files.forEach(function(name) {
if(name.substr(-4) === "html") {
htmlfiles.push(name);
}
});
var count = htmlfiles.length;
htmlfiles.forEach(function(filename) {
fs.readFile(path + filename, "binary", function(err, data) {
if(err) throw err;
window = jsdom.jsdom(data).createWindow();
jsdom.jQueryify(window, 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js', function (window, jquery) {
jquery("tr td img").parent().parent().each(function(){
var step = 0;
jquery(this).children().each(function(index){
if (jquery(this).children('img').attr('src') !== undefined) {
step++;
var empname = jquery(this).parent().next().next().children('td:nth-child('+step+')').children().children().text();
var name_parts = empname.split(",");
var last = name_parts[0];
var name_parts = name_parts[1].split(/\u00a0/g);
var first = name_parts[2]
emps[last + ",_" + first] = jquery(this).children('img').attr('src');
}
});
});
});
});
});
});
}
readDirectory('/home/inet/www/media/employees/', function() {
console.log(emps);
});
In this particular case, there are 2 html files in the directory. If i console.log(emps) during the htmlfiles.forEach() it shows me the results from the first file then the results for both files together the way I expect. how do I get emps to be returned to readDirectory so i can output it as desired?
Completed Script
After the answers below, here is the completed script with a httpServer to serve up the detail.
var sys = require('sys'),
fs = require("fs"),
http = require('http'),
jsdom = require('jsdom'),
emps = {};
var timed = setInterval(function() {
emps = {};
readDirectory('/home/inet/www/media/employees/', function(emps) {
});
}, 3600000);
readDirectory = function(path, callback) {
fs.readdir(path, function(err, files) {
var htmlfiles = [];
files.forEach(function(name) {
if(name.substr(-4) === "html") {
htmlfiles.push(name);
}
});
var count = htmlfiles.length;
htmlfiles.forEach(function(filename) {
fs.readFile(path + filename, "binary", function(err, data) {
if(err) throw err;
window = jsdom.jsdom(data).createWindow();
jsdom.jQueryify(window, 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js', function (window, jquery) {
var imagecount = jquery("tr td img").length;
jquery("tr td img").parent().parent().each(function(){
var step = 0;
jquery(this).children().each(function(index){
if (jquery(this).children('img').attr('src') !== undefined) {
step += 1;
var empname = jquery(this).parent().next().next().children('td:nth-child('+step+')').children().children().text();
var name_parts = empname.split(",");
var last = name_parts[0];
var name_parts = name_parts[1].split(/\u00a0/g);
var first = name_parts[2]
emps[last + ",_" + first] = jquery(this).children('img').attr('src');
}
});
});
count -= 1;
if (count <= 0) {
callback(JSON.stringify(emps));
}
});
});
});
});
}
var init = readDirectory('/home/inet/www/media/employees/', function(emps) {
});
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(JSON.stringify(emps));
}).listen(8124);
That sure is a lot of code a couple of mistakes.
You're never calling the callback function you supply to readDirectory
You need to keep track of the files you have parsed, when you parsed all of them, call the callback and supply the emps
This should work:
var sys = require("sys"),
fs = require("fs"),
jsdom = require("jsdom"),
//path = '/home/inet/www/media/employees/';
// This is a nicer way
function readDirectory(path, callback) {
fs.readdir(path, function(err, files) {
// make this local
var emps = {};
var htmlfiles = [];
files.forEach(function(name) {
if(name.substr(-4) === "html") {
htmlfiles.push(name);
}
});
// Keep track of the number of files we have parsed
var count = htmlfiles.length;
var done = 0;
htmlfiles.forEach(function(filename) {
fs.readFile(path + filename, "binary", function(err, data) {
if(err) throw err;
window = jsdom.jsdom(data).createWindow();
jsdom.jQueryify(window, 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js', function (window, jquery) {
jquery("tr td img").parent().parent().each(function(){
var step = 0;
jquery(this).children().each(function(index){
if (jquery(this).children('img').attr('src') !== undefined) {
step++;
var empname = jquery(this).parent().next().next().children('td:nth-child('+step+')').children().children().text();
var name_parts = empname.split(",");
var last = name_parts[0];
var name_parts = name_parts[1].split(/\u00a0/g);
var first = name_parts[2]
emps[last + ",_" + first] = jquery(this).children('img').attr('src');
}
});
});
// As soon as all have finished call the callback and supply emps
done++;
if (done === count) {
callback(emps);
}
});
});
});
});
}
readDirectory('/home/inet/www/media/employees/', function(emps) {
console.log(emps);
});
You seem to be doing this a tad wrong
readDirectory('/home/inet/www/media/employees/', function() {
console.log(emps);
});
But you've defined your function as:
readDirectory = function(path) {
Where is the callback argument? Try this:
readDirectory = function(path, callback) {
then under emps[last + ",_" + first] = jquery(this).children('img').attr('src'); put
callback.call(null, emps);
Your callback function will be called however many times your loop goes on for. If you want it to return all of them at once, you'll need to get a count of how many times the loop is going to run for, count up until that number then call your callback when the emps array is full of the data you need.

Categories