RestAPI.h 16.4 KB
Newer Older
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
/*
 * RestAPI.h
 *
 *  Created on: 22.05.2019
 *      Author: Micha Mueller
 */

#ifndef DCDBPUSHER_RESTAPI_H_
#define DCDBPUSHER_RESTAPI_H_

#include "RESTHttpsServer.h"

#include <boost/asio.hpp>

#include "includes/PluginDefinitions.h"
#include "../analytics/AnalyticsManager.h"
#include "mqttchecker.h"
#include "MQTTPusher.h"

#define endpointArgs http::response<http::string_body>& res, queries_t& queries
#define stdBind(fun) std::bind(&RestAPI::fun, \
          this, \
          std::placeholders::_1, \
          std::placeholders::_2)

class RestAPI : public RESTHttpsServer {
public:
    RestAPI(serverSettings_t settings,
            pluginVector_t& plugins,
            MQTTPusher* mqttPusher,
            AnalyticsManager* manager,
            boost::asio::io_service& io);

    virtual ~RestAPI() {}

    //TODO rewrite help-section + README + endpoint docs once finished
    // String used as a response for the REST GET /help command
    const string restCheatSheet = "dcdbpusher RESTful API cheatsheet:\n"
                                  " -GET:  /help     This help message\n"
                                  "        /analytics/help\n"
                                  "                  An help message for data analytics commands\n"
                                  "        /plugins  List of currently loaded plugins (Discovery)\n"
                                  "        /[plugin]/sensors\n"
                                  "                  List of currently running sensors which belong\n"
                                  "                  to the specified plugin (Discovery)\n"
                                  "        /[plugin]/[sensor]/avg?interval=[timeInSec]\n"
                                  "                  Average of last sensor readings from the last\n"
                                  "                  [interval] seconds or of all cached readings\n"
                                  "                  if no interval is given\n"
                                  " -PUT:  /[plugin]/[start|stop|reload]\n"
                                  "                  Start/stop the sensors of the plugin or\n"
                                  "                  reload the plugin configuration\n"
                                  "\n";

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
    // String used as a response for the REST GET /help command
    const string anRestCheatSheet = "dcdbpusher analytics RESTful API cheatsheet:\n"
                                    " -GET:  /analytics/plugins  List of currently loaded plugins (Discovery)\n"
                                    "        /analytics/[plugin]/analyzers\n"
                                    "                  List of running analyzers in the specified\n"
                                    "                  data analytics plugin\n"
                                    "        /analytics/[plugin]/[analyzer]/sensors\n"
                                    "                  List of currently running sensors which belong\n"
                                    "                  to the specified data analytics plugin (Discovery)\n"
                                    "        /analytics/[plugin]/[analyzer]/units\n"
                                    "                  List of units to which sensors are associated in the\n"
                                    "                  specified data analytics plugin (Discovery)\n"
                                    " -PUT:  /analytics/[plugin]/[analyzer]/[start|stop|reload]\n"
                                    "                  Start/stop the analyzers of the plugin or\n"
                                    "                  reload the plugin configuration\n"
                                    "        /analytics/[plugin]/[analyzer]/compute\n"
                                    "                  Perform computation of the given analyzer\n"
                                    "                  in real-time. A \"unit\" query, specifying\n"
                                    "                  the target unit must be included\n"
                                    "        /analytics/[plugin]/[analyzer]/[action]\n"
                                    "                  Perform plugin-specific actions\n"
                                    "                  (refer to documentation)\n"
                                    "\n"
                                    "All resources have to be prepended by host:port.\n"
                                    "A query can be appended as ?query=[value] at the end. Multiple queries\n"
                                    "need to be separated by semicolons(';')\n";

82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
private:

    /**
     * GET "/analytics/help"
     *
     * @brief Return a cheatsheet of available REST API endpoints specific for
     *        the analytics manager.
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
     * Required |  -      |        -             |      -
     * Optional |  -      |        -             |      -
     */
    void GET_analytics_help(endpointArgs);

    /**
     * GET "/analytics/plugins"
     *
Micha Mueller's avatar
Micha Mueller committed
100
     * @brief (Discovery) List all currently loaded data analytic plugins.
101
102
103
104
105
106
107
108
109
110
111
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
     * Required |  -      |        -             |      -
     * Optional | json    | true                 | format response as json
     */
    void GET_analytics_plugins(endpointArgs);

    /**
     * GET "/analytics/sensors"
     *
Micha Mueller's avatar
Micha Mueller committed
112
     * @brief (Discovery) List all sensors of a plugin.
113
114
115
116
117
118
119
120
121
122
123
124
125
126
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
     * Required | plugin  | all analyzer plugin  | specify the plugin
     *          |         | names                |
     * Optional | analyzer| all analyzers of a   | restrict sensors list to an
     *          |         | plugin               | analyzer
     *          | json    | true                 | format response as json
     */
    void GET_analytics_sensors(endpointArgs);

    /**
     * GET "/analytics/units"
     *
Micha Mueller's avatar
Micha Mueller committed
127
     * @brief (Discovery) List all units of a plugin.
128
129
130
131
132
133
134
135
136
137
138
139
140
141
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
     * Required | plugin  | all analyzer plugin  | specify the plugin
     *          |         | names                |
     * Optional | analyzer| all analyzers of a   | restrict unit list to an
     *          |         | plugin               | analyzer
     *          | json    | true                 | format response as json
     */
    void GET_analytics_units(endpointArgs);

    /**
     * GET "/analytics/analyzers"
     *
Micha Mueller's avatar
Micha Mueller committed
142
     * @brief (Discovery) List all active analyzers of a plugin.
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
200
201
202
203
204
205
206
207
208
209
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
     * Required | plugin  | all analyzer plugin  | specify the plugin
     *          |         | names                |
     * Optional | json    | true                 | format response as json
     */
    void GET_analytics_analyzers(endpointArgs);

    /**
     * GET "/help"
     *
     * @brief Return a cheatsheet of possible REST API endpoints.
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
     * Required |  -      |        -             |      -
     * Optional |  -      |        -             |      -
     */
    void GET_help(endpointArgs);

    /**
     * GET "/plugins"
     *
     * @brief List all loaded dcdbpusher plugins.
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
     * Required |  -      |        -             |      -
     * Optional | json    | true                 | format response as json
     */
    void GET_plugins(endpointArgs);

    /**
     * GET "/sensors"
     *
     * @brief List all sensors of a specific plugin.
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
     * Required | plugin  | all plugin names     | specify the plugin
     * Optional | json    | true                 | format response as json
     */
    void GET_sensors(endpointArgs);

    /**
     * GET "/average"
     *
     * @brief Get the average of the last readings of a sensor.
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
     * Required | plugin  | all plugin names     | specify the plugin
     *          | sensor  | all sensor names of  | specify the sensor within the
     *          |         | the plugin or the    | plugin
     *          |         | analytics manager    |
     * Optional | interval| number of seconds    | use only readings more recent
     *          |         |                      | than (now - interval) for
     *          |         |                      | average calculation
     */
    void GET_average(endpointArgs);

/******************************************************************************/

    /**
     * PUT "/analytics/start"
     *
Micha Mueller's avatar
Micha Mueller committed
210
211
     * @brief Start all or only a specific plugin. Or only start a specific
     *        streaming analyzer within a specific plugin.
212
213
214
215
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
     * Required |  -      |        -             |      -
Micha Mueller's avatar
Micha Mueller committed
216
217
218
219
220
221
     * Optional | plugin  | all analyzer plugin  | only start the specified
     *          |         | names                | plugin
     *          | analyzer| all analyzers of a   | only start the specified
     *          |         | plugin               | analyzer. Requires a plugin
     *          |         |                      | to be specified. Limited to
     *          |         |                      | streaming analyzers.
222
223
224
225
226
227
     */
    void PUT_analytics_start(endpointArgs);

    /**
     * PUT "/analytics/stop"
     *
Micha Mueller's avatar
Micha Mueller committed
228
229
     * @brief Stop all or only a specific plugin. Or only stop a specific
     *        streaming analyzer within a plugin.
230
231
232
233
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
     * Required |  -      |        -             |      -
Micha Mueller's avatar
Micha Mueller committed
234
235
236
237
238
239
     * Optional | plugin  | all analyzer plugin  | only stop the specified
     *          |         | names                | plugin
     *          | analyzer| all analyzers of a   | only stop the specified
     *          |         | plugin               | analyzer. Requires a plugin
     *          |         |                      | to be specified. Limited to
     *          |         |                      | streaming analyzers.
240
241
242
243
244
245
     */
    void PUT_analytics_stop(endpointArgs);

    /**
     * PUT "/analytics/reload"
     *
Micha Mueller's avatar
Micha Mueller committed
246
247
     * @brief Reload configuration and initialization of all or only a specific
     *        analytics plugin.
248
249
250
251
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
     * Required |  -      |        -             |      -
Micha Mueller's avatar
Micha Mueller committed
252
253
     * Optional | plugin  | all analyzer plugin  | reload only the specified
     *          |         | names                | plugin
254
255
256
257
258
259
     */
    void PUT_analytics_reload(endpointArgs);

    /**
     * PUT "/analytics/compute"
     *
Micha Mueller's avatar
Micha Mueller committed
260
261
262
     * @brief Query the given analyzer for a certain input unit. Intended for
     *        "on-demand" analyzers, but works with "streaming" analyzers as
     *        well.
263
264
265
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
Micha Mueller's avatar
Micha Mueller committed
266
267
268
269
270
271
     * Required | plugin  | all analyzer plugin  | select plugin
     *          |         | names                |
     *          | analyzer| all analyzers of a   | select analyzer
     *          |         | plugin               |
     * Optional | unit    | all units of a plugin| select target unit
     *          | json    | true                 | format response as json
272
273
274
275
276
277
     */
    void PUT_analytics_compute(endpointArgs);

    /**
     * PUT "/analytics/analyzer"
     *
Micha Mueller's avatar
Micha Mueller committed
278
     * @brief Perform a custom REST PUT action defined at analyzer level.
279
280
281
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
Micha Mueller's avatar
Micha Mueller committed
282
283
284
285
286
287
288
289
     * Required | plugin  | all analyzer plugin  | select plugin
     *          |         | names                |
     *          | action  | see analyzer         | select custom action
     *          |         | documentation        |
     *          | custom action may require more queries!
     * Optional | analyzer| all analyzers of a   | select analyzer
     *          |         | plugin               |
     *          | custom action may allow for more queries!
290
291
292
293
294
295
     */
    void PUT_analytics_analyzer(endpointArgs);

    /**
     * PUT "/start"
     *
Micha Mueller's avatar
Micha Mueller committed
296
     * @brief Start a plugin.
297
298
299
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
Micha Mueller's avatar
Micha Mueller committed
300
     * Required | plugin  | all plugin names     | specify the plugin
301
302
303
304
305
306
307
     * Optional |  -      |        -             |      -
     */
    void PUT_start(endpointArgs);

    /**
     * PUT "/stop"
     *
Micha Mueller's avatar
Micha Mueller committed
308
     * @brief Stop a plugin.
309
310
311
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
Micha Mueller's avatar
Micha Mueller committed
312
     * Required | plugin  | all plugin names     | specify the plugin
313
314
315
316
317
318
319
     * Optional |  -      |        -             |      -
     */
    void PUT_stop(endpointArgs);

    /**
     * PUT "/reload"
     *
Micha Mueller's avatar
Micha Mueller committed
320
     * @brief Reload a plugin's configuration (includes plugin restart).
321
322
323
324
325
326
327
328
329
330
     *
     * Queries  | key     | possible values      | explanation
     * -------------------------------------------------------------------------
     * Required | plugin  | all plugin names     | specify the plugin
     * Optional |  -      |        -             |      -
     */
    void PUT_reload(endpointArgs);

/******************************************************************************/

Micha Mueller's avatar
Micha Mueller committed
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
    // Utility method to check if a plugin query was given.
    // Prepares the response accordingly to continue execution on success or
    // immediately return on failure.
    // Return true if plugin was given, false otherwise.
    inline bool hasPlugin(const std::string& plugin, http::response<http::string_body>& res) {
        if (plugin == "") {
            const std::string err = "Request malformed: plugin query missing";
            RESTAPILOG(error) << err;
            res.body() = err;
            res.result(http::status::bad_request);
            return false;
        } else {
            res.body() = "Plugin not found!\n";
            res.result(http::status::not_found);
            return true;
        }
    }

349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
    // Utility method to check the status of the analytics manager.
    // Return true if loaded, false otherwise.
    inline bool managerLoaded(http::response<http::string_body>& res) {
        if (_manager->getStatus() != AnalyticsManager::LOADED) {
            const std::string err = "AnalyticsManager is not loaded!";
            RESTAPILOG(error) << err;
            res.body() = err;
            res.result(http::status::internal_server_error);
            return false;
        }
        return true;
    }

    // Utility method to retrieve the value for a key-query from queries.
    // Return the associated value if found or "" otherwise.
    inline std::string getQuery(const std::string& key, queries_t& queries) {
        try {
            return queries.at(key);
        } catch (const std::out_of_range&) {
            //fall through
        }
        return "";
    }

    // Utility method to remove all MQTT topics associated to a plugin from the used set
    void removeTopics(dl_t p);

    // Utility method to check for the validity of all MQTT topics in a plugin
    bool checkTopics(dl_t p);

    pluginVector_t& _plugins;
    MQTTPusher* _mqttPusher;
    AnalyticsManager* _manager;
    boost::asio::io_service& _io;
};

#endif /* DCDBPUSHER_RESTAPI_H_ */