forked from SaftigeKumquat/Bombay-Crushed
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lfcli.js
183 lines (162 loc) · 5.45 KB
/
lfcli.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
/** @file
* This module provides several utilities to easier access
* the lfapi.
*
* This is meant to be used as a module in nodejs, so use
* @code
* var lfcli = require('lfcli.js')
* @endcode
*/
var http = require('http');
var querystring = require('querystring');
// load configuration
var config = require('./config.js');
var logger = require('./logger.js');
/// Define base URL of LQFB backend
var baseurl = config.baseurl
/**
* Build up the request options for the given path.
*
* @param path The query to perform as defined in http://dev.liquidfeedback.org/trac/lf/wiki/API.
* @param args A dictionary of query arguments
* @param state The current HTTP requests state object.
* Used for session information
*/
var buildRequestOptions = function(path, args, state, isPostRequest) {
var options = {
host: baseurl.host,
port: baseurl.port
};
if(path) {
if(baseurl.path && typeof(baseurl.path) === 'string') {
// make sure there is a dash in between
if(path.charAt(0) === '/' || baseurl.path.charAt(baseurl.path.length-1) === '/') {
options.path = baseurl.path + path;
} else {
options.path = baseurl.path + '/' + path;
}
} else {
options.path = path;
}
}
if(args) {
if(state && state.session_key()) {
args['session_key'] = state.session_key()
}
var argsstring = querystring.stringify(args)
options.path += '?' + argsstring;
//Handle POST requests
if(isPostRequest){
options.method = 'POST';
//Set Content-Lenght header on POST requests
if(!options.headers) options.headers={};
options.headers['Content-Length'] = argsstring.length;
}
}
return options;
}
/**
* Perform a query against the Liquid Feedback API Server.
*
* The function will automaticall check for HTTP-Errors, parse the JSON returned by the server and
* invoke the given handler function.
*
* In case of insufficient priviledges this function will trigger a redirection to the login page.
*
* @param path The query to perform as defined in http://dev.liquidfeedback.org/trac/lf/wiki/API.
* @param args Any arguments required to perform the query (JS Object as Key-Value-Map)
* @param state The current HTTP requests state object. Used for session and error handling.
* @param handler The function to handle the JSON object returned by the API Server in response to the query.
* @return The ClientResponseObject given by http(s).request.
*/
exports.query = function(path, args, state, handler) {
var options = buildRequestOptions(path, args, state);
var extended_handler = function(res) {
if(res.statusCode != 200) {
console.error('Request failed: ' + res.statusCode);
return;
}
// aggregate result body
var body = '';
res.on('data', function(chunk) {
body += chunk;
});
// when everything is aggregated, part body and invoke handlers
res.on('end', function() {
// TODO handle parsing errors
var answer = JSON.parse(body);
if(!answer.status || answer.status !== 'ok') {
if(answer.status && answer.status === 'forbidden') {
state.sendToLogin();
}
console.warn('STATUS: ' + answer.status + ' - Error String: "' + answer.error + '" - Query was: ' + path + ' ' + JSON.stringify(args));
}
// TODO different handler in case of errors
handler(answer);
});
}
return http.get(options, extended_handler).on('error', function(e) {
console.error("Got error: " + e.message);
});
};
/**
* Perform an action agains the Liquid Feedback API Server.
*
* The function will automaticall check for HTTP-Errors, parse the JSON returned by the server and
* invoke the given handler function.
*
* In case of insufficient priviledges this function will trigger a redirection to the login page.
*
* @param path The action to perform as defined in http://dev.liquidfeedback.org/trac/lf/wiki/API.
* @param args Any arguments required to perform the actions (JS Object as Key-Value-Map)
* @param state The current HTTP requests state object. Used for session and error handling.
* @param handler The function to handle the JSON object returned by the API Server in response to the query.
* @return The ClientResponseObject given by http(s).request.
*/
exports.perform = function(path, args, state, handler) {
var options = buildRequestOptions(path, args, state, true);
var extended_handler = function(res) {
if(res.statusCode != 200) {
console.error('Request failed: ' + res.statusCode);
return;
}
// aggregate result body
var body = '';
res.on('data', function(chunk) {
body += chunk;
});
// when everything is aggregated, part body and invoke handlers
res.on('end', function() {
// TODO handle parsing errors
var answer = JSON.parse(body);
if(!answer.status || answer.status !== 'ok') {
if(answer.status && answer.status === 'forbidden') {
state.sendToLogin();
}
console.warn('STATUS: ' + answer.status + ' - Error String: "' + answer.error + '" - Query was: ' + path + ' ' + JSON.stringify(args));
}
// TODO different handler in case of errors
handler(answer);
});
}
var req = http.request(options, extended_handler).on('error', function(e) {
console.error("Got error: " + e.message);
});
req.write(querystring.stringify(args));
req.end();
return req;
};
/**
* Allow to update the Base URL.
*
* @param newbase JSON specification of the base URL as it would be expected by http(s).request().
*/
exports.setBaseURL = function(newbase) {
baseurl = newbase;
}
exports.getBaseURL = function() {
return {
'host': baseurl.host,
'port': baseurl.port
}
}