270 lines
7.3 KiB
C++
270 lines
7.3 KiB
C++
//
|
|
// Created by rhetenor on 5/21/19.
|
|
//
|
|
|
|
#include "FlippRServer.h"
|
|
#include "output/OutputRequestHandlerFactory.h"
|
|
#include "input/InputSocketHandlerFactory.h"
|
|
#include "DriverFactory.h"
|
|
#include "utility/Colors.h"
|
|
|
|
#include <Poco/Net/SocketAddress.h>
|
|
#include <Poco/Net/ServerSocket.h>
|
|
#include <Poco/Net/HTTPServer.h>
|
|
#include <Poco/Util/HelpFormatter.h>
|
|
#include <Poco/JSON/Parser.h>
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <algorithm>
|
|
#include <numeric>
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
std::cout << FGRN("Starting FlippR-Server ... ") << std::endl;
|
|
|
|
flippR_driver::networking::FlippRServer app;
|
|
return app.run(argc, argv);
|
|
}
|
|
|
|
namespace flippR_driver
|
|
{
|
|
namespace networking
|
|
{
|
|
using namespace Poco::Net;
|
|
using namespace Poco::Util;
|
|
using namespace Poco::JSON;
|
|
using namespace Poco;
|
|
|
|
FlippRServer::FlippRServer() :
|
|
help_requested(false),
|
|
input_port(9980),
|
|
output_port(9981)
|
|
{}
|
|
|
|
void FlippRServer::parse_server_config_file()
|
|
{
|
|
std::ifstream config;
|
|
|
|
Parser parser;
|
|
Object::Ptr json;
|
|
|
|
try
|
|
{
|
|
config.open(this->server_config);
|
|
}
|
|
catch(const std::exception e)
|
|
{
|
|
logger().error(FCYN("server_config.json not specified!"));
|
|
exit(Application::EXIT_USAGE);
|
|
}
|
|
|
|
try
|
|
{
|
|
auto parse = parser.parse(config);
|
|
json = parse.extract<Object::Ptr>();
|
|
}
|
|
catch(const std::exception e)
|
|
{
|
|
logger().error(e.what());
|
|
exit(Application::EXIT_IOERR);
|
|
}
|
|
|
|
logger().information(FCYN("Parsing server_config.json..."));
|
|
|
|
Object::NameList keys = json->getNames();
|
|
std::sort(keys.begin(), keys.end());
|
|
|
|
if(!std::includes(keys.begin(), keys.end(), REQUIRED_CONFIG_KEYS.begin(), REQUIRED_CONFIG_KEYS.end()))
|
|
{
|
|
std::string config_keys;
|
|
config_keys = std::accumulate(REQUIRED_CONFIG_KEYS.begin(), REQUIRED_CONFIG_KEYS.end(), config_keys);
|
|
logger().error("Need all of the following keys to be specified in server_config json" + config_keys);
|
|
Application::EXIT_USAGE;
|
|
}
|
|
|
|
this->configs = *json;
|
|
|
|
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.
|
|
*/
|
|
void FlippRServer::initialize(Application &self)
|
|
{
|
|
this->parse_server_config_file();
|
|
//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);
|
|
}
|
|
|
|
void FlippRServer::initialize_output_driver()
|
|
{
|
|
std::ifstream lamp_config_stream;
|
|
std::ifstream solenoid_config_stream;
|
|
std::ifstream sound_config_stream;
|
|
std::ifstream display_config_stream;
|
|
|
|
try
|
|
{
|
|
lamp_config_stream.open(this->configs["lamp-config"].toString());
|
|
solenoid_config_stream.open(this->configs["solenoid-config"].toString());
|
|
sound_config_stream.open(this->configs["sound-config"].toString());
|
|
display_config_stream.open(this->configs["display-config"].toString());
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
logger().error(e.what());
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
this->output_driver = flippR_driver::get_OutputDriver(solenoid_config_stream,
|
|
lamp_config_stream,
|
|
sound_config_stream,
|
|
display_config_stream);
|
|
}
|
|
|
|
void FlippRServer::initialize_input_driver()
|
|
{
|
|
std::ifstream input_config_stream;
|
|
std::ifstream matrix_config_stream;
|
|
|
|
try
|
|
{
|
|
input_config_stream.open(this->configs["input-config"].toString());
|
|
matrix_config_stream.open(this->configs["matrix-config"].toString());
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
logger().error(e.what());
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
this->input_driver = flippR_driver::get_InputDriver(input_config_stream, matrix_config_stream);
|
|
}
|
|
|
|
int FlippRServer::main(const std::vector<std::string>& args)
|
|
{
|
|
if(!help_requested)
|
|
{
|
|
logger().information("Server running!");
|
|
waitForTerminationRequest();
|
|
}
|
|
return Application::EXIT_OK;
|
|
|
|
}
|
|
|
|
HTTPServer* FlippRServer::build_output_server()
|
|
{
|
|
unsigned short port = (unsigned short) config().getInt("FlippRServer.port", this->output_port);
|
|
|
|
std::string runtime_dir = this->get_runtime_dir();
|
|
|
|
SocketAddress address(runtime_dir + SOCKET_NAME);
|
|
ServerSocket server_socket(address);
|
|
|
|
return new HTTPServer(new OutputRequestHandlerFactory(this->output_driver), server_socket, new HTTPServerParams);
|
|
}
|
|
|
|
TCPServer* FlippRServer::build_input_server()
|
|
{
|
|
unsigned short port = (unsigned short) config().getInt("FlippRServer.port", this->output_port);
|
|
|
|
std::string runtime_dir = this->get_runtime_dir();
|
|
SocketAddress address(runtime_dir + SOCKET_NAME);
|
|
ServerSocket server_socket(address);
|
|
|
|
return new TCPServer(new input::InputSocketHandlerFactory(this->input_driver), port);
|
|
}
|
|
|
|
void FlippRServer::defineOptions(OptionSet& options)
|
|
{
|
|
ServerApplication::defineOptions(options);
|
|
|
|
options.addOption(
|
|
Option("help", "h", "display this help")
|
|
.required(false)
|
|
.repeatable(false)
|
|
.callback(OptionCallback<FlippRServer>(
|
|
this, &FlippRServer::handle_help)));
|
|
|
|
options.addOption(Option("input-port", "i", "Define the port for the TCP-Input-Server, which represents the flipper inputs. Default 9980")
|
|
.required(false)
|
|
.repeatable(false)
|
|
.callback(OptionCallback<FlippRServer>(this, &FlippRServer::handle_config_file))
|
|
.argument("input-port", true));
|
|
|
|
options.addOption(Option("output-port", "o", "Define the port for the HTTP-Output-Server, which represents the flipper outputs. Default 9981")
|
|
.required(false)
|
|
.repeatable(false)
|
|
.callback(OptionCallback<FlippRServer>(this, &FlippRServer::handle_config_file))
|
|
.argument("output-port", true));
|
|
|
|
options.addOption(Option("server-config", "s", "Specify where the server-config file with paths to the other configs is located. Only needed when not in this folder.")
|
|
.required(true)
|
|
.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)
|
|
{
|
|
if(name == "input-port")
|
|
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.");
|
|
return;
|
|
}
|
|
logger().information("Set " + name + " to " + value);
|
|
}
|
|
|
|
void FlippRServer::handle_help(const std::string& name, const std::string& value)
|
|
{
|
|
Poco::Util::HelpFormatter helpFormatter(options());
|
|
helpFormatter.setCommand(commandName());
|
|
helpFormatter.setUsage("OPTIONS");
|
|
helpFormatter.setHeader(
|
|
"The FlippR-Server, one must specify a json with all needed config files.");
|
|
helpFormatter.format(std::cout);
|
|
stopOptionsProcessing();
|
|
help_requested = true;
|
|
}
|
|
|
|
std::string FlippRServer::get_runtime_dir()
|
|
{
|
|
std::string runtime_dir = std::getenv("XDG_RUNTIME_DIR");
|
|
if(&runtime_dir == nullptr)
|
|
{
|
|
runtime_dir = DEFAULT_RUNTIME_DIR;
|
|
}
|
|
|
|
return runtime_dir;
|
|
}
|
|
|
|
}
|
|
} |