/* * 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 #include #include #include #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 variables = m_export_map->AllVariables(); response->SetContentType(HttpServer::CONTENT_TYPE_PLAIN); vector::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("403 Unauthorized"); } 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 handlers = m_server.Handlers(); vector::const_iterator iter; response->SetContentType(HttpServer::CONTENT_TYPE_HTML); response->Append("Registered Handlers
    "); for (iter = handlers.begin(); iter != handlers.end(); ++iter) { response->Append("
  • " + *iter + "
  • "); } response->Append("
"); 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 &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::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 &universes, const string &error) { stringstream str; if (error.empty()) { str << " \"universes\": [" << endl; vector::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 &devices, const string &error) { if (error.empty()) { stringstream input_str, output_str; vector::const_iterator iter = devices.begin(); vector::const_iterator input_iter; vector::const_iterator output_iter; input_str << " \"input_ports\": [" << endl; output_str << " \"output_ports\": [" << endl; for (; iter != devices.end(); ++iter) { const vector &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 &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 &devices, const string &error) { if (!error.empty()) { m_server.ServeError(response, error); return; } stringstream str; str << "[" << endl; vector::const_iterator iter = devices.begin(); vector::const_iterator input_iter; vector::const_iterator output_iter; for (; iter != devices.end(); ++iter) { const vector &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 &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( 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(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 ports; vector::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 ports; vector::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 *ports) { vector port_strings; StringSplit(port_ids, port_strings, ","); vector::const_iterator iter; vector 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