forked from ERNICommunity/at11
-
Notifications
You must be signed in to change notification settings - Fork 0
/
menuFetcher.js
111 lines (106 loc) · 4.25 KB
/
menuFetcher.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
var request = require('request');
var cache = require('./cache');
var config = require('./config');
var charset = require('charset');
var iconv = require('iconv-lite');
module.exports.fetchMenu = function(url, date, postParams, parseCallback, doneCallback) {
var cached = cache.get(date + ":" + url);
if (cached && !process.env.AT11_NO_CACHE)
{
doneCallback(null, cached);
}
else
{
load(url, date, postParams, parseCallback, function(error, menu) {
if (!error)
{
if (menu.length > 0)
{
cache.set(date + ":" + url, menu);
}
//we need to go through cache to get cache timestamp
doneCallback(null, cache.get(date + ":" + url));
}
else
{
console.error("Error for %s: %s", url, error);
doneCallback(error);
}
});
}
function load(url, date, postParams, parse, done) {
var options = {
url: url,
method: postParams ? "POST" : "GET",
form: postParams,
encoding: 'binary',
timeout: 10 * 1000 // 10s timeout for request
};
request(options, function(error, response, body) {
if (!error && response.statusCode === 200)
{
var enc = charset(response.headers, body);
if (enc !== 'utf-8')
{
body = iconv.decode(new Buffer(body, 'binary'), enc).toString('utf-8');
}
var timer = setTimeout(function() {
timer = null;//clear needed as value is kept even after timeout fired
done(new Error("Parser timeout"));
}, config.parserTimeout);
try
{
parse(body, date, function(menu) {
if (!timer)
{
//multiple calls in parser or parser called after timeout
return;
}
clearTimeout(timer);
timer = null; //clearTimeout does not null the value
try
{
if (!Array.isArray(menu))
{
throw "Invalid menu returned (expected array, got " + typeof menu + ")";
}
menu.forEach(function(item) {
if (typeof item !== "object")
{
throw "Menu item should be object, but got " + typeof item;
}
if (typeof item.isSoup !== "boolean")
{
throw "Menu item has wrong 'isSoup' flag (" + typeof item.isSoup + ")";
}
if (typeof item.text !== "string")
{
throw "Menu item has wrong 'text' property (" + typeof item.text + ")";
}
if (typeof item.price !== "number")
{
throw "Menu item has wrong 'price' property (" + typeof item.price + ")";
}
item.price = isNaN(item.price) ? "" : item.price.toFixed(2).replace(".", ",") + " €"; //convert to presentable form
});
done(null, menu);
}
catch (err)
{
done(err);
}
});
}
catch (err) //catches only synchronous errors in parser code
{
clearTimeout(timer);
doneCallback(err);
}
}
else
{
doneCallback(error || new Error("Response code " + response.statusCode));
}
});
}
};