// // Created by rhetenor on 3/6/19. // #include #include #include #include #include "OutputRequestHandler.h" namespace flippR_driver { namespace networking { using namespace Poco; using namespace Poco::Net; OutputRequestHandler::OutputRequestHandler(std::shared_ptr output_driver) : output_driver(output_driver) {} /** * Handles a REST request with a URI form of: * * address/{item_type}/[item_name]/[action]/[score] * * Where * {item_type} is either solenoids, lamps, sounds, displays, or one of the two special events: activate and deactivate * [item_name] is the string name of an item (optional if you want to get the list of all available items) * [action] is the particular action for the item: * Solenoids: trigger * lamps: activate, deactivate, status * sounds: play * displays: write_score (for this is the additional optional attribute [score] * * @param request * @param response */ void OutputRequestHandler::handleRequest(HTTPServerRequest &request, HTTPServerResponse &response) { auto path_segments = getPathSegments(URI(request.getURI())); // fill up vector for(int i = path_segments.size(); i < 4; i++) { path_segments.emplace_back(""); } std::string item_type = path_segments.at(0); std::string item_name = path_segments.at(1); std::string action = path_segments.at(2); std::string score = path_segments.at(3); if(item_type == "deactivate") { this->output_driver->deactivate_displays(); this->output_driver->deactivate_all_lamps(); this->output_driver->deactivate_all_flipper_relays(); return; } if(item_type == "activate") { this->output_driver->activate_displays(); this->output_driver->activate_all_flipper_relays(); return; } response.setContentType("text/json"); response.setStatus(HTTPServerResponse::HTTP_OK); try { boost::optional json_response = parseRequest(item_type, item_name, action, score); json_response->stringify(std::cout); if(json_response) { std::ostream& ostr = response.send(); json_response->stringify(ostr); } } catch(const NotFoundException &e) { response.setStatusAndReason(HTTPServerResponse::HTTP_NOT_FOUND, e.displayText()); } catch(const Poco::InvalidArgumentException &e) { response.setStatusAndReason(HTTPServerResponse::HTTP_BAD_REQUEST, e.displayText()); } } boost::optional OutputRequestHandler::parseRequest(const std::string& item_type, const std::string& item_name, const std::string& action, const std::string& score) { if(item_type == "solenoids") { return parseSolenoid(item_name, action); } else if(item_type == "lamps") { return parseLamp(item_name, action); } else if(item_type == "sounds") { return parseSound(item_name, action); } else if(item_type == "displays") { return parseDisplay(item_name, action, score); } else if(item_type == "flippers") { return parseFlipper(item_name, action); } else { throw new Poco::NotFoundException("No item type called " + item_type); } } boost::optional OutputRequestHandler::parseSolenoid(const std::string& item_name, const std::string& action) { if(item_name == "") { Poco::JSON::Object response; response.set("solenoids", this->output_driver->get_solenoids()); return response; } auto opt_solenoid = this->output_driver->get_solenoid(item_name); if(!opt_solenoid) { throw new Poco::NotFoundException("No solenoid with name \"" + item_name + "\"!"); } auto solenoid = opt_solenoid->get(); if(action == "trigger") { solenoid->trigger(); } else { throw new Poco::NotFoundException("No action with name \"" + action + "\" on solenoids!"); } return {}; } boost::optional OutputRequestHandler::parseLamp(const std::string& item_name, const std::string& action) { if(item_name == "") { Poco::JSON::Object response; response.set("lamps", this->output_driver->get_lamps()); return response; } auto opt_lamp = this->output_driver->get_lamp(item_name); if(!opt_lamp) { throw new Poco::NotFoundException("No lamp with name \"" + item_name + "\"!"); } auto lamp = opt_lamp->get(); if(action == "activate") { lamp->activate(); } else if(action == "deactivate") { lamp->deactivate(); } else { throw new Poco::NotFoundException("No action with name \"" + action + "\" on lamps!"); } return {}; } boost::optional OutputRequestHandler::parseSound(const std::string& item_name, const std::string& action) { if(item_name == "") { Poco::JSON::Object response; response.set("sounds", this->output_driver->get_sounds()); return response; } auto opt_sound = this->output_driver->get_sound(item_name); if(!opt_sound) { throw new Poco::NotFoundException("No sound with name \"" + item_name + "\"!"); } auto sound = opt_sound->get(); if(action == "play") { sound->play(); } else { throw new Poco::NotFoundException("No action with name \"" + action + "\" on sounds!"); } return {}; } boost::optional OutputRequestHandler::parseDisplay(const std::string& item_name, const std::string& action, const std::string& score) { if(item_name == "") { Poco::JSON::Object response; response.set("displays", this->output_driver->get_displays()); return response; } uint8_t display_number = std::stoi(item_name); auto opt_display = this->output_driver->get_display(display_number); if(!opt_display) { throw new Poco::NotFoundException("No display with number \"" + item_name + "\"!"); } auto display = opt_display->get(); if(action == "write_score") { try { unsigned int numerical_score = std::stoi(score); display->write_score(numerical_score); } catch(std::invalid_argument &e) { throw new Poco::InvalidArgumentException("Could not convert " + score + " to a number!\n" + e.what()); } } else { throw new Poco::NotFoundException("No Action with name \"" + action + "\" on sounds!"); } return {}; } boost::optional OutputRequestHandler::parseFlipper(const std::string& item_name, const std::string& action) { if(item_name == "") { Poco::JSON::Object response; response.set("flippers", this->output_driver->get_flippers()); return response; } auto opt_flipper = this->output_driver->get_flipper(item_name); if(!opt_flipper) { throw new Poco::NotFoundException("No flipper with name \"" + item_name + "\"!"); } auto flipper = opt_flipper->get(); if(action == "activate") { flipper->activate(); } else if(action == "deactivate") { flipper->deactivate(); } else { throw new Poco::NotFoundException("No action with name \"" + action + "\" on flippers!"); } return {}; } std::vector OutputRequestHandler::getPathSegments(Poco::URI uri) { std::vector path_segments; uri.getPathSegments(path_segments); return path_segments; } } }