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

OpenLightingProject / ola / 16911433572

12 Aug 2025 02:08PM UTC coverage: 45.869% (-0.04%) from 45.909%
16911433572

Pull #1739

github

web-flow
Merge 02faeaa2d into 3566c28d9
Pull Request #1739: New web UI, store highest channel number used

7157 of 16316 branches covered (43.86%)

20915 of 45597 relevant lines covered (45.87%)

52.03 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/DmxBuffer.h"
29
#include "ola/Logging.h"
30
#include "ola/StringUtils.h"
31
#include "ola/base/Version.h"
32
#include "ola/dmx/SourcePriorities.h"
33
#include "ola/network/NetworkUtils.h"
34
#include "ola/web/Json.h"
35
#include "olad/DmxSource.h"
36
#include "olad/HttpServerActions.h"
37
#include "olad/OladHTTPServer.h"
38
#include "olad/OlaServer.h"
39
#include "olad/Preferences.h"
40

41
namespace ola {
42

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

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

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

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

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

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

223
  m_start_time_t = time(NULL);
×
224
}
×
225

226

227
/*
228
 * @brief Teardown
229
 */
230
OladHTTPServer::~OladHTTPServer() {
×
231
  if (m_client_socket) {
×
232
    m_server.SelectServer()->RemoveReadDescriptor(m_client_socket);
×
233
  }
234
  m_client.Stop();
×
235
  if (m_client_socket) {
×
236
    delete m_client_socket;
×
237
  }
238
}
×
239

240

241
/**
242
 * @brief Setup the OLA HTTP server
243
 * @return true if this worked, false otherwise.
244
 */
245
bool OladHTTPServer::Init() {
×
246
  if (!OlaHTTPServer::Init()) {
×
247
    return false;
248
  }
249

250
  if (!m_client.Setup()) {
×
251
    return false;
252
  }
253
  /*
254
  Setup disconnect notifications.
255
  m_socket->SetOnClose(
256
    ola::NewSingleCallback(this, &SimpleClient::SocketClosed));
257
  */
258
  m_server.SelectServer()->AddReadDescriptor(m_client_socket);
×
259
  return true;
×
260
}
261

262

263
/**
264
 * @brief Can be called while the HTTP server is running
265
 */
266
void OladHTTPServer::SetPidStore(const ola::rdm::RootPidStore *pid_store) {
×
267
  m_rdm_module.SetPidStore(pid_store);
×
268
}
×
269

270

271
/**
272
 * @brief Print the server stats JSON
273
 * @param request the HTTPRequest
274
 * @param response the HTTPResponse
275
 * @returns MHD_NO or MHD_YES
276
 */
277
int OladHTTPServer::JsonServerStats(const HTTPRequest*,
×
278
                                    HTTPResponse *response) {
279
  char start_time_str[50];
×
280
#ifdef _WIN32
281
  strftime(start_time_str, sizeof(start_time_str), "%c",
282
      localtime(&m_start_time_t));
283
#else
284
  struct tm start_time;
×
285
  localtime_r(&m_start_time_t, &start_time);
×
286
  strftime(start_time_str, sizeof(start_time_str), "%c", &start_time);
×
287
#endif  // _WIN32
288

289
  JsonObject json;
×
290
  json.Add("hostname", ola::network::FQDN());
×
291
  json.Add("instance_name", m_ola_server->InstanceName());
×
292
  json.Add("config_dir",
×
293
           m_ola_server->GetPreferencesFactory()->ConfigLocation());
×
294
  json.Add("ip", m_interface.ip_address.ToString());
×
295
  json.Add("broadcast", m_interface.bcast_address.ToString());
×
296
  json.Add("subnet", m_interface.subnet_mask.ToString());
×
297
  json.Add("hw_address", m_interface.hw_address.ToString());
×
298
  json.Add("version", ola::base::Version::GetVersion());
×
299
  json.Add("up_since", start_time_str);
×
300
  json.Add("quit_enabled", m_enable_quit);
×
301

302
  response->SetNoCache();
×
303
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
304
  int r = response->SendJson(json);
×
305
  delete response;
×
306
  return r;
×
307
}
×
308

309

310
/**
311
 * @brief Print the list of universes / plugins as a json string
312
 * @param request the HTTPRequest
313
 * @param response the HTTPResponse
314
 * @returns MHD_NO or MHD_YES
315
 */
316
int OladHTTPServer::JsonUniversePluginList(const HTTPRequest*,
×
317
                                           HTTPResponse *response) {
318
  m_client.FetchPluginList(
×
319
      NewSingleCallback(this,
320
                        &OladHTTPServer::HandlePluginList,
321
                        response));
322
  return MHD_YES;
×
323
}
324

325

326
/**
327
 * @brief Print the plugin info as a JSON string
328
 * @param request the HTTPRequest
329
 * @param response the HTTPResponse
330
 * @returns MHD_NO or MHD_YES
331
 */
332
int OladHTTPServer::JsonPluginInfo(const HTTPRequest *request,
×
333
                                   HTTPResponse *response) {
334
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
335
    return ServeUsage(response, "?id=[plugin]");
×
336
  }
337
  string val = request->GetParameter("id");
×
338
  int plugin_id;
×
339
  if (!StringToInt(val, &plugin_id)) {
×
340
    return ServeHelpRedirect(response);
×
341
  }
342

343
  m_client.FetchPluginDescription(
×
344
      (ola_plugin_id) plugin_id,
345
      NewSingleCallback(this,
346
                        &OladHTTPServer::HandlePartialPluginInfo,
347
                        response, plugin_id));
348
  return MHD_YES;
349
}
×
350

351

352
/**
353
 * @brief Return information about a universe
354
 * @param request the HTTPRequest
355
 * @param response the HTTPResponse
356
 * @returns MHD_NO or MHD_YES
357
 */
358
int OladHTTPServer::JsonUniverseInfo(OLA_UNUSED const HTTPRequest *request,
×
359
                                     HTTPResponse *response) {
360
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
361
    return ServeUsage(response, "?id=[universe]");
×
362
  }
363
  string uni_id = request->GetParameter("id");
×
364
  unsigned int universe_id;
×
365
  if (!StringToInt(uni_id, &universe_id)) {
×
366
    return ServeHelpRedirect(response);
×
367
  }
368

369
  m_client.FetchUniverseInfo(
×
370
      universe_id,
371
      NewSingleCallback(this,
372
                        &OladHTTPServer::HandleUniverseInfo,
373
                        response));
374

375
  return MHD_YES;
376
}
×
377

378

379
/**
380
 * @brief Return a list of unbound ports
381
 * @param request the HTTPRequest
382
 * @param response the HTTPResponse
383
 * @returns MHD_NO or MHD_YES
384
 */
385
int OladHTTPServer::JsonAvailablePorts(const HTTPRequest *request,
×
386
                                       HTTPResponse *response) {
387
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
388
    return ServeUsage(response, "? or ?id=[universe]");
×
389
  }
390
  string uni_id = request->GetParameter("id");
×
391

392
  if (uni_id.empty()) {
×
393
    // get all available ports
394
    m_client.FetchCandidatePorts(
×
395
        NewSingleCallback(this,
396
                          &OladHTTPServer::HandleCandidatePorts,
397
                          response));
398
  } else {
399
    unsigned int universe_id;
×
400
    if (!StringToInt(uni_id, &universe_id)) {
×
401
      return ServeHelpRedirect(response);
×
402
    }
403

404
    m_client.FetchCandidatePorts(
×
405
        universe_id,
406
        NewSingleCallback(this,
407
                          &OladHTTPServer::HandleCandidatePorts,
408
                          response));
409
  }
410
  return MHD_YES;
411
}
×
412

413

414
/**
415
 * @brief Create a new universe by binding one or more ports.
416
 * @param request the HTTPRequest
417
 * @param response the HTTPResponse
418
 * @returns MHD_NO or MHD_YES
419
 */
420
int OladHTTPServer::CreateNewUniverse(const HTTPRequest *request,
×
421
                                      HTTPResponse *response) {
422
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
423
    return ServeUsage(response,
×
424
                      "POST id=[universe], name=[name], add_ports=[a comma "
425
                      "separated list of port ids]");
426
  }
427
  string uni_id = request->GetPostParameter("id");
×
428
  string name = request->GetPostParameter("name");
×
429

430
  if (name.size() > K_UNIVERSE_NAME_LIMIT) {
×
431
    name = name.substr(K_UNIVERSE_NAME_LIMIT);
×
432
  }
433

434
  unsigned int universe_id;
×
435
  if (!StringToInt(uni_id, &universe_id)) {
×
436
    return ServeHelpRedirect(response);
×
437
  }
438

439
  ActionQueue *action_queue = new ActionQueue(
×
440
      NewSingleCallback(this,
441
                        &OladHTTPServer::CreateUniverseComplete,
442
                        response,
443
                        universe_id,
444
                        !name.empty()));
×
445

446
  // add patch actions here
447
  string add_port_ids = request->GetPostParameter("add_ports");
×
448
  AddPatchActions(action_queue, add_port_ids, universe_id, ola::client::PATCH);
×
449

450
  if (!name.empty()) {
×
451
    action_queue->AddAction(
×
452
        new SetNameAction(&m_client, universe_id, name, false));
×
453
  }
454

455
  action_queue->NextAction();
×
456
  return MHD_YES;
×
457
}
×
458

459

460
/**
461
 * @brief Modify an existing universe.
462
 * @param request the HTTPRequest
463
 * @param response the HTTPResponse
464
 * @returns MHD_NO or MHD_YES
465
 */
466
int OladHTTPServer::ModifyUniverse(const HTTPRequest *request,
×
467
                                   HTTPResponse *response) {
468
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
469
    return ServeUsage(response,
×
470
                      "POST id=[universe], name=[name], merge_mode=[HTP|LTP], "
471
                      "add_ports=[a comma separated list of port ids], "
472
                      "remove_ports=[a comma separated list of port ids]");
473
  }
474

475
  string uni_id = request->GetPostParameter("id");
×
476
  string name = request->GetPostParameter("name");
×
477
  string merge_mode = request->GetPostParameter("merge_mode");
×
478

479
  unsigned int universe_id;
×
480
  if (!StringToInt(uni_id, &universe_id)) {
×
481
    return ServeHelpRedirect(response);
×
482
  }
483

484
  if (name.empty()) {
×
485
    return m_server.ServeError(response, "No name supplied");
×
486
  }
487

488
  if (name.size() > K_UNIVERSE_NAME_LIMIT) {
×
489
    name = name.substr(K_UNIVERSE_NAME_LIMIT);
×
490
  }
491

492
  ActionQueue *action_queue = new ActionQueue(
×
493
      NewSingleCallback(this,
494
                        &OladHTTPServer::ModifyUniverseComplete,
495
                        response));
×
496

497
  action_queue->AddAction(
×
498
      new SetNameAction(&m_client, universe_id, name, true));
×
499

500
  if (merge_mode == "LTP" || merge_mode == "HTP") {
×
501
    OlaUniverse::merge_mode mode = (
×
502
      merge_mode == "LTP" ? OlaUniverse::MERGE_LTP : OlaUniverse::MERGE_HTP);
×
503
    action_queue->AddAction(
×
504
      new SetMergeModeAction(&m_client, universe_id, mode));
×
505
  }
506

507
  string remove_port_ids = request->GetPostParameter("remove_ports");
×
508
  AddPatchActions(action_queue, remove_port_ids, universe_id, client::UNPATCH);
×
509

510
  string add_port_ids = request->GetPostParameter("add_ports");
×
511
  AddPatchActions(action_queue, add_port_ids, universe_id, client::PATCH);
×
512

513
  AddPriorityActions(action_queue, request);
×
514

515
  action_queue->NextAction();
×
516
  return MHD_YES;
×
517
}
×
518

519
/**
520
 * @brief Set plugin state.
521
 * @param request the HTTPRequest
522
 * @param response the HTTPResponse
523
 * @returns MHD_NO or MHD_YES
524
 */
525
int OladHTTPServer::SetPluginState(const HTTPRequest *request,
×
526
                                   HTTPResponse *response) {
527
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
528
    return ServeUsage(response,
×
529
                      "POST state=[enable|disable], "
530
                      "plugin_id=[a plugin id]");
531
  }
532

533
  string state_string = request->GetPostParameter("state");
×
534

535
  bool state;
×
536
  if (!StringToBoolTolerant(state_string, &state)) {
×
537
    OLA_INFO << "Invalid state " << state_string;
×
538
    return ServeHelpRedirect(response);
×
539
  }
540

541
  string plugin_id_string = request->GetPostParameter("plugin_id");
×
542
  unsigned int plugin_id;
×
543
  if (!StringToInt(plugin_id_string, &plugin_id)) {
×
544
    OLA_INFO << "Invalid plugin id " << plugin_id_string;
×
545
    return ServeHelpRedirect(response);
×
546
  }
547

548
  m_client.SetPluginState(
×
549
      (ola_plugin_id) plugin_id,
550
      state,
551
      NewSingleCallback(this, &OladHTTPServer::HandleBoolResponse, response));
552

553
  return MHD_YES;
554
}
×
555

556

557
/**
558
 * @brief Handle the get DMX command
559
 * @param request the HTTPRequest
560
 * @param response the HTTPResponse
561
 * @returns MHD_NO or MHD_YES
562
 */
563
int OladHTTPServer::GetDmx(const HTTPRequest *request,
×
564
                           HTTPResponse *response) {
565
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
566
    return ServeUsage(response, "?u=[universe]");
×
567
  }
568
  string uni_id = request->GetParameter("u");
×
569
  unsigned int universe_id;
×
570
  if (!StringToInt(uni_id, &universe_id)) {
×
571
    return ServeHelpRedirect(response);
×
572
  }
573

574
  m_client.FetchDMX(
×
575
      universe_id,
576
      NewSingleCallback(this, &OladHTTPServer::HandleGetDmx, response));
577
  return MHD_YES;
578
}
×
579

580

581
/**
582
 * @brief Handle the set DMX command
583
 * @param request the HTTPRequest
584
 * @param response the HTTPResponse
585
 * @returns MHD_NO or MHD_YES
586
 */
587
int OladHTTPServer::HandleSetDmx(const HTTPRequest *request,
×
588
                                 HTTPResponse *response) {
589
  if (request->CheckParameterExists(HELP_PARAMETER)) {
×
590
    return ServeUsage(response,
×
591
        "POST u=[universe], d=[DMX data (a comma separated list of values)]");
592
  }
593
  string dmx_data_str = request->GetPostParameter("d");
×
594
  string uni_id = request->GetPostParameter("u");
×
595
  unsigned int universe_id;
×
596
  if (!StringToInt(uni_id, &universe_id)) {
×
597
    return ServeHelpRedirect(response);
×
598
  }
599

600
  DmxBuffer buffer;
×
601
  buffer.SetFromString(dmx_data_str);
×
602
  if (!buffer.Size()) {
×
603
    return m_server.ServeError(response, "Invalid DMX string");
×
604
  }
605

606
  ola::client::SendDMXArgs args(
×
607
      NewSingleCallback(this, &OladHTTPServer::HandleBoolResponse, response));
×
608
  m_client.SendDMX(universe_id, buffer, args);
×
609
  return MHD_YES;
610
}
×
611

612

613
/**
614
 * @brief Cause the server to shutdown
615
 * @param request the HTTPRequest
616
 * @param response the HTTPResponse
617
 * @returns MHD_NO or MHD_YES
618
 */
619
int OladHTTPServer::DisplayQuit(OLA_UNUSED const HTTPRequest *request,
×
620
                                HTTPResponse *response) {
621
  if (m_enable_quit) {
×
622
    response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
623
    response->Append("ok");
×
624
    m_ola_server->StopServer();
×
625
  } else {
626
    response->SetStatus(403);
×
627
    response->SetContentType(HTTPServer::CONTENT_TYPE_HTML);
×
628
    response->Append("<b>403 Unauthorized</b>");
×
629
  }
630
  response->SetNoCache();
×
631
  int r = response->Send();
×
632
  delete response;
×
633
  return r;
×
634
}
635

636

637
/**
638
 * @brief Reload all plugins
639
 * @param request the HTTPRequest
640
 * @param response the HTTPResponse
641
 * @returns MHD_NO or MHD_YES
642
 */
643
int OladHTTPServer::ReloadPlugins(const HTTPRequest*,
×
644
                                  HTTPResponse *response) {
645
  m_client.ReloadPlugins(
×
646
      NewSingleCallback(this, &OladHTTPServer::HandleBoolResponse, response));
647
  return MHD_YES;
×
648
}
649

650

651
/**
652
 * @brief Reload the PID Store.
653
 * @param request the HTTPRequest
654
 * @param response the HTTPResponse
655
 * @returns MHD_NO or MHD_YES
656
 */
657
int OladHTTPServer::ReloadPidStore(OLA_UNUSED const HTTPRequest *request,
×
658
                                   HTTPResponse *response) {
659
  m_ola_server->ReloadPidStore();
×
660
  response->SetNoCache();
×
661
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
662
  response->Append("ok");
×
663
  int r = response->Send();
×
664
  delete response;
×
665
  return r;
×
666
}
667

668

669
/**
670
 * @brief Handle the plugin list callback
671
 * @param response the HTTPResponse that is associated with the request.
672
 * @param result the result of the API call
673
 * @param plugins a list of plugins
674
 */
675
void OladHTTPServer::HandlePluginList(HTTPResponse *response,
×
676
                                      const client::Result &result,
677
                                      const vector<OlaPlugin> &plugins) {
678
  if (!result.Success()) {
×
679
    m_server.ServeError(response, result.Error());
×
680
    return;
×
681
  }
682

683
  JsonObject *json = new JsonObject();
×
684

685
  // fire off the universe request now. the main server is running in a
686
  // separate thread.
687
  m_client.FetchUniverseList(
×
688
      NewSingleCallback(this,
689
                        &OladHTTPServer::HandleUniverseList,
690
                        response,
691
                        json));
692

693
  JsonArray *plugins_json = json->AddArray("plugins");
×
694
  vector<OlaPlugin>::const_iterator iter;
×
695
  for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
×
696
    JsonObject *plugin = plugins_json->AppendObject();
×
697
    plugin->Add("name", iter->Name());
×
698
    plugin->Add("id", iter->Id());
×
699
    plugin->Add("active", iter->IsActive());
×
700
    plugin->Add("enabled", iter->IsEnabled());
×
701
  }
702
}
703

704

705
/**
706
 * @brief Handle the universe list callback
707
 * @param response the HTTPResponse that is associated with the request.
708
 * @param json the JsonObject to add the data to
709
 * @param result the result of the API call
710
 * @param universes the vector of OlaUniverse
711
 */
712
void OladHTTPServer::HandleUniverseList(HTTPResponse *response,
×
713
                                        JsonObject *json,
714
                                        const client::Result &result,
715
                                        const vector<OlaUniverse> &universes) {
716
  if (result.Success()) {
×
717
    JsonArray *universe_json = json->AddArray("universes");
×
718

719
    vector<OlaUniverse>::const_iterator iter;
×
720
    for (iter = universes.begin(); iter != universes.end(); ++iter) {
×
721
      JsonObject *universe = universe_json->AppendObject();
×
722
      universe->Add("id", iter->Id());
×
723
      universe->Add("input_ports", iter->InputPortCount());
×
724
      universe->Add("name", iter->Name());
×
725
      universe->Add("output_ports", iter->OutputPortCount());
×
726
      universe->Add("rdm_devices", iter->RDMDeviceCount());
×
727
    }
728
  }
729

730
  response->SetNoCache();
×
731
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
732
  response->SendJson(*json);
×
733
  delete response;
×
734
  delete json;
×
735
}
×
736

737

738
/**
739
 * @brief Handle the plugin description response.
740
 * @param response the HTTPResponse that is associated with the request.
741
 * @param plugin_id the plugin id.
742
 * @param result the result of the API call.
743
 * @param description the plugin description.
744
 */
745
void OladHTTPServer::HandlePartialPluginInfo(HTTPResponse *response,
×
746
                                             int plugin_id,
747
                                             const client::Result &result,
748
                                             const string &description) {
749
  if (!result.Success()) {
×
750
    m_server.ServeError(response, result.Error());
×
751
    return;
×
752
  }
753
  m_client.FetchPluginState(
×
754
      (ola_plugin_id) plugin_id,
755
      NewSingleCallback(this,
×
756
                        &OladHTTPServer::HandlePluginInfo,
757
                        response, description));
758
}
759

760
/**
761
 * @brief Handle the plugin description response.
762
 * @param response the HTTPResponse that is associated with the request.
763
 * @param description the plugin description
764
 * @param result the result of the API call.
765
 * @param state the state of the plugin.
766
 */
767
void OladHTTPServer::HandlePluginInfo(HTTPResponse *response,
×
768
                                      string description,
769
                                      const client::Result &result,
770
                                      const ola::client::PluginState &state) {
771
  if (!result.Success()) {
×
772
    m_server.ServeError(response, result.Error());
×
773
    return;
×
774
  }
775

776
  string escaped_description = description;
×
777
  // Replace \n before passing in so we get \\n out the far end
778
  ReplaceAll(&escaped_description, "\n", "\\n");
×
779

780
  JsonObject json;
×
781
  json.Add("description", escaped_description);
×
782
  json.Add("name", state.name);
×
783
  json.Add("enabled", state.enabled);
×
784
  json.Add("active", state.active);
×
785
  json.Add("preferences_source", state.preferences_source);
×
786
  JsonArray *plugins = json.AddArray("conflicts_with");
×
787
  vector<OlaPlugin>::const_iterator iter = state.conflicting_plugins.begin();
×
788
  for (; iter != state.conflicting_plugins.end(); ++iter) {
×
789
    JsonObject *plugin = plugins->AppendObject();
×
790
    plugin->Add("active", iter->IsActive());
×
791
    plugin->Add("id", iter->Id());
×
792
    plugin->Add("name", iter->Name());
×
793
  }
794

795
  response->SetNoCache();
×
796
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
797
  response->SendJson(json);
×
798
  delete response;
×
799
}
×
800

801

802
/**
803
 * @brief Handle the universe info
804
 * @param response the HTTPResponse that is associated with the request.
805
 * @param result the result of the API call
806
 * @param universe the OlaUniverse object
807
 */
808
void OladHTTPServer::HandleUniverseInfo(HTTPResponse *response,
×
809
                                        const client::Result &result,
810
                                        const OlaUniverse &universe) {
811
  if (!result.Success()) {
×
812
    m_server.ServeError(response, result.Error());
×
813
    return;
×
814
  }
815

816
  JsonObject *json = new JsonObject();
×
817

818
  // fire off the device/port request now. the main server is running in a
819
  // separate thread.
820
  m_client.FetchDeviceInfo(
×
821
      ola::OLA_PLUGIN_ALL,
822
      NewSingleCallback(this,
823
                        &OladHTTPServer::HandlePortsForUniverse,
824
                        response,
825
                        json,
826
                        universe.Id()));
827

828
  json->Add("id", universe.Id());
×
829
  json->Add("name", universe.Name());
×
830
  json->Add("merge_mode",
×
831
           (universe.MergeMode() == OlaUniverse::MERGE_HTP ? "HTP" : "LTP"));
×
832
}
833

834

835
void OladHTTPServer::HandlePortsForUniverse(
×
836
    HTTPResponse *response,
837
    JsonObject *json,
838
    unsigned int universe_id,
839
    const client::Result &result,
840
    const vector<OlaDevice> &devices) {
841
  if (result.Success()) {
×
842
    vector<OlaDevice>::const_iterator iter = devices.begin();
×
843
    vector<OlaInputPort>::const_iterator input_iter;
×
844
    vector<OlaOutputPort>::const_iterator output_iter;
×
845

846
    JsonArray *output_ports_json = json->AddArray("output_ports");
×
847
    JsonArray *input_ports_json = json->AddArray("input_ports");
×
848

849
    for (; iter != devices.end(); ++iter) {
×
850
      const vector<OlaInputPort> &input_ports = iter->InputPorts();
×
851
      for (input_iter = input_ports.begin(); input_iter != input_ports.end();
×
852
           ++input_iter) {
×
853
        if (input_iter->IsActive() && input_iter->Universe() == universe_id) {
×
854
          JsonObject *obj = input_ports_json->AppendObject();
×
855
          PortToJson(obj, *iter, *input_iter, false);
×
856
        }
857
      }
858

859
      const vector<OlaOutputPort> &output_ports = iter->OutputPorts();
×
860
      for (output_iter = output_ports.begin();
×
861
           output_iter != output_ports.end(); ++output_iter) {
×
862
        if (output_iter->IsActive() &&
×
863
            output_iter->Universe() == universe_id) {
×
864
          JsonObject *obj = output_ports_json->AppendObject();
×
865
          PortToJson(obj, *iter, *output_iter, true);
×
866
        }
867
      }
868
    }
869
  }
870

871
  response->SetNoCache();
×
872
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
873
  response->SendJson(*json);
×
874
  delete json;
×
875
  delete response;
×
876
}
×
877

878

879
/**
880
 * @brief Handle the list of candidate ports
881
 * @param response the HTTPResponse that is associated with the request.
882
 * @param result the result of the API call
883
 * @param devices the possible devices & ports
884
 */
885
void OladHTTPServer::HandleCandidatePorts(
×
886
    HTTPResponse *response,
887
    const client::Result &result,
888
    const vector<OlaDevice> &devices) {
889
  if (!result.Success()) {
×
890
    m_server.ServeError(response, result.Error());
×
891
    return;
×
892
  }
893

894
  vector<OlaDevice>::const_iterator iter = devices.begin();
×
895
  vector<OlaInputPort>::const_iterator input_iter;
×
896
  vector<OlaOutputPort>::const_iterator output_iter;
×
897

898
  JsonArray json;
×
899
  for (; iter != devices.end(); ++iter) {
×
900
    const vector<OlaInputPort> &input_ports = iter->InputPorts();
×
901
    for (input_iter = input_ports.begin(); input_iter != input_ports.end();
×
902
         ++input_iter) {
×
903
      JsonObject *obj = json.AppendObject();
×
904
      PortToJson(obj, *iter, *input_iter, false);
×
905
    }
906

907
    const vector<OlaOutputPort> &output_ports = iter->OutputPorts();
×
908
    for (output_iter = output_ports.begin();
×
909
         output_iter != output_ports.end(); ++output_iter) {
×
910
      JsonObject *obj = json.AppendObject();
×
911
      PortToJson(obj, *iter, *output_iter, true);
×
912
    }
913
  }
914

915
  response->SetNoCache();
×
916
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
917
  response->SendJson(json);
×
918
  delete response;
×
919
}
×
920

921

922
/*
923
 * @brief Schedule a callback to send the new universe response to the client
924
 */
925
void OladHTTPServer::CreateUniverseComplete(HTTPResponse *response,
×
926
                                            unsigned int universe_id,
927
                                            bool included_name,
928
                                            class ActionQueue *action_queue) {
929
  // this is a trick to unwind the stack and return control to a method outside
930
  // the Action
931
  m_server.SelectServer()->RegisterSingleTimeout(
×
932
    0,
933
    NewSingleCallback(this, &OladHTTPServer::SendCreateUniverseResponse,
934
                      response, universe_id, included_name, action_queue));
935
}
×
936

937

938

939
/*
940
 * @brief Send the response to a new universe request
941
 */
942
void OladHTTPServer::SendCreateUniverseResponse(
×
943
    HTTPResponse *response,
944
    unsigned int universe_id,
945
    bool included_name,
946
    class ActionQueue *action_queue) {
947
  unsigned int action_count = action_queue->ActionCount();
×
948
  if (included_name) {
×
949
    action_count--;
×
950
  }
951
  bool failed = true;
×
952
  // it only takes one port patch to pass
953
  for (unsigned int i = 0; i < action_count; i++) {
×
954
    failed &= action_queue->GetAction(i)->Failed();
×
955
  }
956

957
  JsonObject json;
×
958
  json.Add("ok", !failed);
×
959
  json.Add("universe", universe_id);
×
960
  json.Add("message", (failed ? "Failed to patch any ports" : ""));
×
961

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

969

970
/*
971
 * @brief Schedule a callback to send the modify universe response to the client
972
 */
973
void OladHTTPServer::ModifyUniverseComplete(HTTPResponse *response,
×
974
                                            ActionQueue *action_queue) {
975
  // this is a trick to unwind the stack and return control to a method outside
976
  // the Action
977
  m_server.SelectServer()->RegisterSingleTimeout(
×
978
    0,
979
    NewSingleCallback(this, &OladHTTPServer::SendModifyUniverseResponse,
980
                     response, action_queue));
981
}
×
982

983

984
/*
985
 * @brief Send the response to a modify universe request.
986
 */
987
void OladHTTPServer::SendModifyUniverseResponse(HTTPResponse *response,
×
988
                                                ActionQueue *action_queue) {
989
  if (!action_queue->WasSuccessful()) {
×
990
    delete action_queue;
×
991
    m_server.ServeError(response, "Update failed");
×
992
  } else {
993
    response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
994
    response->Append("ok");
×
995
    response->Send();
×
996
    delete action_queue;
×
997
    delete response;
×
998
  }
999
}
×
1000

1001
/**
1002
 * @brief Serve usage information.
1003
 * @param response the response to use.
1004
 * @param details the usage information
1005
 */
1006
int OladHTTPServer::ServeUsage(HTTPResponse *response, const string &details) {
×
1007
  response->SetContentType(HTTPServer::CONTENT_TYPE_HTML);
×
1008
  response->Append("<b>Usage:</b>");
×
1009
  if (!details.empty()) {
×
1010
    response->Append("<p>");
×
1011
    response->Append(details);
×
1012
    response->Append("</p>");
×
1013
  }
1014
  int r = response->Send();
×
1015
  delete response;
×
1016
  return r;
×
1017
}
1018

1019
/**
1020
 * @brief Callback for m_client.FetchDmx called by GetDmx
1021
 * @param response the HTTPResponse
1022
 * @param result the result of the API call
1023
 * @param buffer the DmxBuffer
1024
 */
1025
void OladHTTPServer::HandleGetDmx(HTTPResponse *response,
×
1026
                                  const client::Result &result,
1027
                                  const client::DMXMetadata &,
1028
                                  const DmxBuffer &buffer) {
1029
  // rather than adding 512 JsonValue we cheat and use raw here
1030
  ostringstream str;
×
1031
  str << "[" << buffer.ToString() << "]";
×
1032
  JsonObject json;
×
1033
  json.AddRaw("dmx", str.str());
×
1034
  json.Add("error", result.Error());
×
1035

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

1042

1043
/**
1044
 * @brief Handle the set DMX response.
1045
 * @param response the HTTPResponse that is associated with the request.
1046
 * @param result the result of the API call
1047
 */
1048
void OladHTTPServer::HandleBoolResponse(HTTPResponse *response,
×
1049
                                        const client::Result &result) {
1050
  if (!result.Success()) {
×
1051
    m_server.ServeError(response, result.Error());
×
1052
    return;
×
1053
  }
1054
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
1055
  response->Append("ok");
×
1056
  response->Send();
×
1057
  delete response;
×
1058
}
1059

1060

1061
/**
1062
 * @brief Add the json representation of this port to the ostringstream
1063
 */
1064
void OladHTTPServer::PortToJson(JsonObject *json,
×
1065
                                const OlaDevice &device,
1066
                                const OlaPort &port,
1067
                                bool is_output) {
1068
  ostringstream str;
×
1069
  str << device.Alias() << "-" << (is_output ? "O" : "I") << "-" << port.Id();
×
1070

1071
  json->Add("device", device.Name());
×
1072
  json->Add("description", port.Description());
×
1073
  json->Add("id", str.str());
×
1074
  json->Add("is_output", is_output);
×
1075

1076
  JsonObject *priority_json = json->AddObject("priority");
×
1077
  if (port.PriorityCapability() != CAPABILITY_NONE) {
×
1078
    // This can be used as the default value for the priority input and because
1079
    // inherit ports can return a 0 priority we shall set it to the default
1080
    // here
1081
    uint8_t priority = port.Priority();
×
1082
    if (priority == 0) {
×
1083
      // We check here because 0 is an invalid priority outside of Olad
1084
      priority = dmx::SOURCE_PRIORITY_DEFAULT;
×
1085
    }
1086
    priority_json->Add("value", static_cast<int>(priority));
×
1087
    priority_json->Add(
×
1088
      "current_mode",
1089
      (port.PriorityMode() == PRIORITY_MODE_INHERIT ?  "inherit" : "static"));
×
1090
    priority_json->Add("priority_capability",
×
1091
      (port.PriorityCapability() == CAPABILITY_STATIC ? "static" : "full"));
×
1092
  }
1093
}
×
1094

1095

1096
/**
1097
 * @brief Add the Patch Actions to the ActionQueue.
1098
 * @param action_queue the ActionQueue to add the actions to.
1099
 * @param port_id_string a string to ports to add/remove.
1100
 * @param universe the universe id to add these ports if
1101
 * @param port_action either PATCH or UNPATCH.
1102
 */
1103
void OladHTTPServer::AddPatchActions(ActionQueue *action_queue,
×
1104
                                     const string port_id_string,
1105
                                     unsigned int universe,
1106
                                     client::PatchAction port_action) {
1107
  vector<port_identifier> ports;
×
1108
  vector<port_identifier>::const_iterator iter;
×
1109
  DecodePortIds(port_id_string, &ports);
×
1110

1111
  for (iter = ports.begin(); iter != ports.end(); ++iter) {
×
1112
    action_queue->AddAction(new PatchPortAction(
×
1113
      &m_client,
1114
      iter->device_alias,
×
1115
      iter->port,
×
1116
      iter->direction,
×
1117
      universe,
1118
      port_action));
×
1119
  }
1120
}
×
1121

1122

1123
/**
1124
 * @brief Add the Priority Actions to the ActionQueue.
1125
 * @param action_queue the ActionQueue to add the actions to.
1126
 * @param request the HTTPRequest to read the url params from.
1127
 */
1128
void OladHTTPServer::AddPriorityActions(ActionQueue *action_queue,
×
1129
                                        const HTTPRequest *request) {
1130
  string port_ids = request->GetPostParameter("modify_ports");
×
1131
  vector<port_identifier> ports;
×
1132
  vector<port_identifier>::const_iterator iter;
×
1133
  DecodePortIds(port_ids, &ports);
×
1134

1135
  for (iter = ports.begin(); iter != ports.end(); ++iter) {
×
1136
    string priority_mode_id = iter->string_id + K_PRIORITY_MODE_SUFFIX;
×
1137
    string priority_id = iter->string_id + K_PRIORITY_VALUE_SUFFIX;
×
1138
    string mode = request->GetPostParameter(priority_mode_id);
×
1139

1140
    if (mode == "inherit") {
×
1141
      action_queue->AddAction(new PortPriorityInheritAction(
×
1142
        &m_client,
1143
        iter->device_alias,
×
1144
        iter->port,
×
1145
        iter->direction));
×
1146
    } else if (mode == "static" || mode == "") {
×
1147
      // an empty mode param means this is a static port
1148
      string value = request->GetPostParameter(priority_id);
×
1149
      uint8_t priority_value;
×
1150
      if (StringToInt(value, &priority_value)) {
×
1151
        action_queue->AddAction(new PortPriorityStaticAction(
×
1152
          &m_client,
1153
          iter->device_alias,
×
1154
          iter->port,
×
1155
          iter->direction,
×
1156
          priority_value));
×
1157
      }
1158
    }
×
1159
  }
×
1160
}
×
1161

1162

1163
/**
1164
 * @brief Decode port ids in a string.
1165
 *
1166
 * This converts a string like "4-I-1,2-O-3" into a vector of port identifiers.
1167
 * @param port_ids the port ids in a , separated string
1168
 * @param ports a vector of port_identifiers that will be filled.
1169
 */
1170
void OladHTTPServer::DecodePortIds(const string &port_ids,
×
1171
                                   vector<port_identifier> *ports) {
1172
  vector<string> port_strings;
×
1173
  StringSplit(port_ids, &port_strings, ",");
×
1174
  vector<string>::const_iterator iter;
×
1175
  vector<string> tokens;
×
1176

1177
  for (iter = port_strings.begin(); iter != port_strings.end(); ++iter) {
×
1178
    if (iter->empty()) {
×
1179
      continue;
×
1180
    }
1181

1182
    tokens.clear();
×
1183
    StringSplit(*iter, &tokens, "-");
×
1184

1185
    if (tokens.size() != 3 || (tokens[1] != "I" && tokens[1] != "O")) {
×
1186
      OLA_INFO << "Not a valid port id " << *iter;
×
1187
      continue;
×
1188
    }
1189

1190
    unsigned int device_alias, port;
×
1191
    if (!StringToInt(tokens[0], &device_alias) ||
×
1192
        !StringToInt(tokens[2], &port)) {
×
1193
      OLA_INFO << "Not a valid port id " << *iter;
×
1194
      continue;
×
1195
    }
1196

1197
    client::PortDirection direction = (
×
1198
        tokens[1] == "I" ?  client::INPUT_PORT : client::OUTPUT_PORT);
×
1199
    port_identifier port_id = {device_alias, port, direction, *iter};
×
1200
    ports->push_back(port_id);
×
1201
  }
×
1202
}
×
1203

1204

1205
/**
1206
 * @brief Register a handler
1207
 */
1208
inline void OladHTTPServer::RegisterHandler(
×
1209
    const string &path,
1210
    int (OladHTTPServer::*method)(const HTTPRequest*, HTTPResponse*)) {
1211
  m_server.RegisterHandler(
×
1212
      path,
1213
      NewCallback<OladHTTPServer, int, const HTTPRequest*, HTTPResponse*>(
1214
        this,
1215
        method));
1216
}
×
1217
}  // 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