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

OpenLightingProject / ola / 24609073669

18 Apr 2026 04:36PM UTC coverage: 44.864% (-0.9%) from 45.72%
24609073669

push

github

web-flow
Merge pull request #2043 from peternewman/nortle-ftdi

Revert some stuff via 146cf26 which accidentally snuck into #1999 by mistake

8554 of 19846 branches covered (43.1%)

22105 of 49271 relevant lines covered (44.86%)

48.53 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("build", ola::base::Version::GetBuildName());
×
466
  json.Add("up_since", start_time_str);
×
467
  json.Add("quit_enabled", m_enable_quit);
×
468

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

476

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

492

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

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

518

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

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

542
  return MHD_YES;
543
}
×
544

545

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

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

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

580

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

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

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

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

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

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

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

626

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

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

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

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

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

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

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

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

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

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

680
  AddPriorityActions(action_queue, request);
×
681

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

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

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

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

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

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

720
  return MHD_YES;
721
}
×
722

723

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

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

747

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

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

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

779

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

803

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

817

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

835

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

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

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

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

871

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

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

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

904

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

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

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

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

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

968

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

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

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

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

1001

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

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

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

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

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

1045

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

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

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

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

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

1088

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

1104

1105

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

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

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

1136

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

1150

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

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

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

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

1209

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

1227

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

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

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

1262

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

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

1289

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

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

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

1329

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

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

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

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

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

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

1371

1372
/**
1373
 * @brief Register a handler
1374
 */
1375
inline void OladHTTPServer::RegisterHandler(
×
1376
    const string &path,
1377
    int (OladHTTPServer::*method)(const HTTPRequest*, HTTPResponse*)) {
1378
  m_server.RegisterHandler(
×
1379
      path,
1380
      NewCallback<OladHTTPServer, int, const HTTPRequest*, HTTPResponse*>(
1381
        this,
1382
        method));
1383
}
×
1384
}  // 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

© 2026 Coveralls, Inc