# HG changeset patch # User František Kučera # Date 1649365452 -7200 # Node ID 4b05b16b97e6541dadbe72e81ab84b44fc7812e0 # Parent 23c516259cc54d4d7743da50ec19e5b2baf58f34 configurable TCP listener port + RequestHandler interface diff -r 23c516259cc5 -r 4b05b16b97e6 bash-completion.sh --- a/bash-completion.sh Thu Apr 07 21:06:37 2022 +0200 +++ b/bash-completion.sh Thu Apr 07 23:04:12 2022 +0200 @@ -22,54 +22,10 @@ w2=${COMP_WORDS[COMP_CWORD-2]} w3=${COMP_WORDS[COMP_CWORD-3]} - DATA_TYPE=( - "string" - "integer" - "boolean" - ) - - INPUT_ATTRIBUTE_POLICY=( - "append" - "prepend" - "auto" - ) - - # FIXME: user must type " and then press TAB otherwise the completion is broken due to the : colon - # - # can be fixed by global modification of environment variable: - # COMP_WORDBREAKS=${COMP_WORDBREAKS//:} - # but it will affect other completions (where : is a separator) - # - # these functions should help: - # _get_comp_words_by_ref -n : cur - # __ltrim_colon_completions "$cur" - # but was not working (despite w0 renamed to cur) - XMLNS=( - "tag:globalcode.info,2018:relpipe" - "http://www.w3.org/1999/xhtml" - "http://www.w3.org/2000/svg" - "http://www.w3.org/2005/Atom" - "http://docbook.org/ns/docbook" - ) - - - if [[ "$w1" == "--relation" && "x$w0" == "x" ]]; then COMPREPLY=("'.*'") - elif [[ "$w1" == "--where" && "x$w0" == "x" ]]; then COMPREPLY=("''") - elif [[ "$w1" == "--xml-attribute" && "x$w0" == "x" ]]; then COMPREPLY=("''") - elif [[ "$w1" == "--output-attribute" && "x$w0" == "x" ]]; then COMPREPLY=("''") - elif [[ "$w2" == "--output-attribute" ]]; then COMPREPLY=($(compgen -W "${DATA_TYPE[*]}" -- "$w0")) - elif [[ "$w3" == "--output-attribute" && "x$w0" == "x" ]]; then COMPREPLY=("''") - elif [[ "$w1" == "--namespace" && "x$w0" == "x" ]]; then COMPREPLY=("''") - elif [[ "$w2" == "--namespace" ]]; then COMPREPLY=($(compgen -W "${XMLNS[*]}" -- "$w0")) - elif [[ "$w1" == "--input-attributes" ]]; then COMPREPLY=($(compgen -W "${INPUT_ATTRIBUTE_POLICY[*]}" -- "$w0")) + if [[ "$w1" == "--tcp-port" && "x$w0" == "x" ]]; then COMPREPLY=("8080") else OPTIONS=( - "--namespace" - "--relation" - "--where" - "--output-attribute" - "--input-attributes" - "--xml-attribute" + "--tcp-port" ) COMPREPLY=($(compgen -W "${OPTIONS[*]}" -- "$w0")) fi diff -r 23c516259cc5 -r 4b05b16b97e6 src/CLIParser.h --- a/src/CLIParser.h Thu Apr 07 21:06:37 2022 +0200 +++ b/src/CLIParser.h Thu Apr 07 23:04:12 2022 +0200 @@ -36,76 +36,20 @@ else throw relpipe::cli::RelpipeCLIException(L"Missing CLI argument" + (i > 0 ? (L" after " + arguments[i - 1]) : L""), relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); } - /** - * TODO: use a common method - */ - bool parseBoolean(const relpipe::common::type::StringX& value) { - if (value == L"true") return true; - else if (value == L"false") return false; - else throw relpipe::cli::RelpipeCLIException(L"Unable to parse boolean value: " + value + L" (expecting true or false)", relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); - } - - void addRelation(Configuration& c, RelationConfiguration& currentRelation) { - if (currentRelation.relation.size()) { - c.relationConfigurations.push_back(currentRelation); - currentRelation = RelationConfiguration(); - } - } - - /** - * TODO: use a common method - */ - relpipe::writer::TypeId parseTypeId(const relpipe::common::type::StringX& value) { - using t = relpipe::writer::TypeId; - if (value == L"string") return t::STRING; - else if (value == L"integer") return t::INTEGER; - else if (value == L"boolean") return t::BOOLEAN; - else throw relpipe::cli::RelpipeCLIException(L"Unable to parse TypeId: " + value, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); - } - public: - static const relpipe::common::type::StringX OPTION_NAMESPACE; - static const relpipe::common::type::StringX OPTION_RELATION; - static const relpipe::common::type::StringX OPTION_WHERE; - static const relpipe::common::type::StringX OPTION_INPUT_ATTRIBUTES; - static const relpipe::common::type::StringX OPTION_OUTPUT_ATTRIBUTE; - static const relpipe::common::type::StringX OPTION_XML_ATTRIBUTE; + static const relpipe::common::type::StringX OPTION_TCP_PORT; Configuration parse(const std::vector& arguments) { Configuration c; - RelationConfiguration currentRelation; for (int i = 0; i < arguments.size();) { relpipe::common::type::StringX option = readNext(arguments, i); - if (option == OPTION_NAMESPACE) { - c.namespaceMappings.push_back(readNext(arguments, i)); - c.namespaceMappings.push_back(readNext(arguments, i)); - } else if (option == OPTION_RELATION) { - addRelation(c, currentRelation); // previous relation - currentRelation.relation = readNext(arguments, i); - } else if (option == OPTION_WHERE) { - currentRelation.where = readNext(arguments, i); - } else if (option == OPTION_XML_ATTRIBUTE) { - currentRelation.xmlAttributes.push_back(readNext(arguments, i)); - } else if (option == OPTION_OUTPUT_ATTRIBUTE) { - AttributeRecipe attribute; - attribute.name = readNext(arguments, i); - attribute.type = parseTypeId(readNext(arguments, i)); - attribute.httpd = readNext(arguments, i); - currentRelation.outputAttributes.push_back(attribute); - } else if (option == OPTION_INPUT_ATTRIBUTES) { - relpipe::common::type::StringX policyName = readNext(arguments, i); - InputAttributePolicy policy; - if (policyName == L"append") policy = InputAttributePolicy::Append; - else if (policyName == L"prepend") policy = InputAttributePolicy::Prepend; - else if (policyName == L"auto") policy = InputAttributePolicy::Auto; - else throw relpipe::cli::RelpipeCLIException(L"Unsupported input attributes policy: " + policyName, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); - currentRelation.inputAttributePolicy = policy; + if (option == OPTION_TCP_PORT) { + c.tcpPort = stoi(readNext(arguments, i)); } else throw relpipe::cli::RelpipeCLIException(L"Unsupported CLI option: " + option, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); } - addRelation(c, currentRelation); // last relation return c; } @@ -114,12 +58,7 @@ } }; -const relpipe::common::type::StringX CLIParser::OPTION_NAMESPACE = L"--namespace"; -const relpipe::common::type::StringX CLIParser::OPTION_RELATION = L"--relation"; -const relpipe::common::type::StringX CLIParser::OPTION_WHERE = L"--where"; -const relpipe::common::type::StringX CLIParser::OPTION_INPUT_ATTRIBUTES = L"--input-attributes"; -const relpipe::common::type::StringX CLIParser::OPTION_OUTPUT_ATTRIBUTE = L"--output-attribute"; -const relpipe::common::type::StringX CLIParser::OPTION_XML_ATTRIBUTE = L"--xml-attribute"; +const relpipe::common::type::StringX CLIParser::OPTION_TCP_PORT = L"--tcp-port"; } } diff -r 23c516259cc5 -r 4b05b16b97e6 src/Configuration.h --- a/src/Configuration.h Thu Apr 07 21:06:37 2022 +0200 +++ b/src/Configuration.h Thu Apr 07 23:04:12 2022 +0200 @@ -25,40 +25,9 @@ namespace tr { namespace httpd { -enum class InputAttributePolicy { - Prepend, - Append, - Auto -}; - -class AttributeRecipe { -public: - - virtual ~AttributeRecipe() { - } - - relpipe::common::type::StringX name; - relpipe::writer::TypeId type; - relpipe::common::type::StringX httpd; -}; - -class RelationConfiguration { -public: - - virtual ~RelationConfiguration() { - } - - relpipe::common::type::StringX relation; - relpipe::common::type::StringX where; - InputAttributePolicy inputAttributePolicy = InputAttributePolicy::Auto; - std::vector outputAttributes; - std::vector xmlAttributes; -}; - class Configuration { public: - std::vector relationConfigurations; - std::vector namespaceMappings; + uint16_t tcpPort = 8080; virtual ~Configuration() { } diff -r 23c516259cc5 -r 4b05b16b97e6 src/HTTPDHandler.h --- a/src/HTTPDHandler.h Thu Apr 07 21:06:37 2022 +0200 +++ b/src/HTTPDHandler.h Thu Apr 07 23:04:12 2022 +0200 @@ -45,7 +45,6 @@ shared_ptr relationalWriter; Configuration configuration; std::shared_ptr httpServer; - RelationConfiguration* currentRelationConfiguration = nullptr; std::vector currentReaderMetadata; std::vector currentWriterMetadata; size_t currentAttributeIndex = 0; diff -r 23c516259cc5 -r 4b05b16b97e6 src/HTTPServer.cpp --- a/src/HTTPServer.cpp Thu Apr 07 21:06:37 2022 +0200 +++ b/src/HTTPServer.cpp Thu Apr 07 23:04:12 2022 +0200 @@ -27,9 +27,14 @@ class HTTPServer::HTTPServerImpl { public: MHD_Daemon* mhd = nullptr; + std::shared_ptr requestHandler; }; -HTTPServer* HTTPServer::create() { +void HTTPServer::setRequestHandler(std::shared_ptr handler) { + impl->requestHandler = handler; +} + +HTTPServer* HTTPServer::create(HTTPServer::Options options) { HTTPServer::HTTPServerImpl* impl = new HTTPServer::HTTPServerImpl(); void* acceptCallbackData = nullptr; @@ -48,7 +53,7 @@ impl->mhd = MHD_start_daemon(MHD_USE_INTERNAL_POLLING_THREAD, - 8080, + options.tcpPort, acceptCallback, acceptCallbackData, accessCallback, accessCallbackData, MHD_OPTION_THREAD_POOL_SIZE, 10, diff -r 23c516259cc5 -r 4b05b16b97e6 src/HTTPServer.h --- a/src/HTTPServer.h Thu Apr 07 21:06:37 2022 +0200 +++ b/src/HTTPServer.h Thu Apr 07 23:04:12 2022 +0200 @@ -17,6 +17,11 @@ #pragma once +#include +#include +#include +#include + namespace relpipe { namespace tr { namespace httpd { @@ -31,11 +36,47 @@ public: + + class Header { + public: + std::string name; + std::string value; + }; + + class Request { + public: + std::vector
header; + std::string host; + std::string method; + std::string url; + std::string body; + }; + + class Response { + public: + std::vector
header; + uint16_t code; + std::string body; + }; + + class RequestHandler { + public: + + virtual const Response handle(const Request& request); + }; + + class Options { + public: + uint16_t tcpPort = 8080; + }; + virtual ~HTTPServer(); HTTPServer(const HTTPServer&) = delete; HTTPServer& operator=(const HTTPServer&) = delete; - static HTTPServer* create(); + void setRequestHandler(std::shared_ptr handler); + + static HTTPServer* create(Options options); }; diff -r 23c516259cc5 -r 4b05b16b97e6 src/relpipe-tr-httpd.cpp --- a/src/relpipe-tr-httpd.cpp Thu Apr 07 21:06:37 2022 +0200 +++ b/src/relpipe-tr-httpd.cpp Thu Apr 07 23:04:12 2022 +0200 @@ -51,7 +51,9 @@ Configuration configuration = cliParser.parse(cli.arguments()); std::shared_ptr writer(relpipe::writer::Factory::create(std::cout)); std::shared_ptr reader(relpipe::reader::Factory::create(std::cin)); - std::shared_ptr httpServer(HTTPServer::create()); + HTTPServer::Options serverOptions; + serverOptions.tcpPort = configuration.tcpPort; + std::shared_ptr httpServer(HTTPServer::create(serverOptions)); HttpdHandler handler(writer, configuration, httpServer); reader->addHandler(&handler); reader->process();