diff --git a/include/villas/api/request.hpp b/include/villas/api/request.hpp new file mode 100644 index 000000000..a31a7b7cd --- /dev/null +++ b/include/villas/api/request.hpp @@ -0,0 +1,149 @@ +/** API Request. + * + * @file + * @author Steffen Vogel + * @copyright 2014-2020, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#pragma once + +#include + +#include + +#include +#include + +namespace villas { +namespace node { +namespace api { + +/* Forward declarations */ +class Session; +class Response; +class RequestFactory; + +class Request { + + friend RequestFactory; + friend Response; + +protected: + Session *session; + + Logger logger; + +public: + std::string uri; + int method; + std::smatch matches; + json_t *body; + + RequestFactory *factory; + + enum Method { + UNKNOWN_METHOD, + GET, + POST, + DELETE, + OPTIONS, + PUT, + PATCH + }; + + Request(Session *s) : + session(s), + body(nullptr) + { + logger = logging.get("api:request"); + } + + virtual ~Request() + { + if (body) + json_decref(body); + } + + virtual Response * execute() = 0; + + void setBody(json_t *j) + { + body = j; + } +}; + +class RequestFactory : public plugin::Plugin { + +public: + using plugin::Plugin::Plugin; + + virtual bool + match(const std::string &uri, std::smatch &m) const = 0; + + virtual Request * + make(Session *s) = 0; + + static Request * + make(Session *s, const std::string &uri, int meth); +}; + +template +class RequestPlugin : public RequestFactory { + +protected: + std::regex regex; + +public: + using RequestFactory::RequestFactory; + + RequestPlugin() : + RequestFactory(), + regex(re) + { } + + virtual Request * + make(Session *s) + { + return new T(s); + } + + // Get plugin name + virtual std::string + getName() const + { + return name; + } + + // Get plugin description + virtual std::string + getDescription() const + { + return desc; + } + + virtual bool + match(const std::string &uri, std::smatch &match) const + { + return std::regex_match(uri, match, regex); + } +}; + +} /* namespace api */ +} /* namespace node */ +} /* namespace villas */ diff --git a/include/villas/api/response.hpp b/include/villas/api/response.hpp new file mode 100644 index 000000000..7ff6e026a --- /dev/null +++ b/include/villas/api/response.hpp @@ -0,0 +1,94 @@ +/** API response. + * + * @file + * @author Steffen Vogel + * @copyright 2014-2020, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#pragma once + +#include + +#include +#include +#include +#include + +namespace villas { +namespace node { +namespace api { + +/* Forward declarations */ +class Session; +class Request; + +class Response { + +protected: + Session *session; + Logger logger; + +public: + json_t *response; + int code; + + Response(Session *s, json_t *resp = nullptr); + + virtual ~Response(); + + int + getCode() const + { + return code; + } + + /** Return JSON representation of response as used by API sockets. */ + virtual json_t * + toJson() + { + return response; + } +}; + +class ErrorResponse : public Response { + +protected: + std::string error; + +public: + ErrorResponse(Session *s, const RuntimeError &e) : + Response(s), + error(e.what()) + { + code = 500; + } + + ErrorResponse(Session *s, const Error &e) : + Response(s), + error(e.what()) + { + code = e.code; + } + + virtual json_t * toJson(); +}; + +} /* namespace api */ +} /* namespace node */ +} /* namespace villas */ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index d59580dbd..4cea694ae 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -115,7 +115,7 @@ if(WITH_HOOKS) list(APPEND WHOLE_ARCHIVES hooks) endif() -if(WITH_API) +if(WITH_API AND WITH_WEB) list(APPEND LIB_SRC api.cpp ) diff --git a/lib/web.cpp b/lib/web.cpp index 7e50e7e2f..5fcc33804 100644 --- a/lib/web.cpp +++ b/lib/web.cpp @@ -27,10 +27,8 @@ #include #include #include +#include #include -#include -#include - #include using namespace villas; @@ -50,16 +48,10 @@ lws_protocols protocols[] = { #ifdef WITH_API { .name = "http-api", - .callback = api_http_protocol_cb, - .per_session_data_size = sizeof(api::sessions::Http), + .callback = api::Session::protocolCallback, + .per_session_data_size = sizeof(api::Session), .rx_buffer_size = 1024 }, - { - .name = "api", - .callback = api_ws_protocol_cb, - .per_session_data_size = sizeof(api::sessions::WebSocket), - .rx_buffer_size = 0 - }, #endif /* WITH_API */ #ifdef WITH_NODE_WEBSOCKET { @@ -79,7 +71,7 @@ static lws_http_mount mounts[] = { #ifdef WITH_API { .mount_next = &mounts[1], /* linked-list "next" */ - .mountpoint = "/api/v1", /* mountpoint URL */ + .mountpoint = "/api/v2", /* mountpoint URL */ .origin = "http-api", /* protocol */ .def = nullptr, .protocol = "http-api",