i'm trying to write a simple app with node.js to pull some json from twitter..
json loads ok the first time, however, my 'tweets' event isnt getting triggered correctly..
anyone see where I'm going wrong? any advice hugely appreciated !
var twitterClient = http.createClient(80, 'api.twitter.com');
var tweetEmitter = new events.EventEmitter();
var request = twitterClient.request("GET", "/1/statuses/public_timeline.json", {"host": "api.twitter.com"});
function getTweats() {
request.addListener("response", function (response) {
var body = "";
response.addListener("data", function (data) {
body += data;
});
response.addListener("end", function (end) {
var tweets = JSON.parse(body);
if (tweets.length > 0) {
tweetEmitter.emit("tweets", tweets);
console.log(tweets, 'tweets loaded');
}
});
});
request.end();
}
setInterval(getTweats(), 1000);
http.createServer(function (request, response) {
var uri = url.parse(request.url).pathname;
console.log(uri);
if (uri === '/stream') {
var cb = function (tweets) {
console.log('tweet'); // never happens!
response.writeHead(200, {"Content-Type": "text/plain"});
response.write(JSON.stringify(tweets));
response.end();
clearTimeout(timeout);
};
tweetEmitter.addListener("tweets", cb);
// timeout to kill requests that take longer than 10 secs
var timeout = setTimeout(function () {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write(JSON.stringify([]));
response.end();
tweetEmitter.removeListener("tweets", cb);
}, 10000);
} else {
loadStaticFile(uri, response);
}
}).listen(port);
console.log("Server running at http://localhost:" + port + "/");
see full file # https://gist.github.com/770810
You have two problems here:
httpClient.request is just that, a one time request.
You're not passing the function getTweats to the interval, but its return value:
setInterval(getTweats() */ <-- parenthesis execute the function */, 1000);
In order to fix it, create a new request for each call of getTweats:
function getTweats() {
// There's no need for request being global, just make it local to getTweats
var request = twitterClient.request("GET", "/1/statuses/public_timeline.json", {"host": "api.twitter.com"});
And pass the function correctly to setTimeout:
setInterval(getTweats, 1000);
PS: Thx for the gist! Took me like 15 seconds to figure it out from there, always great when people post more than just 5 lines of out of context code :)
Related
Im a newbie with node.js and i'm trying to output some data to html.
My code works when I use console.log but not when I use response.end.
When I use response.end I only see on record while when I use console.log I get to see all the records
See my full code below:
var http = require('http');
var formOutput;
var WooCommerceAPI = require('woocommerce-api');
// Initialize the WooCommerceAPI class
var WooCommerce = new WooCommerceAPI({
//url: 'http://example.com', // Your store url (required)
});
function handleRequest(response) {
// GET example
WooCommerce.get('products', function (err, data, res) {
//console.log(res);
//var fs = require('fs');
//var jsonContent = JSON.parse(JSON.stringify(res, null, 4))
var jsonContent = JSON.parse(res)
for (var i = 0; i < jsonContent["products"].length; i++) {
var name = jsonContent["products"][i];
// this works well and I can output all records
//console.log(name['title']);
//console.log(name['id']);
//console.log(name['sku']);
//console.log(name['regular_price']);
//response.writeHead(200, { 'Content-Type': 'text/html' });
//res.end(name['id']);
formOutput = name['regular_price'];
//formOutput = '<h1>XYZ Repository Commit Monitor</h1>';
//response.write();
//Only get one record
response.end(formOutput);
//response.write('<html><head></head><body>');
//response.end("test");
//response.end('</body></html>');
}
});
//response.end(formOutput);
}
http.createServer(function (req, response) {
if (response.url === '/favicon.ico') {
response.writeHead(404);
response.end();
} else {
response.writeHead(200, { 'Content-Type': 'text/html' });
}
//code here...
handleRequest(response);
// response.end(formOutput);
}).listen(1337, "localhost");
console.log("Server running at http://localhost:1337/");
With Express, response.end() closes the communication channel after one call so only one element will be sent to the user. Don't use end() to send data, in your case, use response.json() (or send()) ONCE after you built the data array.
var dataToSend = [];
for (var i = 0; i < jsonContent["products"].length; i++) {
// build an array of data to send here
}
response.json(dataToSend);
On a side note, don't use response.end() unless you want to end the communication explicitly. response.json() and response.send() already close the channel when needed.
I need to make an HTTP call and then put the response in database. i should repeat it forever. i have been reading on async module but i didn't understood how to combine these actions along with the waiting for couple of seconds between each iteration.
Can someone help?
Thanks in advance.
Look into async.forever. Your code would look something like this:
var async = require("async");
var http = require("http");
//Delay of 5 seconds
var delay = 5000;
async.forever(
function(next) {
http.get({
host: "google.com",
path: "/"
}, function(response) {
// Continuously update stream with data
var body = "";
response.on("data", function(chunk) {
body += chunk;
});
response.on("end", function() {
//Store data in database
console.log(body);
//Repeat after the delay
setTimeout(function() {
next();
}, delay)
});
});
},
function(err) {
console.error(err);
}
);
Why using such a module only for doing this ? Why don't you just use setTimeout like:
function makeRequest() {
request(url, function(response) {
saveInDatabase(function() {
// After save is complete, use setTimeout to call again
// "makeRequest" a few seconds later (Here 1 sec)
setTimeout(makeRequest, 1000);
});
}
}
This code won't really work for the request and save part of course, it was just to give an example of what I was proposing.
Okay the question is when I "instanciate" a new object, and run a function from the object, it run 2 times, why's that ? Could some one explain me ?
Example:
server.js
var http = require("http");
var testObj = require("/path/to/obj");
exports.start = function() {
function onRequest(request, response)
{
var app = new testObj();
app.date();
response.writeHead(200, {"Content-Type": "application/json"});
response.write('Testing stuff!');
response.end();
}
http.createServer(onRequest).listen(config.core.server_port);
console.log("Server has started.");
};
obj.js
function Session(){
}
Session.prototype.date = function(){
var date = new Date();
console.log(date);
};
module.exports = Session;
The output in console should be only a date print, but I'm getting two dates prints, why is that?
Most likely the browser is making another request for favicon.
I have the following PHP Script on server that will wait 10 seconds and say Hello:
<php sleep(10); ?>Hello
On the client side (node), I have the following:
var http = require('http');
http.get ('http://example.com/sleep.php', function (resp) {
resp.on('data', function (d) {
console.log ('data!', d.toString());
});
resp.on('end', function (d) {
console.log ('Finished!');
});
}).on('error', function (e) {
console.log ('error:', e);
});
The problem is, if the internet connection stopped during the request, it will not trigger error OR end events.
To re-produce the problem:
Place the PHP script somewhere on the Internet
Execute the node script
Disconnect the Internet
The script does nothing
I've also found that if the connection is back within 10 seconds, it can still receive the message.
So, I made a simple interval loop to check the status. However it can't detect if the connection has stopped working or still waiting for response:
var http = require('http');
var lastRespond = 0, intervalCheck;
var respFinished = false;
http.get ('http://jixun.no-ip.org/sleep.php', function (resp) {
resp.on('data', function (d) {
lastRespond = new Date;
console.log ('data!', d.toString());
});
resp.on('end', function (d) {
respFinished = true;
console.log ('Finished!');
});
}).on('error', function (e) {
console.log ('error:', e);
});
intervalCheck = setInterval(function () {
if (respFinished) {
clearInterval(intervalCheck);
} else if (new Date - lastRespond >= 120000) {
console.log ('Timeout :(');
clearInterval(intervalCheck);
}
}, 120000); // 2 mins.
So my question is: Is there any way to check if the socket closed / connection stopped after sending the request?
Thanks in advance.
Using setTimeout on the actual request could solve your problem. Well, it's not an actual event like 'close', 'end' and 'error'. Sample below does reproduce and solves the issue, haven't tried it in another context though.
var http = require('http');
http.get ('http://fake-response.appspot.com?sleep=5', function (resp) {
resp.on('data', function (d) {
console.log ('data!', d.toString());
});
resp.on('end', function (d) {
console.log ('Finished!');
});
}).on('error', function (e) {
console.log ('error:', e);
}).setTimeout(12000, function ( ) {
console.log('Timeout reached...');
process.exit(1);
});
More information can be found in the documentation. Either use that or listening on the 'close' event as well, that works well with the net module.
Maybe this would be usefull for you:
Create a bash script which checks connection (grabbed from https://stackoverflow.com/a/14939373/1779015 with little modifications):
#!/bin/bash
# Test for network conection
for interface in $(ls /sys/class/net/ | grep -v lo);
do
if [[ $(cat /sys/class/net/$interface/carrier 2> /dev/null) = 1 ]]; then OnLine=1; fi
done
if ! [ $OnLine ]; then echo "0";
else
echo "1";
fi
Then call it from node script and read stdout, for example with child_process (http://nodejs.org/api/child_process.html):
var spawn = require('child_process').spawn,
hasInet = spawn('./test-inet.sh');
hasInet.stdout.pipe(process.stdout);
Here is my solution ... instead of using set interval I check if on "data" event keeps firing until END event.
var http = require('http');
var url = require('url');
var options = {};
var parsed_url = url.parse(url, true);
var req_options = {
path: parsed_url.pathname,
host: parsed_url.hostname
};
var file = fs.createWriteStream(filename,options);
try{
const check_data_timeout = 10000;
var check_data_timer = 0;
var current_size = 0;
var request = http.get(req_options, function(response) {
len = parseInt(response.headers['content-length'], 10);
response.on("data", function(chunk) {
current_size += chunk.length;
percent = (100.0 * current_size / len).toFixed(2);
console.log("Download percent : "+percent+"%");
clearTimeout(check_data_timer);
check_data_timer = setTimeout(function(){
console.log("UPS !! No new data ... connection must be stalled");
},check_data_timeout);
});
response.on("end", function() {
console.log("Response ENDED !!!");
clearTimeout(check_data_timer);
});
response.pipe(file);
check_data_timer = setTimeout(function(){
console.log("UPS !! No new data ... connection must be stalled");
},check_data_timeout);
}).once('error', function(error) {
console.log("Response ERROR !!!");
});
}catch(e){
console.log(e);
}
Hope it helps ...
There is a post: How do I set a timeout for client http connections in node.js
but none of the answer will work.
So, I have the code like that:
var remote_client = http.createClient(myPost, myHost);
var path = '/getData?';
var param = { };
var request = remote_client.request("POST", path,);
// error case
remote_client.addListener('error', function(connectionException){
console.log("Nucleus Error: " + connectionException);
next(connectionException);
});
request.addListener('response', function (response) {
response.setEncoding('utf-8');
var body = '';
response.addListener('data', function (chunk) {
// get the result!
});
});
request.end();
The biggest problem is that the url that I'm connection to may timeout. Therefore, I would like to set a timeout, like 15 secs. If so, trigger a listener.
However, I haven't seen any timeout features in the documentation for http.createClient. Please advise. Thanks. :)
var foo = setTimeout(function() {
request.emit("timeout-foo");
}, 15000);
// listen to timeout
request.on("timeout-foo", function() { });
request.addListener('response', function (response) {
// bla
// clear counter
clearTimeout(foo);
});
Just run the counter yourself.