I've been trying to create a scenario where Request A would arrive first, but it would take a long time to process, meanwhile Request B would arrive second, but would take only a few seconds to process, and I would like for Request B to finish before Request A. However, Request A is currently blocking not just itself, but also Request B.
var http = require('http')
function block(){while(true){var x =2;}}
var server = http.createServer(function(req, res) {
if(req.url=='/wait'){block();}
res.writeHead(200);
res.end('Hello Http');
console.log(req.url)
});
server.listen(3000);
If your original goal is to block a request based on some condition then there 's a better way than using a while loop.
Although it would make your code asynchronous, which will require you to handle your request a little differently.
var server = http.createServer(function(req, res) {
if (req.url == '/wait')
setTimeout(serveRequest, 60000);
else
serveRequest();
function serveRequest() {
res.writeHead(200);
res.end('Hello Http');
console.log(req.url);
}
});
Though the request a depends on request b, there must be a rule to guarantee that request a1 and b1 are a pair, and a2 and b2 are pair, and so on.In other words, it should has a algorithm of checking wheather two request are a pair.
var em = new events.EventEmitter();
const EVENT_B_FINISH = 'bFinishedEvent';
var requestPairQueue = {};//key-value format,the key is the rid of request a,the value is the rid of request b.
//------request a arrive-----
var rid = //get the unique request id
//process a code......
if (requestPairQueue[rid]) {
//the paired b request has processed,send a response directly
}
em.on(EVENT_B_FINISH,function() {
if (requestPairQueue[rid]) {
//the paired b request processed after a while,send a response
}
});
//-----request b arrive----
var ridA = //the relation a request rid
var ridB = //the current b request id
//after process code....
requestPairQueue[ridA] = ridB;
em.emit(EVENT_B_FINISH);
Related
I'm trying to make a .js file that will constantly have the price of bitcoin updated (every five minutes or so). I've tried tons of different ways to web scrape but they always output with either null or nothing. Here is my latest code, any ideas?
var express = require('express');
var path = require('path');
var request = require('request');
var cheerio = require('cheerio');
var fs = require('fs');
var app = express();
var url = 'https://blockchain.info/charts/';
var port = 9945;
function BTC() {
request(url, function (err, res, body) {
var $ = cheerio.load(body);
var a = $(".market-price");
var b = a.text();
console.log(b);
})
setInterval(BTC, 300000)
}
BTC();
app.listen(port);
console.log('server is running on '+port);
It successfully says what port it's running on, that's not the problem. This example (when outputting) just makes a line break every time the function happens.
UPDATE:
I changed the new code I got from Wartoshika and it stopped working, but im not sure why. Here it is:
function BTCPrice() {
request('https://blockchain.info/de/ticker', (error, response, body) => {
const data = JSON.parse(body);
var value = (parseInt(data.USD.buy, 10) + parseInt(data.USD.sell, 10)) / 2;
return value;
});
};
console.log(BTCPrice());
If I have it console.log directly from inside the function it works, but when I have it console.log the output of the function it outputs undefined. Any ideas?
I would rather use a JSON api to get the current bitcoin value instead of an HTML parser. With the JSON api you get a strait forward result set that is parsable by your browser.
Checkout Exchange Rates API
Url will look like https://blockchain.info/de/ticker
Working script:
const request = require('request');
function BTC() {
// send a request to blockchain
request('https://blockchain.info/de/ticker', (error, response, body) => {
// parse the json answer and get the current bitcoin value
const data = JSON.parse(body);
value = (parseInt(data.THB.buy, 10) + parseInt(data.THB.sell, 10)) / 2;
console.log(value);
});
}
BTC();
Using the value as callback:
const request = require('request');
function BTC() {
return new Promise((resolve) => {
// send a request to blockchain
request('https://blockchain.info/de/ticker', (error, response, body) => {
// parse the json answer and get the current bitcoin value
const data = JSON.parse(body);
value = (parseInt(data.THB.buy, 10) + parseInt(data.THB.sell, 10)) / 2;
resolve(value);
});
});
}
BTC().then(val => console.log(val));
As the other answer stated, you should really use an API. You should also think about what type of price you want to request. If you just want a sort of index price that aggregates prices from multiple exchanges, use something like the CoinGecko API. Also if you need real-time data you need a websocket-based API, not a REST API.
If you need prices for a particular exchange, for example you're building a trading bot for one or more exchanges, you;ll need to communicate with each exchange's websoceket API directly. For that I would recommend something like the Coygo API, a node.js package that connects you directly to each exchange's real-time data feeds. You want something that doesn't add a middleman since that would add latency to your data.
I have a route in my express app, which is supposed to do the following:
Get some data from outside (OK)
Show a HTML page with socket.io listening for messages (OK)
Perform some calculations, which take a long time
Send a message trough socket.io after each one one completed (OK)
When all calculations are completed, show a result page (problem)
So, a simplified version of my code is:
module.exports = function(io) { // This is so I can use socket.io inside the route
var express = require('express');
var router = express.Router();
[... and other required]
router.post('/', function(req, res, next) {
res.render('loading'); // This renders the template which holds accepts and renders socket.io messages
pefromCalculaton();
sendSocketIOMessage();
session.data = resultData; // I get the result of all calculations and put that in the session. It's a quick fix, don't judge, I've got no presistancy in my project as for now...
res.redirect('results'); // And here I'd like to go to the other route, which will display the data, getting it from the session.
});
return router;
}
Since this doesn't work, I am probably trying to do something really stupid here. But what I actually want to do is:
Perform calculations
While performing the calculations, update progress using sockets
When calculation is done, render a template, showing all the results.
Well, my friend, as you know that one can't send two responses from within one request. So here is what you need to do.
module.exports = function(io) { // This is so I can use socket.io inside the route
var express = require('express');
var router = express.Router();
[... and other required]
router.post('/', function(req, res, next) {
var taskId = (new Date()).getTime(); //timestamp to get unique task id.
res.render('loading');
startCalculations(function(progressIndicator){ //progress callback
io.emit('progress',progressIndicator);
},function(result){ // Finish callback
session[taskId] = result;
io.emit('finish',{ taskid: taskId });
});
});
router.get('/result:taskId', function(req, res, next) {
var result = session[req.params.taskId];
if(!result)
{
//Result already consumed!
res.render('expired');
return;
}
delete session[req.params.taskId];
res.render('result', {result: result});
});
//progress callback will be called when we want to report progress
//done callback indicates our results are ready.
function startCalculations(progress, done){
//This is just a stupid piece of code, just to emulate loading.
//Your awesome async code will replace this
//In your case it will not be a loop and there will be a callback
//To signal finish.
var result = 0;
for(i = 0; i < 100; i++)
{
result = result + i;
//Simulate progress
progress(i);
}
//Simulate finish -- result has 0 to 99 all added up ;)
done(result);
}
return router;
}
Now on the html front you can have ...
this is how your loading view would look like.
<script src="/socket.io/socket.io.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
var socket = io();
//Init code.
socket.on('progress', function(progressIndicator){
//Your jquery mojo to show progress
displayProgress(progressIndicator);
});
socket.on('finish', function(task){
//Redirect to result page from frontend (you were trying to do
//on backend -- node.js)
window.location.href = "/result/" + task.taskId;
//OR
//window.location.replace("/result/" + task.taskId);
});
</script>
Hope this makes sense and helps ...
Let me know if you need anything else.
Have fun!
Node is asynchronous. Use callbacks or promises to make sure that the result page is shown only when the calculations has been completed.
Recently I started learning a little bit about Node.js and it's capabilities and tried to use it for some web services.
I wanted to create a web service which will serve as a proxy for web requests.
I wanted my service to work that way:
User will access my service -> http://myproxyservice.com/api/getuserinfo/tom
My service will perform request to -> http://targetsite.com/user?name=tom
Responded data would get reflected to the user.
To implement it I used the following code:
app.js:
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
var proxy = require('./proxy_query.js')
function makeProxyApiRequest(name) {
return proxy.getUserData(name, parseProxyApiRequest);
}
function parseProxyApiRequest(data) {
returned_data = JSON.parse(data);
if (returned_data.error) {
console.log('An eror has occoured. details: ' + JSON.stringify(returned_data));
returned_data = '';
}
return JSON.stringify(returned_data);
}
app.post('/api/getuserinfo/tom', function(request, response) {
makeProxyApiRequest('tom', response);
//response.end(result);
});
var port = 7331;
proxy_query.js:
var https = require('https');
var callback = undefined;
var options = {
host: 'targetsite.com',
port: 443,
method: 'GET',
};
function resultHandlerCallback(result) {
var buffer = '';
result.setEncoding('utf8');
result.on('data', function(chunk){
buffer += chunk;
});
result.on('end', function(){
if (callback) {
callback(buffer);
}
});
}
exports.getUserData = function(name, user_callback) {
callback = user_callback
options['path'] = user + '?name=' + name;
var request = https.get(options, resultHandlerCallback);
request.on('error', function(e){
console.log('error from proxy_query:getUserData: ' + e.message)
});
request.end();
}
app.listen(port);
I wish I didn't screwed this code because I replaced some stuff to fit my example.
Anyway, the problem is that I want to post the response to the user when the HTTP request is done and I cant find how to do so because I use express and express uses asynchronous calls and so do the http request.
I know that if I want to do so, I should pass the makeProxyApiRequest the response object so he would be able to pass it to the callback but it is not possible because of asyn problems.
any suggestions?
help will be appreciated.
As you're using your functions to process requests inside your route handling, it's better to write them as express middleware functions, taking the specific request/response pair, and making use of express's next cascade model:
function makeProxyApiRequest(req, res, next) {
var name = parseProxyApiRequest(req.name);
res.locals.userdata = proxy.getUserData(name);
next();
}
function parseProxyApiRequest(req, res, next) {
try {
// remember that JSON.parse will throw if it fails!
data = JSON.parse(res.locals.userdata);
if (data .error) {
next('An eror has occoured. details: ' + JSON.stringify(data));
}
res.locals.proxyData = data;
next();
}
catch (e) { next("could not parse user data JSON."); }
}
app.post('/api/getuserinfo/tom',
makeProxyApiRequest,
parseProxyApiRequest,
function(req, res) {
// res.write or res.json or res.render or
// something, with this specific request's
// data that we stored in res.locals.proxyData
}
);
Even better would be to move those middleware functions into their own file now, so you can simply do:
var middleware = require("./lib/proxy_middleware");
app.post('/api/getuserinfo/tom',
middleware.makeProxyApiRequest,
middleware.parseProxyApiRequest,
function(req, res) {
// res.write or res.json or res.render or
// something, with this specific request's
// data that we stored in res.locals.proxyData
}
);
And keep your app.js as small as possible. Note that the client's browser will simply wait for a response by express, which happens once res.write, res.json or res.render etc is used. Until then the connection is simply kept open between the browser and the server, so if your middleware calls take a long time, that's fine - the browser will happily wait a long time for a response to get sent back, and will be doing other things in the mean time.
Now, in order to get the name, we can use express's parameter construct:
app.param("name", function(req, res, next, value) {
req.params.name = value;
// do something if we need to here, like verify it's a legal name, etc.
// for instance:
var isvalidname = validator.checkValidName(name);
if(!isvalidname) { return next("Username not valid"); }
next();
});
...
app.post("/api/getuserinfo/:name", ..., ..., ...);
Using this system, the :name part of any route will be treated based on the name parameter we defined using app.param. Note that we don't need to define this more than once: we can do the following and it'll all just work:
app.post("/api/getuserinfo/:name", ..., ..., ...);
app.post("/register/:name", ..., ..., ... );
app.get("/api/account/:name", ..., ..., ... );
and for every route with :name, the code for the "name" parameter handler will kick in.
As for the proxy_query.js file, rewriting this to a proper module is probably safer than using individual exports:
// let's not do more work than we need: http://npmjs.org/package/request
// is way easier than rolling our own URL fetcher. In Node.js the idea is
// to write as little as possible, relying on npmjs.org to find you all
// the components that you need to glue together. If you're writing more
// than just the glue, you're *probably* doing more than you need to.
var request = require("request");
module.exports = {
getURL: function(name, url, callback) {
request.get(url, function(err, result) {
if(err) return callback(err);
// do whatever processing you need to do to result:
var processedResult = ....
callback(false, processedResult);
});
}
};
and then we can use that as proxy = require("./lib/proxy_query"); in the middleware we need to actually do the URL data fetching.
There are two examples in between these pages 16 and 18.
Example 1.3 is a server app.
Example 1.4 is a client app doing GET requests to the server.
When I run the two examples (at the same time) I notice some quite weird behavior
in the client. All requests are executed (i.e. the for loop in the client completes)
but the callbacks of only 5 of them get called. The client doesn't exit and also
doesn't error out. And just no more callbacks are called.
Any ideas what might be happening or how I can troubleshoot this further?
Note: I am running Node.js v0.10.20 on Windows 7.
Server:
var http = require('http');
var fs = require('fs');
// write out numbers
function writeNumbers(res) {
var counter = 0;
// increment, write to client
for (var i = 0; i<100; i++) {
counter++;
res.write(counter.toString() + '\n');
}
}
// create http server
http.createServer(function (req, res) {
var query = require('url').parse(req.url).query;
var app = require('querystring').parse(query).file;
// content header
res.writeHead(200, {'Content-Type': 'text/plain'});
if (!app){
res.end();
console.log('No file argument found in query string.');
return;
}else{
app = app + ".txt";
}
// write out numbers
writeNumbers(res);
// timer/timeout to open file and read contents
setTimeout(function() {
console.log('Opening file: ' + app + '.');
// open and read in file contents
fs.readFile(app, 'utf8', function(err, data) {
res.write('\r\n');
if (err)
res.write('Could not find or open file ' + app + ' for reading.\r\n');
else {
res.write(data);
}
// response is done
res.end();
});
},2000);
}).listen(8124);
console.log('Server running at 8124');
Client:
var http = require('http');
var N = 200;
// The URL we want, plus the path and options we need
var options = {
host: 'localhost',
port: 8124,
path: '/?file=automatic',
method: 'GET'
};
var callback_function = function(response) {
// finished? ok, write the data to a file
console.log('got response back');
};
for (var i = 1; i <= N; i++) {
// make the request, and then end it, to close the connection
http.request(options, callback_function).end();
console.log('done with call # ' + i);
}
--- Experiment Done ---
If I lower N to 10 and also if I do a
global "var i = 1" and then do this thing:
function schedule(){
http.request(options, callback_function).end();
console.log('done with call ' + i);
i++;
if (i<=N){
setTimeout(function(){
schedule();
}, 1000);
}
}
schedule();
instead of the loop in the client, I get similar behavior.
I guess that's what Milimetric meant by "sleep" i.e. just
to make sure I don't hit the server too quickly with too
many simultaneous requests.
But the behavior is not fully identical, it takes several mins
to print 'got response back' on the second set of 5 requests
and then another maybe 5-6 mins for the client to exit.
Still, all that does look weird to me.
C:\PERSONAL\NODE_TEST>node test004.js
done with call 1
got response back
done with call 2
got response back
done with call 3
got response back
done with call 4
got response back
done with call 5
got response back
done with call 6
done with call 7
done with call 8
done with call 9
done with call 10
got response back
got response back
got response back
got response back
got response back
C:\PERSONAL\NODE_TEST>
The problem is that the client doesn't consume the response body sent by the server, so the connection remains (half) open and the http agent only allows 5 concurrent requests per client by default, causing it to hang after 5 requests. The connection will eventually timeout, causing the next 5 requests to be processed.
node.js http.get hangs after 5 requests to remote site
Change your callback function to consume any data sent down the response.
var callback_function = function(response) {
// finished? ok, write the data to a file
console.log('got response back');
response.on('data', function () {});
};
Here is my code:
I have more than 500,000 records in my database and I want to loop and request some information from another server. I've successfully wrote all functions except delays between each request. If I send all request with node.js remote server goes downs or can not answer each request. So I need to create a queue for looping But my code is not working still sending all request very fast.
var http = require('http')
, mysql = require('mysql');
var querystring = require('querystring');
var fs = require('fs');
var url = require('url');
var client = mysql.createClient({
user: 'root',
password: ''
});
client.useDatabase('database');
client.query("SELECT * from datatable",
function(err, results, fields) {
if (err) throw err;
for (var index in results) {
username = results[index].username;
setInterval(function() {
requestinfo(username);
}, 5000 );
}
}
);
client.end();
}
Your problem lies in the for loop since you set all the requests to go off every 5 seconds. Meaning after 5 seconds all the requests will be fired relatively simultaneously. And since it is done with setInterval then it will happen every 5 seconds.
You can solve it in 2 ways.
First choice is to set an interval to create a new request every 5 seconds if the index is a number, so instead of a for loop you do something like:
var index = 0;
setInterval(function(){
requestinfo(results[index].username);
index++;
}, 5000)
The second choice is to set all the requests with an increasing timeout so you modify your current script like so:
var timeout = 0;
for (var index in results) {
username = results[index].username;
setTimeout(function() {
requestinfo(username);
}, timeout );
timeout += 5000;
}
This will set timeouts for 0,5,10,15... etc seconds so every 5 seconds a new request is fired.