resolved merge conflict

This commit is contained in:
Johannes Wendel
2019-08-01 20:32:50 +02:00
23 changed files with 1594 additions and 9 deletions

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.6.2)
project(flippR_driver_networking)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/cli/networking)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin/networking)
set(SOURCES
input/InputSocketHandler.cpp
output/OutputRequestHandler.cpp

View File

@@ -57,7 +57,7 @@ void FlippRServer::parse_server_config_file()
try
{
config.open("./server_config.json");
config.open(this->server_config);
}
catch(const std::exception e)
{
@@ -85,6 +85,15 @@ void FlippRServer::parse_server_config_file()
config.close();
}
void FlippRServer::uninitialize()
{
this->output_driver->deactivate_all_lamps();
this->output_driver->deactivate_displays();
this->output_server->stop();
ServerApplication::uninitialize();
}
/**
* Initially called before main.
*/
@@ -93,10 +102,14 @@ void FlippRServer::initialize(Application &self)
//Todo May restructure with subsystems
//make this one application and subsystems ServerApplications
this->initialize_output_driver();
this->initialize_input_driver();
this->output_server = std::unique_ptr<Poco::Net::HTTPServer>(this->build_output_server());
this->output_server->start();
this->input_server = std::unique_ptr<TCPServer>(this->build_input_server());
//https://gist.github.com/NIPE-SYSTEMS/5a06428c0880ed7ff3cc4304be436e3e
ServerApplication::initialize(self);
}
@@ -162,7 +175,6 @@ int FlippRServer::main(const std::vector<std::string>& args)
this->output_driver->deactivate_all_lamps();
this->output_driver->deactivate_displays();
output_server->stop();
return Application::EXIT_OK;
}
@@ -189,8 +201,6 @@ TCPServer* FlippRServer::build_input_server()
return new TCPServer(new input::InputSocketHandlerFactory(this->input_driver), port);
}
void FlippRServer::defineOptions(OptionSet& options)
{
ServerApplication::defineOptions(options);
@@ -249,6 +259,12 @@ void FlippRServer::defineOptions(OptionSet& options)
.repeatable(false)
.callback(OptionCallback<FlippRServer>(this, &FlippRServer::handle_config_file))
.argument("display-config", true));
options.addOption(Option("server-config", "s", "Specify where the server-config file is located. Only needed when not in this folder.")
.required(this->display_config == "Not set")
.repeatable(false)
.callback(OptionCallback<FlippRServer>(this, &FlippRServer::handle_config_file))
.argument("server-config", true));
}
void FlippRServer::handle_config_file(const std::string &name, const std::string &value)
@@ -269,6 +285,8 @@ void FlippRServer::handle_config_file(const std::string &name, const std::string
this->input_port = std::stoi(value);
else if(name == "output-port")
this->output_port = std::stoi(value);
else if(name == "server-config")
this->server_config = value;
else
{
logger().information("Configuration \"" + name + "\" is not known.");
@@ -298,6 +316,8 @@ std::string FlippRServer::get_runtime_dir()
{
runtime_dir = DEFAULT_RUNTIME_DIR;
}
return runtime_dir;
}
}

View File

@@ -24,6 +24,7 @@ public:
int main(const std::vector<std::string>& args);
void initialize(Poco::Util::Application& self);
void uninitialize();
void defineOptions(Poco::Util::OptionSet& options);
void handle_help(const std::string &name, const std::string &port);
@@ -38,7 +39,6 @@ private:
Poco::Net::HTTPServer* build_output_server();
Poco::Net::TCPServer* build_input_server();
private:
const std::string DEFAULT_RUNTIME_DIR = "/tmp/flippR_driver-runtime/";
const std::string SOCKET_NAME = "S.flippR_driver";
@@ -53,9 +53,14 @@ private:
std::string solenoid_config;
std::string sound_config;
std::string display_config;
std::string server_config;
std::shared_ptr<input::InputDriver> input_driver;
std::shared_ptr<output::OutputDriver> output_driver;
std::unique_ptr<Poco::Net::HTTPServer> output_server;
std::unique_ptr<Poco::Net::TCPServer> input_server;
};
};

View File

@@ -0,0 +1,261 @@
//
// Created by rhetenor on 3/6/19.
//
#include <Poco/Net/HTTPServerResponse.h>
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Exception.h>
#include <string>
#include "OutputRequestHandler.h"
namespace flippR_driver
{
namespace networking
{
using namespace Poco;
using namespace Poco::Net;
OutputRequestHandler::OutputRequestHandler(std::shared_ptr<output::OutputDriver> 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();
return;
}
if(item_type == "activate")
{
this->output_driver->activate_displays();
return;
}
response.setContentType("text/json");
response.setStatus(HTTPServerResponse::HTTP_OK);
try
{
boost::optional<Poco::JSON::Object> json_response = parseRequest(item_type, item_name, action, score);
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<Poco::JSON::Object> 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
{
throw new Poco::NotFoundException("No item type called " + item_type);
}
}
boost::optional<Poco::JSON::Object> 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<Poco::JSON::Object> 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<Poco::JSON::Object> 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<Poco::JSON::Object> 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 {};
}
std::vector<std::string> OutputRequestHandler::getPathSegments(Poco::URI uri)
{
std::vector<std::string> path_segments;
uri.getPathSegments(path_segments);
return path_segments;
}
}
}