syndilights/open-lighting-architecture/ola-0.8.4/olad/OlaHttpServer.cpp

1020 lines
31 KiB
C++

/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* OlaHttpServer.cpp
* Ola HTTP class
* Copyright (C) 2005-2008 Simon Newton
*/
#include <sys/time.h>
#include <iostream>
#include <string>
#include <vector>
#include "ola/ActionQueue.h"
#include "ola/Callback.h"
#include "ola/DmxBuffer.h"
#include "olad/HttpServerActions.h"
#include "ola/Logging.h"
#include "ola/StringUtils.h"
#include "ola/network/NetworkUtils.h"
#include "olad/OlaHttpServer.h"
#include "olad/OlaServer.h"
#include "olad/OlaVersion.h"
namespace ola {
using ola::network::ConnectedSocket;
using std::cout;
using std::endl;
using std::string;
using std::stringstream;
using std::vector;
const char OlaHttpServer::K_DATA_DIR_VAR[] = "http_data_dir";
const char OlaHttpServer::K_UPTIME_VAR[] = "uptime-in-ms";
const char OlaHttpServer::K_BACKEND_DISCONNECTED_ERROR[] =
"Failed to send request, client isn't connected";
const char OlaHttpServer::K_PRIORITY_VALUE_SUFFIX[] = "_priority_value";
const char OlaHttpServer::K_PRIORITY_MODE_SUFFIX[] = "_priority_mode";
/**
* Create a new OLA HTTP server
* @param export_map the ExportMap to display when /debug is called
* @param client_socket A ConnectedSocket which is used to communicate with the
* server.
* @param
*/
OlaHttpServer::OlaHttpServer(ExportMap *export_map,
ConnectedSocket *client_socket,
OlaServer *ola_server,
unsigned int port,
bool enable_quit,
const string &data_dir,
const ola::network::Interface &interface)
: m_server(port, data_dir),
m_export_map(export_map),
m_client_socket(client_socket),
m_client(client_socket),
m_ola_server(ola_server),
m_enable_quit(enable_quit),
m_interface(interface),
m_rdm_module(&m_server, &m_client) {
// The main handlers
RegisterHandler("/", &OlaHttpServer::DisplayIndex);
RegisterHandler("/debug", &OlaHttpServer::DisplayDebug);
RegisterHandler("/help", &OlaHttpServer::DisplayHandlers);
RegisterHandler("/quit", &OlaHttpServer::DisplayQuit);
RegisterHandler("/reload", &OlaHttpServer::ReloadPlugins);
RegisterHandler("/new_universe", &OlaHttpServer::CreateNewUniverse);
RegisterHandler("/modify_universe", &OlaHttpServer::ModifyUniverse);
RegisterHandler("/set_dmx", &OlaHttpServer::HandleSetDmx);
// json endpoints for the new UI
RegisterHandler("/json/server_stats", &OlaHttpServer::JsonServerStats);
RegisterHandler("/json/universe_plugin_list",
&OlaHttpServer::JsonUniversePluginList);
RegisterHandler("/json/plugin_info", &OlaHttpServer::JsonPluginInfo);
RegisterHandler("/json/get_ports", &OlaHttpServer::JsonAvailablePorts);
RegisterHandler("/json/universe_info", &OlaHttpServer::JsonUniverseInfo);
// these are the static files for the new UI
RegisterFile("blank.gif", HttpServer::CONTENT_TYPE_GIF);
RegisterFile("button-bg.png", HttpServer::CONTENT_TYPE_PNG);
RegisterFile("custombutton.css", HttpServer::CONTENT_TYPE_CSS);
RegisterFile("expander.png", HttpServer::CONTENT_TYPE_PNG);
RegisterFile("handle.vertical.png", HttpServer::CONTENT_TYPE_PNG);
RegisterFile("loader.gif", HttpServer::CONTENT_TYPE_GIF);
RegisterFile("logo.png", HttpServer::CONTENT_TYPE_PNG);
RegisterFile("ola.html", HttpServer::CONTENT_TYPE_HTML);
RegisterFile("ola.js", HttpServer::CONTENT_TYPE_JS);
RegisterFile("tick.gif", HttpServer::CONTENT_TYPE_GIF);
RegisterFile("toolbar-bg.png", HttpServer::CONTENT_TYPE_PNG);
RegisterFile("toolbar.css", HttpServer::CONTENT_TYPE_CSS);
RegisterFile("vertical.gif", HttpServer::CONTENT_TYPE_GIF);
StringVariable *data_dir_var = export_map->GetStringVar(K_DATA_DIR_VAR);
data_dir_var->Set(m_server.DataDir());
Clock::CurrentTime(&m_start_time);
m_start_time_t = time(NULL);
export_map->GetStringVar(K_UPTIME_VAR);
}
/*
* Teardown
*/
OlaHttpServer::~OlaHttpServer() {
if (m_client_socket)
m_server.SelectServer()->RemoveSocket(m_client_socket);
m_client.Stop();
if (m_client_socket)
delete m_client_socket;
}
/**
* Setup the OLA HTTP server
* @return true if this worked, false otherwise.
*/
bool OlaHttpServer::Init() {
bool ret = m_server.Init();
if (ret) {
if (!m_client.Setup()) {
return false;
}
/*
Setup disconnect notifications.
m_socket->SetOnClose(
ola::NewSingleClosure(this, &SimpleClient::SocketClosed));
*/
m_server.SelectServer()->AddSocket(m_client_socket);
}
return ret;
}
/*
* Print the server stats json
* @param request the HttpRequest
* @param response the HttpResponse
* @returns MHD_NO or MHD_YES
*/
int OlaHttpServer::JsonServerStats(const HttpRequest *request,
HttpResponse *response) {
struct tm start_time;
char start_time_str[50];
localtime_r(&m_start_time_t, &start_time);
strftime(start_time_str, sizeof(start_time_str), "%c", &start_time);
stringstream str;
str << "{" << endl;
str << " \"hostname\": \"" << EscapeString(ola::network::FullHostname()) <<
"\"," << endl;
str << " \"ip\": \"" <<
ola::network::AddressToString(m_interface.ip_address) << "\"," << endl;
str << " \"broadcast\": \"" <<
ola::network::AddressToString(m_interface.bcast_address) << "\"," << endl;
str << " \"subnet\": \"" <<
ola::network::AddressToString(m_interface.subnet_address) << "\"," << endl;
str << " \"hw_address\": \"" <<
ola::network::HardwareAddressToString(m_interface.hw_address) << "\","
<< endl;
str << " \"version\": \"" << OLA_VERSION << "\"," << endl;
str << " \"up_since\": \"" << start_time_str << "\"," << endl;
str << " \"quit_enabled\": " << m_enable_quit << "," << endl;
str << "}";
response->SetContentType(HttpServer::CONTENT_TYPE_PLAIN);
response->Append(str.str());
int r = response->Send();
delete response;
return r;
(void) request;
}
/*
* Print the list of universes / plugins as a json string
* @param request the HttpRequest
* @param response the HttpResponse
* @returns MHD_NO or MHD_YES
*/
int OlaHttpServer::JsonUniversePluginList(const HttpRequest *request,
HttpResponse *response) {
bool ok = m_client.FetchPluginList(
NewSingleCallback(this,
&OlaHttpServer::HandlePluginList,
response));
if (!ok)
return m_server.ServeError(response, K_BACKEND_DISCONNECTED_ERROR);
return MHD_YES;
(void) request;
}
/**
* Print the plugin info as a json string
* @param request the HttpRequest
* @param response the HttpResponse
* @returns MHD_NO or MHD_YES
*/
int OlaHttpServer::JsonPluginInfo(const HttpRequest *request,
HttpResponse *response) {
string val = request->GetParameter("id");
int plugin_id = atoi(val.data());
bool ok = m_client.FetchPluginDescription(
(ola_plugin_id) plugin_id,
NewSingleCallback(this,
&OlaHttpServer::HandlePluginInfo,
response));
if (!ok)
return m_server.ServeError(response, K_BACKEND_DISCONNECTED_ERROR);
return MHD_YES;
}
/**
* Return information about a universe
* @param request the HttpRequest
* @param response the HttpResponse
* @returns MHD_NO or MHD_YES
*/
int OlaHttpServer::JsonUniverseInfo(const HttpRequest *request,
HttpResponse *response) {
string uni_id = request->GetParameter("id");
unsigned int universe_id;
if (!StringToUInt(uni_id, &universe_id))
return m_server.ServeNotFound(response);
bool ok = m_client.FetchUniverseInfo(
universe_id,
NewSingleCallback(this,
&OlaHttpServer::HandleUniverseInfo,
response));
if (!ok)
return m_server.ServeError(response, K_BACKEND_DISCONNECTED_ERROR);
return MHD_YES;
(void) request;
}
/**
* Return a list of unbound ports
* @param request the HttpRequest
* @param response the HttpResponse
* @returns MHD_NO or MHD_YES
*/
int OlaHttpServer::JsonAvailablePorts(const HttpRequest *request,
HttpResponse *response) {
string uni_id = request->GetParameter("id");
bool ok = false;
if (uni_id.empty()) {
// get all available ports
ok = m_client.FetchCandidatePorts(
NewSingleCallback(this,
&OlaHttpServer::HandleCandidatePorts,
response));
} else {
unsigned int universe_id;
if (!StringToUInt(uni_id, &universe_id))
return m_server.ServeNotFound(response);
ok = m_client.FetchCandidatePorts(
universe_id,
NewSingleCallback(this,
&OlaHttpServer::HandleCandidatePorts,
response));
}
if (!ok)
return m_server.ServeError(response, K_BACKEND_DISCONNECTED_ERROR);
return MHD_YES;
}
/*
* Create a new universe by binding one or more ports.
* @param request the HttpRequest
* @param response the HttpResponse
* @returns MHD_NO or MHD_YES
*/
int OlaHttpServer::CreateNewUniverse(const HttpRequest *request,
HttpResponse *response) {
string uni_id = request->GetPostParameter("id");
string name = request->GetPostParameter("name");
if (name.size() > K_UNIVERSE_NAME_LIMIT)
name = name.substr(K_UNIVERSE_NAME_LIMIT);
unsigned int universe_id;
if (!StringToUInt(uni_id, &universe_id))
return m_server.ServeNotFound(response);
ActionQueue *action_queue = new ActionQueue(
NewSingleCallback(this,
&OlaHttpServer::CreateUniverseComplete,
response,
universe_id,
!name.empty()));
// add patch actions here
string add_port_ids = request->GetPostParameter("add_ports");
AddPatchActions(action_queue, add_port_ids, universe_id, PATCH);
if (!name.empty())
action_queue->AddAction(
new SetNameAction(&m_client, universe_id, name, false));
action_queue->NextAction();
return MHD_YES;
}
/*
* Modify an existing universe.
* @param request the HttpRequest
* @param response the HttpResponse
* @returns MHD_NO or MHD_YES
*/
int OlaHttpServer::ModifyUniverse(const HttpRequest *request,
HttpResponse *response) {
string uni_id = request->GetPostParameter("id");
string name = request->GetPostParameter("name");
string merge_mode = request->GetPostParameter("merge_mode");
unsigned int universe_id;
if (!StringToUInt(uni_id, &universe_id))
return m_server.ServeNotFound(response);
if (name.empty())
return m_server.ServeError(response, "No name supplied");
if (name.size() > K_UNIVERSE_NAME_LIMIT)
name = name.substr(K_UNIVERSE_NAME_LIMIT);
ActionQueue *action_queue = new ActionQueue(
NewSingleCallback(this,
&OlaHttpServer::ModifyUniverseComplete,
response));
action_queue->AddAction(
new SetNameAction(&m_client, universe_id, name, true));
if (merge_mode == "LTP" || merge_mode == "HTP") {
OlaUniverse::merge_mode mode = (
merge_mode == "LTP" ? OlaUniverse::MERGE_LTP : OlaUniverse::MERGE_HTP);
action_queue->AddAction(
new SetMergeModeAction(&m_client, universe_id, mode));
}
string remove_port_ids = request->GetPostParameter("remove_ports");
AddPatchActions(action_queue, remove_port_ids, universe_id, UNPATCH);
string add_port_ids = request->GetPostParameter("add_ports");
AddPatchActions(action_queue, add_port_ids, universe_id, PATCH);
AddPriorityActions(action_queue, request);
action_queue->NextAction();
return MHD_YES;
}
/*
* Display the index page
* @param request the HttpRequest
* @param response the HttpResponse
* @returns MHD_NO or MHD_YES
*/
int OlaHttpServer::DisplayIndex(const HttpRequest *request,
HttpResponse *response) {
HttpServer::static_file_info file_info;
file_info.file_path = "ola.html";
file_info.content_type = HttpServer::CONTENT_TYPE_HTML;
return m_server.ServeStaticContent(&file_info, response);
(void) request;
}
/*
* Handle the set dmx command
* @param request the HttpRequest
* @param response the HttpResponse
* @returns MHD_NO or MHD_YES
*/
int OlaHttpServer::HandleSetDmx(const HttpRequest *request,
HttpResponse *response) {
string dmx_data_str = request->GetPostParameter("d");
string uni_id = request->GetPostParameter("u");
unsigned int universe_id;
if (!StringToUInt(uni_id, &universe_id))
return m_server.ServeNotFound(response);
DmxBuffer buffer;
buffer.SetFromString(dmx_data_str);
if (!buffer.Size())
return m_server.ServeError(response, "Invalid DMX string");
bool ok = m_client.SendDmx(
universe_id,
buffer,
NewSingleCallback(this, &OlaHttpServer::HandleBoolResponse, response));
if (!ok)
return m_server.ServeError(response, K_BACKEND_DISCONNECTED_ERROR);
return MHD_YES;
}
/*
* Display the debug page
* @param request the HttpRequest
* @param response the HttpResponse
* @returns MHD_NO or MHD_YES
*/
int OlaHttpServer::DisplayDebug(const HttpRequest *request,
HttpResponse *response) {
TimeStamp now;
Clock::CurrentTime(&now);
TimeInterval diff = now - m_start_time;
stringstream str;
str << (diff.AsInt() / 1000);
m_export_map->GetStringVar(K_UPTIME_VAR)->Set(str.str());
vector<BaseVariable*> variables = m_export_map->AllVariables();
response->SetContentType(HttpServer::CONTENT_TYPE_PLAIN);
vector<BaseVariable*>::iterator iter;
for (iter = variables.begin(); iter != variables.end(); ++iter) {
stringstream out;
out << (*iter)->Name() << ": " << (*iter)->Value() << "\n";
response->Append(out.str());
}
int r = response->Send();
delete response;
return r;
(void) request;
}
/*
* Cause the server to shutdown
* @param request the HttpRequest
* @param response the HttpResponse
* @returns MHD_NO or MHD_YES
*/
int OlaHttpServer::DisplayQuit(const HttpRequest *request,
HttpResponse *response) {
if (m_enable_quit) {
response->SetContentType(HttpServer::CONTENT_TYPE_PLAIN);
response->Append("ok");
m_ola_server->StopServer();
} else {
response->SetStatus(403);
response->SetContentType(HttpServer::CONTENT_TYPE_HTML);
response->Append("<b>403 Unauthorized</b>");
}
int r = response->Send();
delete response;
return r;
(void) request;
}
/*
* Reload all plugins
* @param request the HttpRequest
* @param response the HttpResponse
* @returns MHD_NO or MHD_YES
*/
int OlaHttpServer::ReloadPlugins(const HttpRequest *request,
HttpResponse *response) {
m_ola_server->ReloadPlugins();
response->SetContentType(HttpServer::CONTENT_TYPE_PLAIN);
response->Append("ok");
int r = response->Send();
delete response;
return r;
(void) request;
}
/*
* Display a list of registered handlers
*/
int OlaHttpServer::DisplayHandlers(const HttpRequest *request,
HttpResponse *response) {
vector<string> handlers = m_server.Handlers();
vector<string>::const_iterator iter;
response->SetContentType(HttpServer::CONTENT_TYPE_HTML);
response->Append("<html><body><b>Registered Handlers</b><ul>");
for (iter = handlers.begin(); iter != handlers.end(); ++iter) {
response->Append("<li><a href='" + *iter + "'>" + *iter + "</a></li>");
}
response->Append("</ul></body></html>");
int r = response->Send();
delete response;
return r;
(void) request;
}
/*
* Handle the plugin list callback
* @param response the HttpResponse that is associated with the request.
* @param plugins a list of plugins
* @param error an error string.
*/
void OlaHttpServer::HandlePluginList(HttpResponse *response,
const vector<OlaPlugin> &plugins,
const string &error) {
if (!error.empty()) {
m_server.ServeError(response, error);
return;
}
// fire off the universe request now. the main server is running in a
// separate thread.
bool ok = m_client.FetchUniverseList(
NewSingleCallback(this,
&OlaHttpServer::HandleUniverseList,
response));
if (!ok) {
m_server.ServeError(response, K_BACKEND_DISCONNECTED_ERROR);
return;
}
stringstream str;
str << "{" << endl;
str << " \"plugins\": [" << endl;
vector<OlaPlugin>::const_iterator iter;
for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
str << " {\"name\": \"" << EscapeString(iter->Name()) <<
"\", \"id\": " << iter->Id() << "}," << endl;
}
str << " ]," << endl;
response->Append(str.str());
}
/*
* Handle the universe list callback
* @param response the HttpResponse that is associated with the request.
* @param plugins a list of plugins
* @param error an error string.
*/
void OlaHttpServer::HandleUniverseList(HttpResponse *response,
const vector<OlaUniverse> &universes,
const string &error) {
stringstream str;
if (error.empty()) {
str << " \"universes\": [" << endl;
vector<OlaUniverse>::const_iterator iter;
for (iter = universes.begin(); iter != universes.end(); ++iter) {
str << " {" << endl;
str << " \"id\": " << iter->Id() << "," << endl;
str << " \"input_ports\": " << iter->InputPortCount() << "," <<
endl;
str << " \"name\": \"" << EscapeString(iter->Name()) << "\"," <<
endl;
str << " \"output_ports\": " << iter->OutputPortCount() << "," <<
endl;
str << " \"rdm_devices\": " << iter->RDMDeviceCount() << "," <<
endl;
str << " }," << endl;
}
str << " ]," << endl;
}
str << "}";
response->SetContentType(HttpServer::CONTENT_TYPE_PLAIN);
response->Append(str.str());
response->Send();
delete response;
}
/*
* Handle the plugin description response.
* @param response the HttpResponse that is associated with the request.
* @param description the plugin description.
* @param error an error string.
*/
void OlaHttpServer::HandlePluginInfo(HttpResponse *response,
const string &description,
const string &error) {
if (!error.empty()) {
m_server.ServeError(response, error);
return;
}
string escaped_description = description;
Escape(&escaped_description);
response->SetContentType(HttpServer::CONTENT_TYPE_PLAIN);
response->Append("{\"description\": \"");
response->Append(escaped_description);
response->Append("\"}");
response->Send();
delete response;
}
/*
* Handle the universe info
* @param response the HttpResponse that is associated with the request.
* @param universe the OlaUniverse object
* @param error an error string.
*/
void OlaHttpServer::HandleUniverseInfo(HttpResponse *response,
OlaUniverse &universe,
const string &error) {
if (!error.empty()) {
m_server.ServeError(response, error);
return;
}
// fire off the device/port request now. the main server is running in a
// separate thread.
bool ok = m_client.FetchDeviceInfo(
ola::OLA_PLUGIN_ALL,
NewSingleCallback(this,
&OlaHttpServer::HandlePortsForUniverse,
response,
universe.Id()));
if (!ok) {
m_server.ServeError(response, K_BACKEND_DISCONNECTED_ERROR);
return;
}
stringstream str;
str << "{" << endl;
str << " \"id\": " << universe.Id() << "," << endl;
str << " \"name\": \"" << EscapeString(universe.Name()) << "\"," << endl;
str << " \"merge_mode\": \"" <<
(universe.MergeMode() == OlaUniverse::MERGE_HTP ? "HTP" : "LTP") << "\","
<< endl;
response->Append(str.str());
}
void OlaHttpServer::HandlePortsForUniverse(
HttpResponse *response,
unsigned int universe_id,
const vector<OlaDevice> &devices,
const string &error) {
if (error.empty()) {
stringstream input_str, output_str;
vector<OlaDevice>::const_iterator iter = devices.begin();
vector<OlaInputPort>::const_iterator input_iter;
vector<OlaOutputPort>::const_iterator output_iter;
input_str << " \"input_ports\": [" << endl;
output_str << " \"output_ports\": [" << endl;
for (; iter != devices.end(); ++iter) {
const vector<OlaInputPort> &input_ports = iter->InputPorts();
for (input_iter = input_ports.begin(); input_iter != input_ports.end();
++input_iter) {
if (input_iter->IsActive() && input_iter->Universe() == universe_id)
PortToJson(*iter, *input_iter, &input_str, false);
}
const vector<OlaOutputPort> &output_ports = iter->OutputPorts();
for (output_iter = output_ports.begin();
output_iter != output_ports.end(); ++output_iter) {
if (output_iter->IsActive() && output_iter->Universe() == universe_id)
PortToJson(*iter, *output_iter, &output_str, true);
}
}
input_str << " ]," << endl;
output_str << " ]," << endl;
response->Append(input_str.str());
response->Append(output_str.str());
}
response->SetContentType(HttpServer::CONTENT_TYPE_PLAIN);
response->Append("}");
response->Send();
delete response;
}
/*
* Handle the list of candidate ports
* @param response the HttpResponse that is associated with the request.
* @param devices the possbile devices & ports
* @param error an error string.
*/
void OlaHttpServer::HandleCandidatePorts(
HttpResponse *response,
const vector<class OlaDevice> &devices,
const string &error) {
if (!error.empty()) {
m_server.ServeError(response, error);
return;
}
stringstream str;
str << "[" << endl;
vector<OlaDevice>::const_iterator iter = devices.begin();
vector<OlaInputPort>::const_iterator input_iter;
vector<OlaOutputPort>::const_iterator output_iter;
for (; iter != devices.end(); ++iter) {
const vector<OlaInputPort> &input_ports = iter->InputPorts();
for (input_iter = input_ports.begin(); input_iter != input_ports.end();
++input_iter) {
PortToJson(*iter, *input_iter, &str, false);
}
const vector<OlaOutputPort> &output_ports = iter->OutputPorts();
for (output_iter = output_ports.begin();
output_iter != output_ports.end(); ++output_iter) {
PortToJson(*iter, *output_iter, &str, true);
}
}
str << "]" << endl;
response->SetContentType(HttpServer::CONTENT_TYPE_PLAIN);
response->Append(str.str());
response->Send();
delete response;
}
/*
* Schedule a callback to send the new universe response to the client
*/
void OlaHttpServer::CreateUniverseComplete(HttpResponse *response,
unsigned int universe_id,
bool included_name,
class ActionQueue *action_queue) {
// this is a trick to unwind the stack and return control to a method outside
// the Action
m_server.SelectServer()->RegisterSingleTimeout(
0,
NewSingleClosure(this, &OlaHttpServer::SendCreateUniverseResponse,
response, universe_id, included_name, action_queue));
}
/*
* Send the response to a new universe request
*/
void OlaHttpServer::SendCreateUniverseResponse(
HttpResponse *response,
unsigned int universe_id,
bool included_name,
class ActionQueue *action_queue) {
unsigned int action_count = action_queue->ActionCount();
if (included_name)
action_count--;
bool failed = true;
// it only takes one port patch to pass
for (unsigned int i = 0; i < action_count; i++) {
failed &= action_queue->GetAction(i)->Failed();
}
stringstream str;
str << "{" << endl;
str << " \"ok\": " << !failed << "," << endl;
str << " \"universe\": " << universe_id << "," << endl;
str << " \"message\": \"" << (failed ? "Failed to patch any ports" : "") <<
"\"," << endl;
str << "}";
response->SetContentType(HttpServer::CONTENT_TYPE_PLAIN);
response->Append(str.str());
response->Send();
delete action_queue;
delete response;
}
/*
* Schedule a callback to send the modify universe response to the client
*/
void OlaHttpServer::ModifyUniverseComplete(HttpResponse *response,
ActionQueue *action_queue) {
// this is a trick to unwind the stack and return control to a method outside
// the Action
m_server.SelectServer()->RegisterSingleTimeout(
0,
NewSingleClosure(this, &OlaHttpServer::SendModifyUniverseResponse,
response, action_queue));
}
/*
* Send the response to a modify universe request.
*/
void OlaHttpServer::SendModifyUniverseResponse(HttpResponse *response,
ActionQueue *action_queue) {
if (!action_queue->WasSuccessful()) {
delete action_queue;
m_server.ServeError(response, "Update failed");
} else {
response->SetContentType(HttpServer::CONTENT_TYPE_PLAIN);
response->Append("ok");
response->Send();
delete action_queue;
delete response;
}
}
/*
* Handle the set DMX response.
* @param response the HttpResponse that is associated with the request.
* @param error an error string.
*/
void OlaHttpServer::HandleBoolResponse(HttpResponse *response,
const string &error) {
if (!error.empty()) {
m_server.ServeError(response, error);
return;
}
response->SetContentType(HttpServer::CONTENT_TYPE_PLAIN);
response->Append("ok");
response->Send();
delete response;
}
/*
* Register a handler
*/
inline void OlaHttpServer::RegisterHandler(
const string &path,
int (OlaHttpServer::*method)(const HttpRequest*, HttpResponse*)) {
m_server.RegisterHandler(
path,
NewCallback<OlaHttpServer, int, const HttpRequest*, HttpResponse*>(
this,
method));
}
/*
* Register a static file
*/
inline void OlaHttpServer::RegisterFile(const string &file,
const string &content_type) {
m_server.RegisterFile("/" + file, file, content_type);
}
/**
* Add the json representation of this port to the stringstream
*/
void OlaHttpServer::PortToJson(const OlaDevice &device,
const OlaPort &port,
stringstream *str,
bool is_output) {
*str << " {" << endl;
*str << " \"device\": \"" << EscapeString(device.Name())
<< "\"," << endl;
*str << " \"description\": \"" <<
EscapeString(port.Description()) << "\"," << endl;
*str << " \"id\": \"" << device.Alias() << "-" <<
(is_output ? "O" : "I") << "-" << port.Id() << "\"," << endl;
*str << " \"is_output\": " << (is_output ? "true" : "false") << "," <<
endl;
if (port.PriorityCapability() != CAPABILITY_NONE) {
*str << " \"priority\": {" << endl;
*str << " \"value\": " << static_cast<int>(port.Priority()) <<
"," << endl;
if (port.PriorityCapability() == CAPABILITY_FULL) {
*str << " \"current_mode\": \"" <<
(port.PriorityMode() == PRIORITY_MODE_INHERIT ?
"inherit" : "override") << "\"," <<
endl;
}
*str << " }" << endl;
}
*str << " }," << endl;
}
/*
* Add the Patch Actions to the ActionQueue.
* @param action_queue the ActionQueue to add the actions to.
* @param port_id_string a string to ports to add/remove.
* @param universe the universe id to add these ports if
* @param port_action either PATCH or UNPATCH.
*/
void OlaHttpServer::AddPatchActions(ActionQueue *action_queue,
const string port_id_string,
unsigned int universe,
PatchAction port_action) {
vector<port_identifier> ports;
vector<port_identifier>::const_iterator iter;
DecodePortIds(port_id_string, &ports);
if (!ports.size())
return;
for (iter = ports.begin(); iter != ports.end(); ++iter) {
action_queue->AddAction(new PatchPortAction(
&m_client,
iter->device_alias,
iter->port,
iter->direction,
universe,
port_action));
}
}
/*
* Add the Priority Actions to the ActionQueue.
* @param action_queue the ActionQueue to add the actions to.
* @param request the HttpRequest to read the url params from.
*/
void OlaHttpServer::AddPriorityActions(ActionQueue *action_queue,
const HttpRequest *request) {
string port_ids = request->GetPostParameter("modify_ports");
vector<port_identifier> ports;
vector<port_identifier>::const_iterator iter;
DecodePortIds(port_ids, &ports);
if (!ports.size())
return;
for (iter = ports.begin(); iter != ports.end(); ++iter) {
string priority_mode_id = iter->string_id + K_PRIORITY_MODE_SUFFIX;
string priority_id = iter->string_id + K_PRIORITY_VALUE_SUFFIX;
string mode = request->GetPostParameter(priority_mode_id);
if (mode == "0") {
action_queue->AddAction(new PortPriorityInheritAction(
&m_client,
iter->device_alias,
iter->port,
iter->direction));
} else if (mode == "1" || mode == "") {
// an empty mode param means this is a static port
string value = request->GetPostParameter(priority_id);
uint8_t priority_value;
if (StringToUInt8(value, &priority_value)) {
action_queue->AddAction(new PortPriorityOverrideAction(
&m_client,
iter->device_alias,
iter->port,
iter->direction,
priority_value));
}
}
}
}
/*
* Decode port ids in a string.
* This converts a string like "4-I-1,2-O-3" into a vector of port identifiers.
* @param port_ids the port ids in a , separated string
* @param ports a vector of port_identifiers that will be filled.
*/
void OlaHttpServer::DecodePortIds(const string &port_ids,
vector<port_identifier> *ports) {
vector<string> port_strings;
StringSplit(port_ids, port_strings, ",");
vector<string>::const_iterator iter;
vector<string> tokens;
for (iter = port_strings.begin(); iter != port_strings.end(); ++iter) {
if (iter->empty())
continue;
tokens.clear();
StringSplit(*iter, tokens, "-");
if (tokens.size() != 3 || (tokens[1] != "I" && tokens[1] != "O")) {
OLA_INFO << "Not a valid port id " << *iter;
continue;
}
unsigned int device_alias, port;
if (!StringToUInt(tokens[0], &device_alias) ||
!StringToUInt(tokens[2], &port)) {
OLA_INFO << "Not a valid port id " << *iter;
continue;
}
PortDirection direction = tokens[1] == "I" ? INPUT_PORT : OUTPUT_PORT;
port_identifier port_id = {device_alias, port, direction, *iter};
ports->push_back(port_id);
}
}
} // ola