-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathplacequery.js
164 lines (145 loc) · 4.72 KB
/
placequery.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
var _ = require('underscore');
var yaml = require('js-yaml');
var http = require('http');
var https = require('https');
var url = require('url');
var fs = require('fs');
var completer = require('./placesindex/completer.js');
/**
* Strips everything but title and ID from search results
* @param {Array} results Completer results
* @return {Array} Completer results pared down to title and ID
*/
function getIds(results) {
var output = [];
results.forEach(function(obj) {
output.push({title: obj['title'], id: obj['id']});
});
return output;
}
/**
* Creates a JSend style output object
* @param {String} status success, fail, or error
* @param {String} dataFieldName
* @param {Object} data
* @return {Object}
*/
function jsendOutput(status, dataFieldName, data) {
var output = {status: status, data:{}};
output['data'][dataFieldName] = data;
return output;
}
/**
* Write response to client
* @param {http.ServerResponse} res Server response object
* @param {number} code HTTP response code
* @param {Object} data
*/
function respond(res, code, data) {
res.writeHead(code, {'Content-Type': 'application/json'});
res.write(JSON.stringify(data));
res.end();
}
/** Validate a number parameter */
function isNumber(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
// Load config & places db
try {
var config = yaml.safeLoad(fs.readFileSync('./config.yaml', 'utf8'));
var places = JSON.parse(fs.readFileSync(config.paths.database, 'utf8'));
} catch (err) {
console.error(err);
process.exit(1);
}
// Listener function for handling requests
var requestListener = function(req, res) {
var parsedUrl = url.parse(req.url, true);
// Log query
if(config.log.verbose) {
console.log('Processing query');
for(get in parsedUrl['query']) {
console.log(get + ': ' + parsedUrl['query'][get]);
}
}
// Searching by text
searchQuery = parsedUrl['query']['search'];
if(searchQuery != undefined) {
var results = getIds(completer.complete(places, searchQuery));
var output = jsendOutput('success', 'places', results);
respond(res, 200, output);
return;
}
// Searching by location
lonQuery = parsedUrl['query']['longitude'];
latQuery = parsedUrl['query']['latitude'];
if(lonQuery != undefined && latQuery != undefined) {
if(isNumber(lonQuery) && isNumber(latQuery)) {
// Decide maximum number of kdtree results
var limit = config.limits.nearby.default || 10;
var qLimit = parsedUrl['query']['limit'];
if(qLimit != undefined && isNumber(qLimit) && qLimit > 0) {
if(qLimit < config.limits.nearby.maximum) limit = qLimit;
else limit = config.limits.nearby.maximum;
}
var results = getIds(completer.nearby(places, latQuery, lonQuery, limit));
var output = jsendOutput('success', 'places', results.reverse()); // Nearest places tend to end of array
respond(res, 200, output);
} else {
var output = jsendOutput('fail', 'message', 'Longitude and latitude arguments must be numbers');
respond(res, 400, output);
}
return;
}
// Get specific place by ID
idQuery = parsedUrl['query']['id'];
if(idQuery != undefined) {
var place = places['all'][idQuery];
if(place != undefined) {
var output = jsendOutput('success', 'place', place);
respond(res, 200, output);
} else {
var output = jsendOutput('fail', 'message', 'Invalid ID');
respond(res, 404, output);
}
return;
}
// No valid query
var output = jsendOutput('fail', 'message', 'No valid query supplied');
respond(res, 400, output);
console.log('Invalid query');
};
// Launch the HTTP server
console.log('Starting placequery server');
console.log('There are ' + _.size(places['all']) + ' places in the database.');
if(config.server.ssl.enabled) {
try {
var options = {
key: fs.readFileSync(config.server.ssl.key),
cert: fs.readFileSync(config.server.ssl.cert)
};
var server = https.createServer(options, requestListener);
} catch (err) {
console.error(err);
process.exit(1);
}
} else {
var server = http.createServer(requestListener);
}
server.listen(config.server.port, config.server.address, 511, function() {
console.log('Server listening on port ' + config.server.port);
// Start running as another user (lower privs)
var uid = parseInt(process.env.SUDO_UID) || config.server.uid;
var gid = parseInt(process.env.SUDO_GID) || config.server.gid;
if(uid && gid) {
console.log('Changing from ' + process.getuid() + ':' + process.getgid() + ' to ' + uid + ':' + gid + '...');
try {
process.setgid(gid);
process.setuid(uid);
} catch (err) {
console.error(err);
process.exit(1);
}
}
console.log('Running as ' + process.getuid() + ':' + process.getgid());
});