• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OpenLightingProject / ola / 16900099157

12 Aug 2025 05:43AM UTC coverage: 45.72% (-0.02%) from 45.742%
16900099157

Pull #2016

github

web-flow
Merge c368ef6ae into eaf937e80
Pull Request #2016: Bump actions/checkout from 4 to 5

7586 of 17462 branches covered (43.44%)

22424 of 49046 relevant lines covered (45.72%)

51.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/olad/OladHTTPServer.cpp
1
/*
2
 * This program is free software; you can redistribute it and/or modify
3
 * it under the terms of the GNU General Public License as published by
4
 * the Free Software Foundation; either version 2 of the License, or
5
 * (at your option) any later version.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU Library General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
15
 *
16
 * OladHTTPServer.cpp
17
 * Ola HTTP class
18
 * Copyright (C) 2005 Simon Newton
19
 */
20

21
#include <sys/time.h>
22
#include <iostream>
23
#include <string>
24
#include <vector>
25

26
#include "ola/ActionQueue.h"
27
#include "ola/Callback.h"
28
#include "ola/Constants.h"
29
#include "ola/DmxBuffer.h"
30
#include "ola/Logging.h"
31
#include "ola/StringUtils.h"
32
#include "ola/base/Version.h"
33
#include "ola/dmx/SourcePriorities.h"
34
#include "ola/network/NetworkUtils.h"
35
#include "ola/web/Json.h"
36
#include "olad/DmxSource.h"
37
#include "olad/HttpServerActions.h"
38
#include "olad/OladHTTPServer.h"
39
#include "olad/OlaServer.h"
40
#include "olad/Preferences.h"
41

42
namespace ola {
43

44
using ola::client::OlaDevice;
45
using ola::client::OlaInputPort;
46
using ola::client::OlaOutputPort;
47
using ola::client::OlaPlugin;
48
using ola::client::OlaPort;
49
using ola::client::OlaUniverse;
50
using ola::http::HTTPRequest;
51
using ola::http::HTTPResponse;
52
using ola::http::HTTPServer;
53
using ola::io::ConnectedDescriptor;
54
using ola::web::JsonArray;
55
using ola::web::JsonObject;
56
using std::cout;
57
using std::endl;
58
using std::ostringstream;
59
using std::string;
60
using std::vector;
61

62
const char OladHTTPServer::HELP_PARAMETER[] = "help";
63
const char OladHTTPServer::HELP_REDIRECTION[] = "?help=1";
64
const char OladHTTPServer::K_BACKEND_DISCONNECTED_ERROR[] =
65
    "Failed to send request, client isn't connected";
66
const char OladHTTPServer::K_PRIORITY_VALUE_SUFFIX[] = "_priority_value";
67
const char OladHTTPServer::K_PRIORITY_MODE_SUFFIX[] = "_priority_mode";
68

69
/**
70
 * @brief Create a new OLA HTTP server
71
 * @param export_map the ExportMap to display when /debug is called
72
 * @param options the OladHTTPServerOptions for the OLA HTTP server
73
 * @param client_socket A ConnectedDescriptor which is used to communicate with
74
 *   the server.
75
 * @param ola_server the OlaServer to use
76
 * @param iface the network interface to bind to
77
 */
78
OladHTTPServer::OladHTTPServer(ExportMap *export_map,
×
79
                               const OladHTTPServerOptions &options,
80
                               ConnectedDescriptor *client_socket,
81
                               OlaServer *ola_server,
82
                               const ola::network::Interface &iface)
×
83
    : OlaHTTPServer(options, export_map),
84
      m_client_socket(client_socket),
×
85
      m_client(client_socket),
×
86
      m_ola_server(ola_server),
×
87
      m_enable_quit(options.enable_quit),
×
88
      m_interface(iface),
×
89
      m_rdm_module(&m_server, &m_client) {
×
90
  // The main handlers
91
  RegisterHandler("/quit", &OladHTTPServer::DisplayQuit);
×
92
  RegisterHandler("/reload", &OladHTTPServer::ReloadPlugins);
×
93
  RegisterHandler("/reload_pids", &OladHTTPServer::ReloadPidStore);
×
94
  RegisterHandler("/new_universe", &OladHTTPServer::CreateNewUniverse);
×
95
  RegisterHandler("/modify_universe", &OladHTTPServer::ModifyUniverse);
×
96
  RegisterHandler("/set_plugin_state", &OladHTTPServer::SetPluginState);
×
97
  RegisterHandler("/set_dmx", &OladHTTPServer::HandleSetDmx);
×
98
  RegisterHandler("/get_dmx", &OladHTTPServer::GetDmx);
×
99

100
  // json endpoints for the new UI
101
  RegisterHandler("/json/server_stats", &OladHTTPServer::JsonServerStats);
×
102
  RegisterHandler("/json/universe_plugin_list",
×
103
                  &OladHTTPServer::JsonUniversePluginList);
104
  RegisterHandler("/json/plugin_info", &OladHTTPServer::JsonPluginInfo);
×
105
  RegisterHandler("/json/get_ports", &OladHTTPServer::JsonAvailablePorts);
×
106
  RegisterHandler("/json/universe_info", &OladHTTPServer::JsonUniverseInfo);
×
107

108
  // these are the static files for the old UI
109
  m_server.RegisterFile("/blank.gif", HTTPServer::CONTENT_TYPE_GIF);
×
110
  m_server.RegisterFile("/button-bg.png", HTTPServer::CONTENT_TYPE_PNG);
×
111
  m_server.RegisterFile("/custombutton.css", HTTPServer::CONTENT_TYPE_CSS);
×
112
  m_server.RegisterFile("/editortoolbar.png", HTTPServer::CONTENT_TYPE_PNG);
×
113
  m_server.RegisterFile("/expander.png", HTTPServer::CONTENT_TYPE_PNG);
×
114
  m_server.RegisterFile("/handle.vertical.png", HTTPServer::CONTENT_TYPE_PNG);
×
115
  m_server.RegisterFile("/loader.gif", HTTPServer::CONTENT_TYPE_GIF);
×
116
  m_server.RegisterFile("/loader-mini.gif", HTTPServer::CONTENT_TYPE_GIF);
×
117
  m_server.RegisterFile("/logo.png", HTTPServer::CONTENT_TYPE_PNG);
×
118
  m_server.RegisterFile("/logo-mini.png", HTTPServer::CONTENT_TYPE_PNG);
×
119
  m_server.RegisterFile("/mobile.html", HTTPServer::CONTENT_TYPE_HTML);
×
120
  m_server.RegisterFile("/mobile.js", HTTPServer::CONTENT_TYPE_JS);
×
121
  m_server.RegisterFile("/ola.html", HTTPServer::CONTENT_TYPE_HTML);
×
122
  m_server.RegisterFile("/ola.js", HTTPServer::CONTENT_TYPE_JS);
×
123
  m_server.RegisterFile("/tick.gif", HTTPServer::CONTENT_TYPE_GIF);
×
124
  m_server.RegisterFile("/toolbar-bg.png", HTTPServer::CONTENT_TYPE_PNG);
×
125
  m_server.RegisterFile("/toolbar.css", HTTPServer::CONTENT_TYPE_CSS);
×
126
  m_server.RegisterFile("/toolbar_sprites.png", HTTPServer::CONTENT_TYPE_PNG);
×
127
  m_server.RegisterFile("/vertical.gif", HTTPServer::CONTENT_TYPE_GIF);
×
128
  m_server.RegisterFile("/warning.png", HTTPServer::CONTENT_TYPE_PNG);
×
129
  m_server.RegisterFile("/", "landing.html", HTTPServer::CONTENT_TYPE_HTML);
×
130

131
  // these are the static files for the new UI
132
  m_server.RegisterFile(
×
133
      "/new/",
134
      "/new/index.html",
135
      HTTPServer::CONTENT_TYPE_HTML);
136
  m_server.RegisterFile(
×
137
      "/new/views/overview.html",
138
      HTTPServer::CONTENT_TYPE_HTML);
139
  m_server.RegisterFile(
×
140
      "/new/views/plugins.html",
141
      HTTPServer::CONTENT_TYPE_HTML);
142
  m_server.RegisterFile(
×
143
      "/new/views/plugin-info.html",
144
      HTTPServer::CONTENT_TYPE_HTML);
145
  m_server.RegisterFile(
×
146
      "/new/views/universe-overview.html",
147
      HTTPServer::CONTENT_TYPE_HTML);
148
  m_server.RegisterFile(
×
149
      "/new/views/universe-add.html",
150
      HTTPServer::CONTENT_TYPE_HTML);
151
  m_server.RegisterFile(
×
152
      "/new/views/universe-header.html",
153
      HTTPServer::CONTENT_TYPE_HTML);
154
  m_server.RegisterFile(
×
155
      "/new/views/universe-keypad.html",
156
      HTTPServer::CONTENT_TYPE_HTML);
157
  m_server.RegisterFile(
×
158
      "/new/views/universe-patch.html",
159
      HTTPServer::CONTENT_TYPE_HTML);
160
  m_server.RegisterFile(
×
161
      "/new/views/universe-settings.html",
162
      HTTPServer::CONTENT_TYPE_HTML);
163
  m_server.RegisterFile(
×
164
      "/new/views/universe-faders.html",
165
      HTTPServer::CONTENT_TYPE_HTML);
166
  m_server.RegisterFile(
×
167
      "/new/views/universes.html",
168
      HTTPServer::CONTENT_TYPE_HTML);
169
  m_server.RegisterFile(
×
170
      "/new/views/universe-rdm.html",
171
      HTTPServer::CONTENT_TYPE_HTML);
172
  m_server.RegisterFile(
×
173
      "/new/js/app.min.js",
174
      HTTPServer::CONTENT_TYPE_JS);
175
  m_server.RegisterFile(
×
176
      "/new/js/app.min.js.map",
177
      HTTPServer::CONTENT_TYPE_OCT);
178
  m_server.RegisterFile(
×
179
      "/new/libs/jquery/js/jquery.min.js",
180
      HTTPServer::CONTENT_TYPE_JS);
181
  m_server.RegisterFile(
×
182
      "/new/libs/angular-route/js/angular-route.min.js",
183
      HTTPServer::CONTENT_TYPE_JS);
184
  m_server.RegisterFile(
×
185
      "/new/libs/angular/js/angular.min.js",
186
      HTTPServer::CONTENT_TYPE_JS);
187
  m_server.RegisterFile(
×
188
      "/new/libs/marked/js/marked.min.js",
189
      HTTPServer::CONTENT_TYPE_JS);
190
  m_server.RegisterFile(
×
191
      "/new/libs/angular-marked/js/angular-marked.min.js",
192
      HTTPServer::CONTENT_TYPE_JS);
193
  m_server.RegisterFile(
×
194
      "/new/libs/bootstrap/js/bootstrap.min.js",
195
      HTTPServer::CONTENT_TYPE_JS);
196
  m_server.RegisterFile(
×
197
      "/new/libs/bootstrap/fonts/glyphicons-halflings-regular.woff",
198
      HTTPServer::CONTENT_TYPE_OCT);
199
  m_server.RegisterFile(
×
200
      "/new/libs/bootstrap/fonts/glyphicons-halflings-regular.svg",
201
      HTTPServer::CONTENT_TYPE_OCT);
202
  m_server.RegisterFile(
×
203
      "/new/libs/bootstrap/fonts/glyphicons-halflings-regular.ttf",
204
      HTTPServer::CONTENT_TYPE_OCT);
205
  m_server.RegisterFile(
×
206
      "/new/libs/bootstrap/fonts/glyphicons-halflings-regular.eot",
207
      HTTPServer::CONTENT_TYPE_OCT);
208
  m_server.RegisterFile(
×
209
      "/new/libs/bootstrap/fonts/glyphicons-halflings-regular.woff2",
210
      HTTPServer::CONTENT_TYPE_OCT);
211
  m_server.RegisterFile(
×
212
      "/new/css/style.min.css",
213
      HTTPServer::CONTENT_TYPE_CSS);
214
  m_server.RegisterFile(
×
215
      "/new/libs/bootstrap/css/bootstrap.min.css",
216
      HTTPServer::CONTENT_TYPE_CSS);
217
  m_server.RegisterFile(
×
218
      "/new/img/logo.png",
219
      HTTPServer::CONTENT_TYPE_PNG);
220
  m_server.RegisterFile(
×
221
      "/new/img/light_bulb.png",
222
      HTTPServer::CONTENT_TYPE_PNG);
223
  m_server.RegisterFile(
×
224
      "/new/img/light_bulb_off.png",
225
      HTTPServer::CONTENT_TYPE_PNG);
226
  m_server.RegisterFile(
×
227
      "/new/img/logo-mini.png",
228
      HTTPServer::CONTENT_TYPE_PNG);
229
  m_server.RegisterFile(
×
230
      "/new/img/logo-mini@2x.png",
231
      HTTPServer::CONTENT_TYPE_PNG);
232

233
  // Favicons for the new UI
234
  m_server.RegisterFile(
×
235
      "/new/img/favicons/android-chrome-144x144.png",
236
      HTTPServer::CONTENT_TYPE_PNG);
237
  m_server.RegisterFile(
×
238
      "/new/img/favicons/android-chrome-192x192.png",
239
      HTTPServer::CONTENT_TYPE_PNG);
240
  m_server.RegisterFile(
×
241
      "/new/img/favicons/android-chrome-36x36.png",
242
      HTTPServer::CONTENT_TYPE_PNG);
243
  m_server.RegisterFile(
×
244
      "/new/img/favicons/android-chrome-48x48.png",
245
      HTTPServer::CONTENT_TYPE_PNG);
246
  m_server.RegisterFile(
×
247
      "/new/img/favicons/android-chrome-72x72.png",
248
      HTTPServer::CONTENT_TYPE_PNG);
249
  m_server.RegisterFile(
×
250
      "/new/img/favicons/android-chrome-96x96.png",
251
      HTTPServer::CONTENT_TYPE_PNG);
252
  m_server.RegisterFile(
×
253
      "/new/img/favicons/apple-touch-icon-114x114.png",
254
      HTTPServer::CONTENT_TYPE_PNG);
255
  m_server.RegisterFile(
×
256
      "/new/img/favicons/apple-touch-icon-120x120.png",
257
      HTTPServer::CONTENT_TYPE_PNG);
258
  m_server.RegisterFile(
×
259
      "/new/img/favicons/apple-touch-icon-144x144.png",
260
      HTTPServer::CONTENT_TYPE_PNG);
261
  m_server.RegisterFile(
×
262
      "/new/img/favicons/apple-touch-icon-152x152.png",
263
      HTTPServer::CONTENT_TYPE_PNG);
264
  m_server.RegisterFile(
×
265
      "/new/img/favicons/apple-touch-icon-180x180.png",
266
      HTTPServer::CONTENT_TYPE_PNG);
267
  m_server.RegisterFile(
×
268
      "/new/img/favicons/apple-touch-icon-57x57.png",
269
      HTTPServer::CONTENT_TYPE_PNG);
270
  m_server.RegisterFile(
×
271
      "/new/img/favicons/apple-touch-icon-60x60.png",
272
      HTTPServer::CONTENT_TYPE_PNG);
273
  m_server.RegisterFile(
×
274
      "/new/img/favicons/apple-touch-icon-72x72.png",
275
      HTTPServer::CONTENT_TYPE_PNG);
276
  m_server.RegisterFile(
×
277
      "/new/img/favicons/apple-touch-icon-76x76.png",
278
      HTTPServer::CONTENT_TYPE_PNG);
279
  m_server.RegisterFile(
×
280
      "/new/img/favicons/apple-touch-icon-precomposed.png",
281
      HTTPServer::CONTENT_TYPE_PNG);
282
  m_server.RegisterFile(
×
283
      "/new/img/favicons/apple-touch-icon.png",
284
      HTTPServer::CONTENT_TYPE_PNG);
285
  m_server.RegisterFile(
×
286
      "/new/img/favicons/apple-touch-startup-image-1182x2208.png",
287
      HTTPServer::CONTENT_TYPE_PNG);
288
  m_server.RegisterFile(
×
289
      "/new/img/favicons/apple-touch-startup-image-1242x2148.png",
290
      HTTPServer::CONTENT_TYPE_PNG);
291
  m_server.RegisterFile(
×
292
      "/new/img/favicons/apple-touch-startup-image-1496x2048.png",
293
      HTTPServer::CONTENT_TYPE_PNG);
294
  m_server.RegisterFile(
×
295
      "/new/img/favicons/apple-touch-startup-image-1536x2008.png",
296
      HTTPServer::CONTENT_TYPE_PNG);
297
  m_server.RegisterFile(
×
298
      "/new/img/favicons/apple-touch-startup-image-320x460.png",
299
      HTTPServer::CONTENT_TYPE_PNG);
300
  m_server.RegisterFile(
×
301
      "/new/img/favicons/apple-touch-startup-image-640x1096.png",
302
      HTTPServer::CONTENT_TYPE_PNG);
303
  m_server.RegisterFile(
×
304
      "/new/img/favicons/apple-touch-startup-image-640x920.png",
305
      HTTPServer::CONTENT_TYPE_PNG);
306
  m_server.RegisterFile(
×
307
      "/new/img/favicons/apple-touch-startup-image-748x1024.png",
308
      HTTPServer::CONTENT_TYPE_PNG);
309
  m_server.RegisterFile(
×
310
      "/new/img/favicons/apple-touch-startup-image-750x1294.png",
311
      HTTPServer::CONTENT_TYPE_PNG);
312
  m_server.RegisterFile(
×
313
      "/new/img/favicons/apple-touch-startup-image-768x1004.png",
314
      HTTPServer::CONTENT_TYPE_PNG);
315
  m_server.RegisterFile(
×
316
      "/new/img/favicons/browserconfig.xml",
317
      HTTPServer::CONTENT_TYPE_XML);
318
  m_server.RegisterFile(
×
319
      "/new/img/favicons/coast-228x228.png",
320
      HTTPServer::CONTENT_TYPE_PNG);
321
  m_server.RegisterFile(
×
322
      "/new/img/favicons/favicon-16x16.png",
323
      HTTPServer::CONTENT_TYPE_PNG);
324
  m_server.RegisterFile(
×
325
      "/new/img/favicons/favicon-230x230.png",
326
      HTTPServer::CONTENT_TYPE_PNG);
327
  m_server.RegisterFile(
×
328
      "/new/img/favicons/favicon-32x32.png",
329
      HTTPServer::CONTENT_TYPE_PNG);
330
  m_server.RegisterFile(
×
331
      "/new/img/favicons/favicon-96x96.png",
332
      HTTPServer::CONTENT_TYPE_PNG);
333
  m_server.RegisterFile(
×
334
      "/new/img/favicons/favicon.ico",
335
      HTTPServer::CONTENT_TYPE_ICO);
336
  m_server.RegisterFile(
×
337
      "/new/img/favicons/firefox_app_128x128.png",
338
      HTTPServer::CONTENT_TYPE_PNG);
339
  m_server.RegisterFile(
×
340
      "/new/img/favicons/firefox_app_512x512.png",
341
      HTTPServer::CONTENT_TYPE_PNG);
342
  m_server.RegisterFile(
×
343
      "/new/img/favicons/firefox_app_60x60.png",
344
      HTTPServer::CONTENT_TYPE_PNG);
345
  m_server.RegisterFile(
×
346
      "/new/img/favicons/manifest.json",
347
      HTTPServer::CONTENT_TYPE_JSON);
348
  m_server.RegisterFile(
×
349
      "/new/img/favicons/manifest.webapp",
350
      HTTPServer::CONTENT_TYPE_PLAIN);
351
  m_server.RegisterFile(
×
352
      "/new/img/favicons/mstile-144x144.png",
353
      HTTPServer::CONTENT_TYPE_PNG);
354
  m_server.RegisterFile(
×
355
      "/new/img/favicons/mstile-150x150.png",
356
      HTTPServer::CONTENT_TYPE_PNG);
357
  m_server.RegisterFile(
×
358
      "/new/img/favicons/mstile-310x150.png",
359
      HTTPServer::CONTENT_TYPE_PNG);
360
  m_server.RegisterFile(
×
361
      "/new/img/favicons/mstile-310x310.png",
362
      HTTPServer::CONTENT_TYPE_PNG);
363
  m_server.RegisterFile(
×
364
      "/new/img/favicons/mstile-70x70.png",
365
      HTTPServer::CONTENT_TYPE_PNG);
366
  m_server.RegisterFile(
×
367
      "/new/img/favicons/open-graph.png",
368
      HTTPServer::CONTENT_TYPE_PNG);
369
  m_server.RegisterFile(
×
370
      "/new/img/favicons/twitter.png",
371
      HTTPServer::CONTENT_TYPE_PNG);
372
  m_server.RegisterFile(
×
373
      "/new/img/favicons/yandex-browser-50x50.png",
374
      HTTPServer::CONTENT_TYPE_PNG);
375
  m_server.RegisterFile(
×
376
      "/new/img/favicons/yandex-browser-manifest.json",
377
      HTTPServer::CONTENT_TYPE_JSON);
378

379
  m_start_time_t = time(NULL);
×
380
}
×
381

382

383
/*
384
 * @brief Teardown
385
 */
386
OladHTTPServer::~OladHTTPServer() {
×
387
  if (m_client_socket) {
×
388
    m_server.SelectServer()->RemoveReadDescriptor(m_client_socket);
×
389
  }
390
  m_client.Stop();
×
391
  if (m_client_socket) {
×
392
    delete m_client_socket;
×
393
  }
394
}
×
395

396

397
/**
398
 * @brief Setup the OLA HTTP server
399
 * @return true if this worked, false otherwise.
400
 */
401
bool OladHTTPServer::Init() {
×
402
  if (!OlaHTTPServer::Init()) {
×
403
    return false;
404
  }
405

406
  if (!m_client.Setup()) {
×
407
    return false;
408
  }
409
  /*
410
  Setup disconnect notifications.
411
  m_socket->SetOnClose(
412
    ola::NewSingleCallback(this, &SimpleClient::SocketClosed));
413
  */
414
  m_server.SelectServer()->AddReadDescriptor(m_client_socket);
×
415
  return true;
×
416
}
417

418

419
/**
420
 * @brief Can be called while the HTTP server is running
421
 */
422
void OladHTTPServer::SetPidStore(const ola::rdm::RootPidStore *pid_store) {
×
423
  m_rdm_module.SetPidStore(pid_store);
×
424
}
×
425

426

427
/**
428
 * @brief Print the server stats JSON
429
 * @param request the HTTPRequest
430
 * @param response the HTTPResponse
431
 * @returns MHD_NO or MHD_YES
432
 */
433
int OladHTTPServer::JsonServerStats(const HTTPRequest*,
×
434
                                    HTTPResponse *response) {
435
  char start_time_str[50];
×
436
#ifdef _WIN32
437
  strftime(start_time_str, sizeof(start_time_str), "%c",
438
      localtime(&m_start_time_t));
439
#else
440
  struct tm start_time;
×
441
  localtime_r(&m_start_time_t, &start_time);
×
442
  strftime(start_time_str, sizeof(start_time_str), "%c", &start_time);
×
443
#endif  // _WIN32
444

445
  JsonObject json;
×
446
#ifdef OLA_SCREENSHOT_MODE
447
  json.Add("hostname", "***");
448
  json.Add("instance_name", "***");
449
  json.Add("config_dir", "***");
450
  json.Add("ip", "***.***.***.***");
451
  json.Add("broadcast", "***.***.***.***");
452
  json.Add("subnet", "***.***.***.***");
453
  json.Add("hw_address", "**:**:**:**:**:**");
454
#else
455
  json.Add("hostname", ola::network::FQDN());
×
456
  json.Add("instance_name", m_ola_server->InstanceName());
×
457
  json.Add("config_dir",
×
458
           m_ola_server->GetPreferencesFactory()->ConfigLocation());
×
459
  json.Add("ip", m_interface.ip_address.ToString());
×
460
  json.Add("broadcast", m_interface.bcast_address.ToString());
×
461
  json.Add("subnet", m_interface.subnet_mask.ToString());
×
462
  json.Add("hw_address", m_interface.hw_address.ToString());
×
463
#endif  // OLA_SCREENSHOT_MODE
464
  json.Add("version", ola::base::Version::GetVersion());
×
465
  json.Add("up_since", start_time_str);
×
466
  json.Add("quit_enabled", m_enable_quit);
×
467

468
  response->SetNoCache();
×
469
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
470
  int r = response->SendJson(json);
×
471
  delete response;
×
472
  return r;
×
473
}
×
474

475

476
/**
477
 * @brief Print the list of universes / plugins as a json string
478
 * @param request the HTTPRequest
479
 * @param response the HTTPResponse
480
 * @returns MHD_NO or MHD_YES
481
 */
482
int OladHTTPServer::JsonUniversePluginList(const HTTPRequest*,
×
483
                                           HTTPResponse *response) {
484
  m_client.FetchPluginList(
×
485
      NewSingleCallback(this,
486
                        &OladHTTPServer::HandlePluginList,
487
                        response));
488
  return MHD_YES;
×
489
}
490

491

492
/**
493
 * @brief Print the plugin info as a JSON string
494
 * @param request the HTTPRequest
495
 * @param response the HTTPResponse
496
 * @returns MHD_NO or MHD_YES
497
 */
498
int OladHTTPServer::JsonPluginInfo(const HTTPRequest *request,
×
499
                                   HTTPResponse *response) {
500
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
501
    return ServeUsage(response, "?id=[plugin]");
×
502
  }
503
  string val = request->GetParameter("id");
×
504
  int plugin_id;
×
505
  if (!StringToInt(val, &plugin_id)) {
×
506
    return ServeHelpRedirect(response);
×
507
  }
508

509
  m_client.FetchPluginDescription(
×
510
      (ola_plugin_id) plugin_id,
511
      NewSingleCallback(this,
512
                        &OladHTTPServer::HandlePartialPluginInfo,
513
                        response, plugin_id));
514
  return MHD_YES;
515
}
×
516

517

518
/**
519
 * @brief Return information about a universe
520
 * @param request the HTTPRequest
521
 * @param response the HTTPResponse
522
 * @returns MHD_NO or MHD_YES
523
 */
524
int OladHTTPServer::JsonUniverseInfo(OLA_UNUSED const HTTPRequest *request,
×
525
                                     HTTPResponse *response) {
526
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
527
    return ServeUsage(response, "?id=[universe]");
×
528
  }
529
  string uni_id = request->GetParameter("id");
×
530
  unsigned int universe_id;
×
531
  if (!StringToInt(uni_id, &universe_id)) {
×
532
    return ServeHelpRedirect(response);
×
533
  }
534

535
  m_client.FetchUniverseInfo(
×
536
      universe_id,
537
      NewSingleCallback(this,
538
                        &OladHTTPServer::HandleUniverseInfo,
539
                        response));
540

541
  return MHD_YES;
542
}
×
543

544

545
/**
546
 * @brief Return a list of unbound ports
547
 * @param request the HTTPRequest
548
 * @param response the HTTPResponse
549
 * @returns MHD_NO or MHD_YES
550
 */
551
int OladHTTPServer::JsonAvailablePorts(const HTTPRequest *request,
×
552
                                       HTTPResponse *response) {
553
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
554
    return ServeUsage(response, "? or ?id=[universe]");
×
555
  }
556
  string uni_id = request->GetParameter("id");
×
557

558
  if (uni_id.empty()) {
×
559
    // get all available ports
560
    m_client.FetchCandidatePorts(
×
561
        NewSingleCallback(this,
562
                          &OladHTTPServer::HandleCandidatePorts,
563
                          response));
564
  } else {
565
    unsigned int universe_id;
×
566
    if (!StringToInt(uni_id, &universe_id)) {
×
567
      return ServeHelpRedirect(response);
×
568
    }
569

570
    m_client.FetchCandidatePorts(
×
571
        universe_id,
572
        NewSingleCallback(this,
573
                          &OladHTTPServer::HandleCandidatePorts,
574
                          response));
575
  }
576
  return MHD_YES;
577
}
×
578

579

580
/**
581
 * @brief Create a new universe by binding one or more ports.
582
 * @param request the HTTPRequest
583
 * @param response the HTTPResponse
584
 * @returns MHD_NO or MHD_YES
585
 */
586
int OladHTTPServer::CreateNewUniverse(const HTTPRequest *request,
×
587
                                      HTTPResponse *response) {
588
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
589
    return ServeUsage(response,
×
590
                      "POST id=[universe], name=[name], add_ports=[a comma "
591
                      "separated list of port ids]");
592
  }
593
  string uni_id = request->GetPostParameter("id");
×
594
  string name = request->GetPostParameter("name");
×
595

596
  if (name.size() > K_UNIVERSE_NAME_LIMIT) {
×
597
    name = name.substr(K_UNIVERSE_NAME_LIMIT);
×
598
  }
599

600
  unsigned int universe_id;
×
601
  if (!StringToInt(uni_id, &universe_id)) {
×
602
    return ServeHelpRedirect(response);
×
603
  }
604

605
  ActionQueue *action_queue = new ActionQueue(
×
606
      NewSingleCallback(this,
607
                        &OladHTTPServer::CreateUniverseComplete,
608
                        response,
609
                        universe_id,
610
                        !name.empty()));
×
611

612
  // add patch actions here
613
  string add_port_ids = request->GetPostParameter("add_ports");
×
614
  AddPatchActions(action_queue, add_port_ids, universe_id, ola::client::PATCH);
×
615

616
  if (!name.empty()) {
×
617
    action_queue->AddAction(
×
618
        new SetNameAction(&m_client, universe_id, name, false));
×
619
  }
620

621
  action_queue->NextAction();
×
622
  return MHD_YES;
×
623
}
×
624

625

626
/**
627
 * @brief Modify an existing universe.
628
 * @param request the HTTPRequest
629
 * @param response the HTTPResponse
630
 * @returns MHD_NO or MHD_YES
631
 */
632
int OladHTTPServer::ModifyUniverse(const HTTPRequest *request,
×
633
                                   HTTPResponse *response) {
634
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
635
    return ServeUsage(response,
×
636
                      "POST id=[universe], name=[name], merge_mode=[HTP|LTP], "
637
                      "add_ports=[a comma separated list of port ids], "
638
                      "remove_ports=[a comma separated list of port ids]");
639
  }
640

641
  string uni_id = request->GetPostParameter("id");
×
642
  string name = request->GetPostParameter("name");
×
643
  string merge_mode = request->GetPostParameter("merge_mode");
×
644

645
  unsigned int universe_id;
×
646
  if (!StringToInt(uni_id, &universe_id)) {
×
647
    return ServeHelpRedirect(response);
×
648
  }
649

650
  if (name.empty()) {
×
651
    return m_server.ServeError(response, "No name supplied");
×
652
  }
653

654
  if (name.size() > K_UNIVERSE_NAME_LIMIT) {
×
655
    name = name.substr(K_UNIVERSE_NAME_LIMIT);
×
656
  }
657

658
  ActionQueue *action_queue = new ActionQueue(
×
659
      NewSingleCallback(this,
660
                        &OladHTTPServer::ModifyUniverseComplete,
661
                        response));
×
662

663
  action_queue->AddAction(
×
664
      new SetNameAction(&m_client, universe_id, name, true));
×
665

666
  if (merge_mode == "LTP" || merge_mode == "HTP") {
×
667
    OlaUniverse::merge_mode mode = (
×
668
        merge_mode == "LTP" ? OlaUniverse::MERGE_LTP : OlaUniverse::MERGE_HTP);
×
669
    action_queue->AddAction(
×
670
        new SetMergeModeAction(&m_client, universe_id, mode));
×
671
  }
672

673
  string remove_port_ids = request->GetPostParameter("remove_ports");
×
674
  AddPatchActions(action_queue, remove_port_ids, universe_id, client::UNPATCH);
×
675

676
  string add_port_ids = request->GetPostParameter("add_ports");
×
677
  AddPatchActions(action_queue, add_port_ids, universe_id, client::PATCH);
×
678

679
  AddPriorityActions(action_queue, request);
×
680

681
  action_queue->NextAction();
×
682
  return MHD_YES;
×
683
}
×
684

685
/**
686
 * @brief Set plugin state.
687
 * @param request the HTTPRequest
688
 * @param response the HTTPResponse
689
 * @returns MHD_NO or MHD_YES
690
 */
691
int OladHTTPServer::SetPluginState(const HTTPRequest *request,
×
692
                                   HTTPResponse *response) {
693
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
694
    return ServeUsage(response,
×
695
                      "POST state=[enable|disable], "
696
                      "plugin_id=[a plugin id]");
697
  }
698

699
  string state_string = request->GetPostParameter("state");
×
700

701
  bool state;
×
702
  if (!StringToBoolTolerant(state_string, &state)) {
×
703
    OLA_INFO << "Invalid state " << state_string;
×
704
    return ServeHelpRedirect(response);
×
705
  }
706

707
  string plugin_id_string = request->GetPostParameter("plugin_id");
×
708
  unsigned int plugin_id;
×
709
  if (!StringToInt(plugin_id_string, &plugin_id)) {
×
710
    OLA_INFO << "Invalid plugin id " << plugin_id_string;
×
711
    return ServeHelpRedirect(response);
×
712
  }
713

714
  m_client.SetPluginState(
×
715
      (ola_plugin_id) plugin_id,
716
      state,
717
      NewSingleCallback(this, &OladHTTPServer::HandleBoolResponse, response));
718

719
  return MHD_YES;
720
}
×
721

722

723
/**
724
 * @brief Handle the get DMX command
725
 * @param request the HTTPRequest
726
 * @param response the HTTPResponse
727
 * @returns MHD_NO or MHD_YES
728
 */
729
int OladHTTPServer::GetDmx(const HTTPRequest *request,
×
730
                           HTTPResponse *response) {
731
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
732
    return ServeUsage(response, "?u=[universe]");
×
733
  }
734
  string uni_id = request->GetParameter("u");
×
735
  unsigned int universe_id;
×
736
  if (!StringToInt(uni_id, &universe_id)) {
×
737
    return ServeHelpRedirect(response);
×
738
  }
739

740
  m_client.FetchDMX(
×
741
      universe_id,
742
      NewSingleCallback(this, &OladHTTPServer::HandleGetDmx, response));
743
  return MHD_YES;
744
}
×
745

746

747
/**
748
 * @brief Handle the set DMX command
749
 * @param request the HTTPRequest
750
 * @param response the HTTPResponse
751
 * @returns MHD_NO or MHD_YES
752
 */
753
int OladHTTPServer::HandleSetDmx(const HTTPRequest *request,
×
754
                                 HTTPResponse *response) {
755
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
756
    return ServeUsage(response,
×
757
        "POST u=[universe], d=[DMX data (a comma separated list of values)]");
758
  }
759
  string dmx_data_str = request->GetPostParameter("d");
×
760
  string uni_id = request->GetPostParameter("u");
×
761
  unsigned int universe_id;
×
762
  if (!StringToInt(uni_id, &universe_id)) {
×
763
    return ServeHelpRedirect(response);
×
764
  }
765

766
  DmxBuffer buffer;
×
767
  buffer.SetFromString(dmx_data_str);
×
768
  if (!buffer.Size()) {
×
769
    return m_server.ServeError(response, "Invalid DMX string");
×
770
  }
771

772
  ola::client::SendDMXArgs args(
×
773
      NewSingleCallback(this, &OladHTTPServer::HandleBoolResponse, response));
×
774
  m_client.SendDMX(universe_id, buffer, args);
×
775
  return MHD_YES;
776
}
×
777

778

779
/**
780
 * @brief Cause the server to shutdown
781
 * @param request the HTTPRequest
782
 * @param response the HTTPResponse
783
 * @returns MHD_NO or MHD_YES
784
 */
785
int OladHTTPServer::DisplayQuit(OLA_UNUSED const HTTPRequest *request,
×
786
                                HTTPResponse *response) {
787
  if (m_enable_quit) {
×
788
    response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
789
    response->Append("ok");
×
790
    m_ola_server->StopServer();
×
791
  } else {
792
    response->SetStatus(403);
×
793
    response->SetContentType(HTTPServer::CONTENT_TYPE_HTML);
×
794
    response->Append("<b>403 Unauthorized</b>");
×
795
  }
796
  response->SetNoCache();
×
797
  int r = response->Send();
×
798
  delete response;
×
799
  return r;
×
800
}
801

802

803
/**
804
 * @brief Reload all plugins
805
 * @param request the HTTPRequest
806
 * @param response the HTTPResponse
807
 * @returns MHD_NO or MHD_YES
808
 */
809
int OladHTTPServer::ReloadPlugins(const HTTPRequest*,
×
810
                                  HTTPResponse *response) {
811
  m_client.ReloadPlugins(
×
812
      NewSingleCallback(this, &OladHTTPServer::HandleBoolResponse, response));
813
  return MHD_YES;
×
814
}
815

816

817
/**
818
 * @brief Reload the PID Store.
819
 * @param request the HTTPRequest
820
 * @param response the HTTPResponse
821
 * @returns MHD_NO or MHD_YES
822
 */
823
int OladHTTPServer::ReloadPidStore(OLA_UNUSED const HTTPRequest *request,
×
824
                                   HTTPResponse *response) {
825
  m_ola_server->ReloadPidStore();
×
826
  response->SetNoCache();
×
827
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
828
  response->Append("ok");
×
829
  int r = response->Send();
×
830
  delete response;
×
831
  return r;
×
832
}
833

834

835
/**
836
 * @brief Handle the plugin list callback
837
 * @param response the HTTPResponse that is associated with the request.
838
 * @param result the result of the API call
839
 * @param plugins a list of plugins
840
 */
841
void OladHTTPServer::HandlePluginList(HTTPResponse *response,
×
842
                                      const client::Result &result,
843
                                      const vector<OlaPlugin> &plugins) {
844
  if (!result.Success()) {
×
845
    m_server.ServeError(response, result.Error());
×
846
    return;
×
847
  }
848

849
  JsonObject *json = new JsonObject();
×
850

851
  // fire off the universe request now. the main server is running in a
852
  // separate thread.
853
  m_client.FetchUniverseList(
×
854
      NewSingleCallback(this,
855
                        &OladHTTPServer::HandleUniverseList,
856
                        response,
857
                        json));
858

859
  JsonArray *plugins_json = json->AddArray("plugins");
×
860
  vector<OlaPlugin>::const_iterator iter;
×
861
  for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
×
862
    JsonObject *plugin = plugins_json->AppendObject();
×
863
    plugin->Add("name", iter->Name());
×
864
    plugin->Add("id", iter->Id());
×
865
    plugin->Add("active", iter->IsActive());
×
866
    plugin->Add("enabled", iter->IsEnabled());
×
867
  }
868
}
869

870

871
/**
872
 * @brief Handle the universe list callback
873
 * @param response the HTTPResponse that is associated with the request.
874
 * @param json the JsonObject to add the data to
875
 * @param result the result of the API call
876
 * @param universes the vector of OlaUniverse
877
 */
878
void OladHTTPServer::HandleUniverseList(HTTPResponse *response,
×
879
                                        JsonObject *json,
880
                                        const client::Result &result,
881
                                        const vector<OlaUniverse> &universes) {
882
  if (result.Success()) {
×
883
    JsonArray *universe_json = json->AddArray("universes");
×
884

885
    vector<OlaUniverse>::const_iterator iter;
×
886
    for (iter = universes.begin(); iter != universes.end(); ++iter) {
×
887
      JsonObject *universe = universe_json->AppendObject();
×
888
      universe->Add("id", iter->Id());
×
889
      universe->Add("input_ports", iter->InputPortCount());
×
890
      universe->Add("name", iter->Name());
×
891
      universe->Add("output_ports", iter->OutputPortCount());
×
892
      universe->Add("rdm_devices", iter->RDMDeviceCount());
×
893
    }
894
  }
895

896
  response->SetNoCache();
×
897
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
898
  response->SendJson(*json);
×
899
  delete response;
×
900
  delete json;
×
901
}
×
902

903

904
/**
905
 * @brief Handle the plugin description response.
906
 * @param response the HTTPResponse that is associated with the request.
907
 * @param plugin_id the plugin id.
908
 * @param result the result of the API call.
909
 * @param description the plugin description.
910
 */
911
void OladHTTPServer::HandlePartialPluginInfo(HTTPResponse *response,
×
912
                                             int plugin_id,
913
                                             const client::Result &result,
914
                                             const string &description) {
915
  if (!result.Success()) {
×
916
    m_server.ServeError(response, result.Error());
×
917
    return;
×
918
  }
919
  m_client.FetchPluginState(
×
920
      (ola_plugin_id) plugin_id,
921
      NewSingleCallback(this,
×
922
                        &OladHTTPServer::HandlePluginInfo,
923
                        response, description));
924
}
925

926
/**
927
 * @brief Handle the plugin description response.
928
 * @param response the HTTPResponse that is associated with the request.
929
 * @param description the plugin description
930
 * @param result the result of the API call.
931
 * @param state the state of the plugin.
932
 */
933
void OladHTTPServer::HandlePluginInfo(HTTPResponse *response,
×
934
                                      string description,
935
                                      const client::Result &result,
936
                                      const ola::client::PluginState &state) {
937
  if (!result.Success()) {
×
938
    m_server.ServeError(response, result.Error());
×
939
    return;
×
940
  }
941

942
  string escaped_description = description;
×
943
  // Replace \n before passing in so we get \\n out the far end
944
  ReplaceAll(&escaped_description, "\n", "\\n");
×
945

946
  JsonObject json;
×
947
  json.Add("description", escaped_description);
×
948
  json.Add("name", state.name);
×
949
  json.Add("enabled", state.enabled);
×
950
  json.Add("active", state.active);
×
951
  json.Add("preferences_source", state.preferences_source);
×
952
  JsonArray *plugins = json.AddArray("conflicts_with");
×
953
  vector<OlaPlugin>::const_iterator iter = state.conflicting_plugins.begin();
×
954
  for (; iter != state.conflicting_plugins.end(); ++iter) {
×
955
    JsonObject *plugin = plugins->AppendObject();
×
956
    plugin->Add("active", iter->IsActive());
×
957
    plugin->Add("id", iter->Id());
×
958
    plugin->Add("name", iter->Name());
×
959
  }
960

961
  response->SetNoCache();
×
962
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
963
  response->SendJson(json);
×
964
  delete response;
×
965
}
×
966

967

968
/**
969
 * @brief Handle the universe info
970
 * @param response the HTTPResponse that is associated with the request.
971
 * @param result the result of the API call
972
 * @param universe the OlaUniverse object
973
 */
974
void OladHTTPServer::HandleUniverseInfo(HTTPResponse *response,
×
975
                                        const client::Result &result,
976
                                        const OlaUniverse &universe) {
977
  if (!result.Success()) {
×
978
    m_server.ServeError(response, result.Error());
×
979
    return;
×
980
  }
981

982
  JsonObject *json = new JsonObject();
×
983

984
  // fire off the device/port request now. the main server is running in a
985
  // separate thread.
986
  m_client.FetchDeviceInfo(
×
987
      ola::OLA_PLUGIN_ALL,
988
      NewSingleCallback(this,
989
                        &OladHTTPServer::HandlePortsForUniverse,
990
                        response,
991
                        json,
992
                        universe.Id()));
993

994
  json->Add("id", universe.Id());
×
995
  json->Add("name", universe.Name());
×
996
  json->Add("merge_mode",
×
997
           (universe.MergeMode() == OlaUniverse::MERGE_HTP ? "HTP" : "LTP"));
×
998
}
999

1000

1001
void OladHTTPServer::HandlePortsForUniverse(
×
1002
    HTTPResponse *response,
1003
    JsonObject *json,
1004
    unsigned int universe_id,
1005
    const client::Result &result,
1006
    const vector<OlaDevice> &devices) {
1007
  if (result.Success()) {
×
1008
    vector<OlaDevice>::const_iterator iter = devices.begin();
×
1009
    vector<OlaInputPort>::const_iterator input_iter;
×
1010
    vector<OlaOutputPort>::const_iterator output_iter;
×
1011

1012
    JsonArray *output_ports_json = json->AddArray("output_ports");
×
1013
    JsonArray *input_ports_json = json->AddArray("input_ports");
×
1014

1015
    for (; iter != devices.end(); ++iter) {
×
1016
      const vector<OlaInputPort> &input_ports = iter->InputPorts();
×
1017
      for (input_iter = input_ports.begin(); input_iter != input_ports.end();
×
1018
           ++input_iter) {
×
1019
        if (input_iter->IsActive() && input_iter->Universe() == universe_id) {
×
1020
          JsonObject *obj = input_ports_json->AppendObject();
×
1021
          PortToJson(obj, *iter, *input_iter, false);
×
1022
        }
1023
      }
1024

1025
      const vector<OlaOutputPort> &output_ports = iter->OutputPorts();
×
1026
      for (output_iter = output_ports.begin();
×
1027
           output_iter != output_ports.end(); ++output_iter) {
×
1028
        if (output_iter->IsActive() &&
×
1029
            output_iter->Universe() == universe_id) {
×
1030
          JsonObject *obj = output_ports_json->AppendObject();
×
1031
          PortToJson(obj, *iter, *output_iter, true);
×
1032
        }
1033
      }
1034
    }
1035
  }
1036

1037
  response->SetNoCache();
×
1038
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
1039
  response->SendJson(*json);
×
1040
  delete json;
×
1041
  delete response;
×
1042
}
×
1043

1044

1045
/**
1046
 * @brief Handle the list of candidate ports
1047
 * @param response the HTTPResponse that is associated with the request.
1048
 * @param result the result of the API call
1049
 * @param devices the possible devices & ports
1050
 */
1051
void OladHTTPServer::HandleCandidatePorts(
×
1052
    HTTPResponse *response,
1053
    const client::Result &result,
1054
    const vector<OlaDevice> &devices) {
1055
  if (!result.Success()) {
×
1056
    m_server.ServeError(response, result.Error());
×
1057
    return;
×
1058
  }
1059

1060
  vector<OlaDevice>::const_iterator iter = devices.begin();
×
1061
  vector<OlaInputPort>::const_iterator input_iter;
×
1062
  vector<OlaOutputPort>::const_iterator output_iter;
×
1063

1064
  JsonArray json;
×
1065
  for (; iter != devices.end(); ++iter) {
×
1066
    const vector<OlaInputPort> &input_ports = iter->InputPorts();
×
1067
    for (input_iter = input_ports.begin(); input_iter != input_ports.end();
×
1068
         ++input_iter) {
×
1069
      JsonObject *obj = json.AppendObject();
×
1070
      PortToJson(obj, *iter, *input_iter, false);
×
1071
    }
1072

1073
    const vector<OlaOutputPort> &output_ports = iter->OutputPorts();
×
1074
    for (output_iter = output_ports.begin();
×
1075
         output_iter != output_ports.end(); ++output_iter) {
×
1076
      JsonObject *obj = json.AppendObject();
×
1077
      PortToJson(obj, *iter, *output_iter, true);
×
1078
    }
1079
  }
1080

1081
  response->SetNoCache();
×
1082
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
1083
  response->SendJson(json);
×
1084
  delete response;
×
1085
}
×
1086

1087

1088
/*
1089
 * @brief Schedule a callback to send the new universe response to the client
1090
 */
1091
void OladHTTPServer::CreateUniverseComplete(HTTPResponse *response,
×
1092
                                            unsigned int universe_id,
1093
                                            bool included_name,
1094
                                            class ActionQueue *action_queue) {
1095
  // this is a trick to unwind the stack and return control to a method outside
1096
  // the Action
1097
  m_server.SelectServer()->RegisterSingleTimeout(
×
1098
    0,
1099
    NewSingleCallback(this, &OladHTTPServer::SendCreateUniverseResponse,
1100
                      response, universe_id, included_name, action_queue));
1101
}
×
1102

1103

1104

1105
/*
1106
 * @brief Send the response to a new universe request
1107
 */
1108
void OladHTTPServer::SendCreateUniverseResponse(
×
1109
    HTTPResponse *response,
1110
    unsigned int universe_id,
1111
    bool included_name,
1112
    class ActionQueue *action_queue) {
1113
  unsigned int action_count = action_queue->ActionCount();
×
1114
  if (included_name) {
×
1115
    action_count--;
×
1116
  }
1117
  bool failed = true;
×
1118
  // it only takes one port patch to pass
1119
  for (unsigned int i = 0; i < action_count; i++) {
×
1120
    failed &= action_queue->GetAction(i)->Failed();
×
1121
  }
1122

1123
  JsonObject json;
×
1124
  json.Add("ok", !failed);
×
1125
  json.Add("universe", universe_id);
×
1126
  json.Add("message", (failed ? "Failed to patch any ports" : ""));
×
1127

1128
  response->SetNoCache();
×
1129
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
1130
  response->SendJson(json);
×
1131
  delete action_queue;
×
1132
  delete response;
×
1133
}
×
1134

1135

1136
/*
1137
 * @brief Schedule a callback to send the modify universe response to the client
1138
 */
1139
void OladHTTPServer::ModifyUniverseComplete(HTTPResponse *response,
×
1140
                                            ActionQueue *action_queue) {
1141
  // this is a trick to unwind the stack and return control to a method outside
1142
  // the Action
1143
  m_server.SelectServer()->RegisterSingleTimeout(
×
1144
    0,
1145
    NewSingleCallback(this, &OladHTTPServer::SendModifyUniverseResponse,
1146
                     response, action_queue));
1147
}
×
1148

1149

1150
/*
1151
 * @brief Send the response to a modify universe request.
1152
 */
1153
void OladHTTPServer::SendModifyUniverseResponse(HTTPResponse *response,
×
1154
                                                ActionQueue *action_queue) {
1155
  if (!action_queue->WasSuccessful()) {
×
1156
    delete action_queue;
×
1157
    m_server.ServeError(response, "Update failed");
×
1158
  } else {
1159
    response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
1160
    response->Append("ok");
×
1161
    response->Send();
×
1162
    delete action_queue;
×
1163
    delete response;
×
1164
  }
1165
}
×
1166

1167
/**
1168
 * @brief Serve usage information.
1169
 * @param response the response to use.
1170
 * @param details the usage information
1171
 */
1172
int OladHTTPServer::ServeUsage(HTTPResponse *response, const string &details) {
×
1173
  response->SetContentType(HTTPServer::CONTENT_TYPE_HTML);
×
1174
  response->Append("<b>Usage:</b>");
×
1175
  if (!details.empty()) {
×
1176
    response->Append("<p>");
×
1177
    response->Append(details);
×
1178
    response->Append("</p>");
×
1179
  }
1180
  int r = response->Send();
×
1181
  delete response;
×
1182
  return r;
×
1183
}
1184

1185
/**
1186
 * @brief Callback for m_client.FetchDmx called by GetDmx
1187
 * @param response the HTTPResponse
1188
 * @param result the result of the API call
1189
 * @param buffer the DmxBuffer
1190
 */
1191
void OladHTTPServer::HandleGetDmx(HTTPResponse *response,
×
1192
                                  const client::Result &result,
1193
                                  const client::DMXMetadata &,
1194
                                  const DmxBuffer &buffer) {
1195
  // rather than adding 512 JsonValue we cheat and use raw here
1196
  ostringstream str;
×
1197
  str << "[" << buffer.ToString() << "]";
×
1198
  JsonObject json;
×
1199
  json.AddRaw("dmx", str.str());
×
1200
  json.Add("error", result.Error());
×
1201

1202
  response->SetNoCache();
×
1203
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
1204
  response->SendJson(json);
×
1205
  delete response;
×
1206
}
×
1207

1208

1209
/**
1210
 * @brief Handle the set DMX response.
1211
 * @param response the HTTPResponse that is associated with the request.
1212
 * @param result the result of the API call
1213
 */
1214
void OladHTTPServer::HandleBoolResponse(HTTPResponse *response,
×
1215
                                        const client::Result &result) {
1216
  if (!result.Success()) {
×
1217
    m_server.ServeError(response, result.Error());
×
1218
    return;
×
1219
  }
1220
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
1221
  response->Append("ok");
×
1222
  response->Send();
×
1223
  delete response;
×
1224
}
1225

1226

1227
/**
1228
 * @brief Add the json representation of this port to the ostringstream
1229
 */
1230
void OladHTTPServer::PortToJson(JsonObject *json,
×
1231
                                const OlaDevice &device,
1232
                                const OlaPort &port,
1233
                                bool is_output) {
1234
  ostringstream str;
×
1235
  str << device.Alias() << "-" << (is_output ? "O" : "I") << "-" << port.Id();
×
1236

1237
  json->Add("device", device.Name());
×
1238
  json->Add("description", port.Description());
×
1239
  json->Add("id", str.str());
×
1240
  json->Add("is_output", is_output);
×
1241

1242
  JsonObject *priority_json = json->AddObject("priority");
×
1243
  if (port.PriorityCapability() != CAPABILITY_NONE) {
×
1244
    // This can be used as the default value for the priority input and because
1245
    // inherit ports can return a 0 priority we shall set it to the default
1246
    // here
1247
    uint8_t priority = port.Priority();
×
1248
    if (priority == 0) {
×
1249
      // We check here because 0 is an invalid priority outside of Olad
1250
      priority = dmx::SOURCE_PRIORITY_DEFAULT;
×
1251
    }
1252
    priority_json->Add("value", static_cast<int>(priority));
×
1253
    priority_json->Add(
×
1254
      "current_mode",
1255
      (port.PriorityMode() == PRIORITY_MODE_INHERIT ?  "inherit" : "static"));
×
1256
    priority_json->Add("priority_capability",
×
1257
      (port.PriorityCapability() == CAPABILITY_STATIC ? "static" : "full"));
×
1258
  }
1259
}
×
1260

1261

1262
/**
1263
 * @brief Add the Patch Actions to the ActionQueue.
1264
 * @param action_queue the ActionQueue to add the actions to.
1265
 * @param port_id_string a string to ports to add/remove.
1266
 * @param universe the universe id to add these ports if
1267
 * @param port_action either PATCH or UNPATCH.
1268
 */
1269
void OladHTTPServer::AddPatchActions(ActionQueue *action_queue,
×
1270
                                     const string port_id_string,
1271
                                     unsigned int universe,
1272
                                     client::PatchAction port_action) {
1273
  vector<port_identifier> ports;
×
1274
  vector<port_identifier>::const_iterator iter;
×
1275
  DecodePortIds(port_id_string, &ports);
×
1276

1277
  for (iter = ports.begin(); iter != ports.end(); ++iter) {
×
1278
    action_queue->AddAction(new PatchPortAction(
×
1279
      &m_client,
1280
      iter->device_alias,
×
1281
      iter->port,
×
1282
      iter->direction,
×
1283
      universe,
1284
      port_action));
×
1285
  }
1286
}
×
1287

1288

1289
/**
1290
 * @brief Add the Priority Actions to the ActionQueue.
1291
 * @param action_queue the ActionQueue to add the actions to.
1292
 * @param request the HTTPRequest to read the url params from.
1293
 */
1294
void OladHTTPServer::AddPriorityActions(ActionQueue *action_queue,
×
1295
                                        const HTTPRequest *request) {
1296
  string port_ids = request->GetPostParameter("modify_ports");
×
1297
  vector<port_identifier> ports;
×
1298
  vector<port_identifier>::const_iterator iter;
×
1299
  DecodePortIds(port_ids, &ports);
×
1300

1301
  for (iter = ports.begin(); iter != ports.end(); ++iter) {
×
1302
    string priority_mode_id = iter->string_id + K_PRIORITY_MODE_SUFFIX;
×
1303
    string priority_id = iter->string_id + K_PRIORITY_VALUE_SUFFIX;
×
1304
    string mode = request->GetPostParameter(priority_mode_id);
×
1305

1306
    if (mode == "inherit") {
×
1307
      action_queue->AddAction(new PortPriorityInheritAction(
×
1308
        &m_client,
1309
        iter->device_alias,
×
1310
        iter->port,
×
1311
        iter->direction));
×
1312
    } else if (mode == "static" || mode == "") {
×
1313
      // an empty mode param means this is a static port
1314
      string value = request->GetPostParameter(priority_id);
×
1315
      uint8_t priority_value;
×
1316
      if (StringToInt(value, &priority_value)) {
×
1317
        action_queue->AddAction(new PortPriorityStaticAction(
×
1318
          &m_client,
1319
          iter->device_alias,
×
1320
          iter->port,
×
1321
          iter->direction,
×
1322
          priority_value));
×
1323
      }
1324
    }
×
1325
  }
×
1326
}
×
1327

1328

1329
/**
1330
 * @brief Decode port ids in a string.
1331
 *
1332
 * This converts a string like "4-I-1,2-O-3" into a vector of port identifiers.
1333
 * @param port_ids the port ids in a , separated string
1334
 * @param ports a vector of port_identifiers that will be filled.
1335
 */
1336
void OladHTTPServer::DecodePortIds(const string &port_ids,
×
1337
                                   vector<port_identifier> *ports) {
1338
  vector<string> port_strings;
×
1339
  StringSplit(port_ids, &port_strings, ",");
×
1340
  vector<string>::const_iterator iter;
×
1341
  vector<string> tokens;
×
1342

1343
  for (iter = port_strings.begin(); iter != port_strings.end(); ++iter) {
×
1344
    if (iter->empty()) {
×
1345
      continue;
×
1346
    }
1347

1348
    tokens.clear();
×
1349
    StringSplit(*iter, &tokens, "-");
×
1350

1351
    if (tokens.size() != 3 || (tokens[1] != "I" && tokens[1] != "O")) {
×
1352
      OLA_INFO << "Not a valid port id " << *iter;
×
1353
      continue;
×
1354
    }
1355

1356
    unsigned int device_alias, port;
×
1357
    if (!StringToInt(tokens[0], &device_alias) ||
×
1358
        !StringToInt(tokens[2], &port)) {
×
1359
      OLA_INFO << "Not a valid port id " << *iter;
×
1360
      continue;
×
1361
    }
1362

1363
    client::PortDirection direction = (
×
1364
        tokens[1] == "I" ?  client::INPUT_PORT : client::OUTPUT_PORT);
×
1365
    port_identifier port_id = {device_alias, port, direction, *iter};
×
1366
    ports->push_back(port_id);
×
1367
  }
×
1368
}
×
1369

1370

1371
/**
1372
 * @brief Register a handler
1373
 */
1374
inline void OladHTTPServer::RegisterHandler(
×
1375
    const string &path,
1376
    int (OladHTTPServer::*method)(const HTTPRequest*, HTTPResponse*)) {
1377
  m_server.RegisterHandler(
×
1378
      path,
1379
      NewCallback<OladHTTPServer, int, const HTTPRequest*, HTTPResponse*>(
1380
        this,
1381
        method));
1382
}
×
1383
}  // namespace ola
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc