This repository has been archived by the owner on Nov 16, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
199 lines (183 loc) · 5.84 KB
/
server.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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
var express = require('express');
var moment = require('moment');
var xml2js = require('xml2js');
var rest = require('restler'); //also requires xml2js
var async = require('async');
var app = express();
var settings = {
baseUrl: "https://netmon.freifunk-franken.de",
apiMaxParallelRequests: 1, //TODO ask netmon developers what they think is best here; ERROR: Multible request return the same data
apiMaxPageLimit: 50,
port: 9001
}
/**
* TODO
* @param res
* @param code
* @param error
* @param reason
* @returns error object
*/
function _showError(res, code, error, reason) {
var e = {
error: error,
reason: reason,
};
res.statusCode = code;
res.send(e);
return e;
}
/**
* cleanup of unnecessary arrays:
* "key": [ "value" ] ==> "key": "value"
* @param obj
* @returns clean object
*/
function _cleanObject(obj) {
var object = {};
for (var key in obj) {
if (Object.keys(obj[key]).length===1) {
var val = obj[key][0];
if (val && val.length>0) { object[key] = val; }
} else if (Object.keys(obj[key]).length>1) {
object[key] = _cleanObject(obj[key]);
}
}
return object;
}
/**
* Creates a query string from an key-value object: ?key1=value1&key2=value2
* @param params
* @returns {String}
*/
function _createQueryList(params) {
var query = "?";
for (var key in params) {
query += key + "=" + params[key] + "&";
}
return query.slice(0, -1);
}
/**
* TODO
* @param router
* @returns api compatible router object
*/
function _createRouterNode(router) {
router = _cleanObject(router);
var node = {
"api_rev": "1.0",
"type": "router",
"hostname": router.hostname,
"ctime" : moment.unix(router.create_date).utc(),
"mtime" : moment().utc(),
"lat": parseFloat(router.latitude),
"lon": parseFloat(router.longitude),
"community": "Freifunk/Franken",
"attributes": {
"netmon": {
"id": router.router_id,
"url": settings.baseUrl + "/router.php?router_id=" + router.router_id,
}
}
};
if (router.description && router.description.length>0) { node.site = router.description; }
return node;
}
/** **************************************************************************
* get all nodes
*/
app.get('/nodes', function(req, res) {
console.log("REQUEST /nodes" + _createQueryList(req.query));
var routerlist = [];
//Filter "unwanted" url-parameters
if (req.query.limit !== undefined) {
return _showError(res, 400, "invalid parameter", "the parameter 'limit' is not allowed because it is used internaly");
//alternative: delete req.query['limit'];
}
if (req.query.offset !== undefined) {
return _showError(res, 400, "invalid parameter", "the parameter 'offset' is not allowed because it is used internaly");
//alternative: delete req.query['offset'];
}
var queue = async.queue(function(offset, callback) {
var parameterList = _createQueryList(req.query);
parameterList = (parameterList.length > 0) ? parameterList + "&" : "?";
var url = settings.baseUrl + "/api/rest/routerlist" + parameterList + "sort_by=router_id&offset=" + offset + "&limit=" + settings.apiMaxPageLimit;
console.log("get data from netmon: " + url);
rest.get(url).once('success', function(data, response) {
try {
if (!data.netmon_response || !data.netmon_response.routerlist) {
throw _showError(res, 500, "data.netmon_response.routerlist is undefined", "here was an error loading data from url: " + url);
}
//routerlist.push(data.netmon_response.routerlist[0].router);
var rs = data.netmon_response.routerlist[0].router;
if (rs !== undefined) {
rs.forEach(function(router) {
routerlist.push(router);
});
}
callback(offset);
} catch (err) {
console.error("ERROR: ", err);
}
});
}, settings.apiMaxParallelRequests);
//When the queue is emptied we want to check if we're done
queue.drain = function(err) {
//TODO error handling
var nodes = [];
routerlist.forEach(function(router) {
var node = _createRouterNode(router);
node.attributes.user = _cleanObject(router.user[0]);
node.attributes.chipset = _cleanObject(router.chipset[0]);
node.attributes.statusdata = _cleanObject(router.statusdata[0]);
nodes.push(node);
});
res.json(nodes);
console.log("FINISHED delivering list with " + nodes.length + " nodes\n");
};
rest.get(settings.baseUrl + "/api/rest/routerlist?limit=0").once('success', function(data, response) {
var avlNodeCount = data.netmon_response.routerlist[0].$.total_count;
var n = 0;
while ( n < avlNodeCount) {
queue.push(n);
n += settings.apiMaxPageLimit;
}
var remnant = avlNodeCount-n;
if (remnant > 0) queue.push(remnant);
});
});
/** **************************************************************************
* get node data by (netmon) id
*/
app.get('/node/:id', function(req, res) {
console.log("REQUEST /node/" + req.params.id);
var router = null;
var interfaces = null;
async.parallel([
function(callback) {
var queryUrl = settings.baseUrl + "/api/rest/router/" + req.params.id;
console.log("get data from netmon: " + queryUrl);
rest.get(queryUrl).once('success', function(data, response) {
if (data.netmon_response === undefined || data.netmon_response.router === undefined) {
return _showError(res, 404, "not_found", data.netmon_response.request[0].error_message[0] || data);
}
router = data.netmon_response.router[0];
callback();
}).once('fail', function(data, response) {
return _showError(res, 404, "not_found", data.netmon_response.request[0].error_message[0] || data);
});
}
/*TODO get more node information, function(callback) { ... } */
], function(err) {
//TODO error handling
var node = _createRouterNode(router);
res.json(node);
console.log("FINISHED delivering node data\n");
});
});
//IP logging
//app.use(express.logger());
//start API server
app.listen(settings.port);
console.log("server started with port:", settings.port);