// // 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 #include #include #include #include #include #include #include #include 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(); } 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(this->build_output_server()); this->output_server->start(); this->input_server = std::unique_ptr(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& 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( 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(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(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(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() { const char* runtime_dir = std::getenv("XDG_RUNTIME_DIR"); if(&runtime_dir == nullptr) { runtime_dir = DEFAULT_RUNTIME_DIR; } return runtime_dir; } } }