From 55beae9c70c3c3a5553c9b05da444035d7fedb78 Mon Sep 17 00:00:00 2001 From: nekosu Date: Fri, 10 Nov 2023 20:54:23 +0800 Subject: [PATCH] feat: restful server structure --- 3rdparty/MaaDeps | 2 +- CMakeLists.txt | 4 + source/CMakeLists.txt | 8 +- source/MaaRestful/CMakeLists.txt | 18 ++++ source/MaaRestful/Handle/Context.hpp | 37 ++++++++ source/MaaRestful/Handle/DeviceDispatcher.cpp | 71 +++++++++++++++ source/MaaRestful/Handle/DeviceDispatcher.hpp | 12 +++ source/MaaRestful/Handle/Dispatcher.cpp | 80 +++++++++++++++++ source/MaaRestful/Handle/Dispatcher.hpp | 33 +++++++ source/MaaRestful/Handle/RootDispatcher.cpp | 37 ++++++++ source/MaaRestful/Handle/RootDispatcher.hpp | 14 +++ source/MaaRestful/Helper/Forward.hpp | 9 ++ source/MaaRestful/Helper/Log.hpp | 13 +++ source/MaaRestful/Helper/Mime.cpp | 38 ++++++++ source/MaaRestful/Helper/Mime.hpp | 9 ++ source/MaaRestful/Listener/Listener.hpp | 76 ++++++++++++++++ source/MaaRestful/Session/Session.hpp | 87 +++++++++++++++++++ source/MaaRestful/main.cpp | 22 +++++ source/include/Conf/Conf.h | 6 ++ source/include/Utils/Boost.hpp | 15 +++- 20 files changed, 585 insertions(+), 6 deletions(-) create mode 100644 source/MaaRestful/CMakeLists.txt create mode 100644 source/MaaRestful/Handle/Context.hpp create mode 100644 source/MaaRestful/Handle/DeviceDispatcher.cpp create mode 100644 source/MaaRestful/Handle/DeviceDispatcher.hpp create mode 100644 source/MaaRestful/Handle/Dispatcher.cpp create mode 100644 source/MaaRestful/Handle/Dispatcher.hpp create mode 100644 source/MaaRestful/Handle/RootDispatcher.cpp create mode 100644 source/MaaRestful/Handle/RootDispatcher.hpp create mode 100644 source/MaaRestful/Helper/Forward.hpp create mode 100644 source/MaaRestful/Helper/Log.hpp create mode 100644 source/MaaRestful/Helper/Mime.cpp create mode 100644 source/MaaRestful/Helper/Mime.hpp create mode 100644 source/MaaRestful/Listener/Listener.hpp create mode 100644 source/MaaRestful/Session/Session.hpp create mode 100644 source/MaaRestful/main.cpp diff --git a/3rdparty/MaaDeps b/3rdparty/MaaDeps index 0981084f3..f96e356a6 160000 --- a/3rdparty/MaaDeps +++ b/3rdparty/MaaDeps @@ -1 +1 @@ -Subproject commit 0981084f3b1cda55838383be8c957c427bd7f2b6 +Subproject commit f96e356a65d10f09b83728f450854142432013f6 diff --git a/CMakeLists.txt b/CMakeLists.txt index 55c9b56ae..f734a6400 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ option(WITH_ADB_CONTROLLER "build with adb controller" ON) option(WITH_THRIFT_CONTROLLER "build with thrift controller" ON) option(WITH_DBG_CONTROLLER "build with debugging controller" ON) option(WITH_GRPC "build with protobuf and grpc" ON) +option(WITH_RESTFUL "build with beast for restful server" ON) option(BUILD_GRPC_CLI "build grpc CLI exec" ON) option(BUILD_SAMPLE "build a demo" OFF) option(BUILD_PIPELINE_TESTING "build pipeline testing" OFF) @@ -54,6 +55,9 @@ if(WITH_GRPC) include(${PROJECT_SOURCE_DIR}/cmake/grpc-gen.cmake) add_compile_definitions(WITH_GRPC) endif() +if (WITH_RESTFUL) + add_compile_definitions(WITH_RESTFUL) +endif() find_package(OpenCV REQUIRED COMPONENTS core imgproc imgcodecs) find_package(Boost REQUIRED COMPONENTS system) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 42186db59..c1c221247 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -1,12 +1,12 @@ add_subdirectory(MaaUtils) -if (WITH_ADB_CONTROLLER) +if(WITH_ADB_CONTROLLER) add_subdirectory(MaaAdbControlUnit) endif(WITH_ADB_CONTROLLER) if(WITH_THRIFT_CONTROLLER AND NOT MAA_CROSSCOMPILE) add_subdirectory(MaaThriftController) endif(WITH_THRIFT_CONTROLLER AND NOT MAA_CROSSCOMPILE) -if (WITH_DBG_CONTROLLER) +if(WITH_DBG_CONTROLLER) add_subdirectory(MaaDbgControlUnit) endif(WITH_DBG_CONTROLLER) @@ -17,4 +17,8 @@ if(WITH_GRPC) add_subdirectory(MaaRpc) endif(WITH_GRPC) +if(WITH_RESTFUL) + add_subdirectory(MaaRestful) +endif(WITH_RESTFUL) + add_subdirectory(binding) diff --git a/source/MaaRestful/CMakeLists.txt b/source/MaaRestful/CMakeLists.txt new file mode 100644 index 000000000..13cbe2c54 --- /dev/null +++ b/source/MaaRestful/CMakeLists.txt @@ -0,0 +1,18 @@ +file(GLOB_RECURSE maa_restful_src *.h *.hpp *.cpp) + +add_executable(MaaRestful ${maa_restful_src}) + +target_include_directories( + MaaRestful + INTERFACE ../../include + PRIVATE . ../include ../../include) + +target_link_libraries(MaaRestful MaaFramework MaaToolKit MaaUtils HeaderOnlyLibraries Boost::system) + +install( + TARGETS MaaRestful + RUNTIME DESTINATION bin + LIBRARY DESTINATION bin + ARCHIVE DESTINATION lib) + +source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${maa_restful_src}) diff --git a/source/MaaRestful/Handle/Context.hpp b/source/MaaRestful/Handle/Context.hpp new file mode 100644 index 000000000..06060097c --- /dev/null +++ b/source/MaaRestful/Handle/Context.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "Helper/Forward.hpp" + +#include + +MAA_RESTFUL_NS_BEGIN + +struct Context +{ + Context(http::request&& req, http::response& res) + : req_(std::move(req)), res_(res) + {} + + void json_body(const json::object& value) + { + res_.set(http::field::content_type, "application/json"); + res_.body() = value.to_string(); + } + + void bad_request(const std::string& why) + { + res_.result(http::status::bad_request); + json_body({ { "error", why } }); + } + + void init() + { + res_.set(http::field::server, BOOST_BEAST_VERSION_STRING); + res_.keep_alive(req_.keep_alive()); + } + + http::request req_; + http::response& res_; +}; + +MAA_RESTFUL_NS_END diff --git a/source/MaaRestful/Handle/DeviceDispatcher.cpp b/source/MaaRestful/Handle/DeviceDispatcher.cpp new file mode 100644 index 000000000..2a9106a8e --- /dev/null +++ b/source/MaaRestful/Handle/DeviceDispatcher.cpp @@ -0,0 +1,71 @@ +#include "Handle/DeviceDispatcher.hpp" +#include "MaaToolKit/MaaToolKitAPI.h" +#include "Utils/Format.hpp" + +MAA_RESTFUL_NS_BEGIN + +bool DeviceDispatcher::handle(Context& ctx, std::vector url_segs) +{ + auto seg0 = url_segs[0]; + + if (seg0 == "devices") { + if (url_segs.size() == 1) { + // switch (ctx.req_.method()) { + // case http::verb::get: + // // TODO: return all devices + // ctx.json_body({ { "count", MaaToolKitFindDevice() } }); + // break; + // default: + // ctx.bad_request(MAA_FMT::format("bad verb {}", std::string_view(ctx.req_.method_string()))); + // } + // return true; + } + else { + auto seg1 = url_segs[1]; + + if (seg1 == "find") { + switch (ctx.req_.method()) { + case http::verb::put: + ctx.json_body({ { "count", MaaToolKitFindDevice() } }); + break; + default: + ctx.bad_request(MAA_FMT::format("bad verb {}", std::string_view(ctx.req_.method_string()))); + } + return true; + } + } + } + else if (seg0 == "device") { + if (url_segs.size() == 1) { + ctx.bad_request(MAA_FMT::format("id expected")); + return true; + } + else { + auto seg1 = url_segs[1]; + + int id = std::stoul(std::string(seg1)); + + if (url_segs.size() == 2) { + switch (ctx.req_.method()) { + case http::verb::get: + ctx.json_body({ { "name", MaaToolKitGetDeviceName(id) }, + { "adb_path", MaaToolKitGetDeviceAdbPath(id) }, + { "adb_serial", MaaToolKitGetDeviceAdbSerial(id) }, + { "controller_type", MaaToolKitGetDeviceAdbControllerType(id) }, + { "adb_config", MaaToolKitGetDeviceAdbConfig(id) } }); + break; + default: + ctx.bad_request(MAA_FMT::format("bad verb {}", std::string_view(ctx.req_.method_string()))); + } + return true; + } + else { + // TODO: implement partial query + } + } + } + + return false; +} + +MAA_RESTFUL_NS_END diff --git a/source/MaaRestful/Handle/DeviceDispatcher.hpp b/source/MaaRestful/Handle/DeviceDispatcher.hpp new file mode 100644 index 000000000..a3da5b88f --- /dev/null +++ b/source/MaaRestful/Handle/DeviceDispatcher.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "Handle/Dispatcher.hpp" + +MAA_RESTFUL_NS_BEGIN + +struct DeviceDispatcher : public Dispatcher +{ + virtual bool handle(Context& ctx, std::vector url_segs) override; +}; + +MAA_RESTFUL_NS_END diff --git a/source/MaaRestful/Handle/Dispatcher.cpp b/source/MaaRestful/Handle/Dispatcher.cpp new file mode 100644 index 000000000..ca3f213b0 --- /dev/null +++ b/source/MaaRestful/Handle/Dispatcher.cpp @@ -0,0 +1,80 @@ +#include "Handle/Dispatcher.hpp" +#include "Handle/RootDispatcher.hpp" +#include "MaaFramework/MaaAPI.h" +#include "Utils/Format.hpp" +#include +#include + +MAA_RESTFUL_NS_BEGIN + +http::message_generator handle_request(http::request&& req) +{ + http::response res { http::status::ok, req.version() }; + + std::string url = req.target(); + auto url_segs_rng = std::string_view(url) | std::views::split('/'); + std::vector url_segs; + for (auto seg : url_segs_rng) { + std::string_view part(seg.begin(), seg.end()); + if (part.length() == 0) { + continue; + } + url_segs.push_back(part); + } + + Context ctx(std::move(req), res); + ctx.init(); + + RootDispatcher rd; + if (!rd.handle(ctx, url_segs)) { + ctx.bad_request(MAA_FMT::format("unknown path {}", std::string_view(ctx.req_.target()))); + } + + res.prepare_payload(); + + return res; + + // auto const bad_request = [&req](beast::string_view why) { + // http::response res { http::status::bad_request, req.version() }; + // res.set(http::field::server, BOOST_BEAST_VERSION_STRING); + // res.set(http::field::content_type, "text/html"); + // res.keep_alive(req.keep_alive()); + // res.body() = std::string(why); + // res.prepare_payload(); + // return res; + // }; + + // // auto const not_found = [&req](beast::string_view target) { + // // http::response res { http::status::not_found, req.version() }; + // // res.set(http::field::server, BOOST_BEAST_VERSION_STRING); + // // res.set(http::field::content_type, "text/html"); + // // res.keep_alive(req.keep_alive()); + // // res.body() = "The resource '" + std::string(target) + "' was not found."; + // // res.prepare_payload(); + // // return res; + // // }; + + // // auto const server_error = [&req](beast::string_view what) { + // // http::response res { http::status::internal_server_error, req.version() }; + // // res.set(http::field::server, BOOST_BEAST_VERSION_STRING); + // // res.set(http::field::content_type, "text/html"); + // // res.keep_alive(req.keep_alive()); + // // res.body() = "An error occurred: '" + std::string(what) + "'"; + // // res.prepare_payload(); + // // return res; + // // }; + + // if (req.method() != http::verb::get) { + // return bad_request("Unknown HTTP-method"); + // } + + // http::response res { http::status::ok, req.version() }; + // res.set(http::field::server, BOOST_BEAST_VERSION_STRING); + // res.set(http::field::content_type, "text/plain"); + // res.body() = req.target(); + // res.prepare_payload(); + // res.keep_alive(req.keep_alive()); + // return res; +} + +MAA_RESTFUL_NS_END diff --git a/source/MaaRestful/Handle/Dispatcher.hpp b/source/MaaRestful/Handle/Dispatcher.hpp new file mode 100644 index 000000000..85575b88e --- /dev/null +++ b/source/MaaRestful/Handle/Dispatcher.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "Handle/Context.hpp" + +#include +#include + +MAA_RESTFUL_NS_BEGIN + +struct DispatcherBase +{ + virtual ~DispatcherBase() {} +}; + +template +struct Dispatcher +{ + Dispatcher(Env env) : env_(env) {} + + virtual bool handle(Context& ctx, std::vector url_segs) = 0; + + Env env_; +}; + +template <> +struct Dispatcher +{ + virtual bool handle(Context& ctx, std::vector url_segs) = 0; +}; + +http::message_generator handle_request(http::request&& req); + +MAA_RESTFUL_NS_END diff --git a/source/MaaRestful/Handle/RootDispatcher.cpp b/source/MaaRestful/Handle/RootDispatcher.cpp new file mode 100644 index 000000000..fb707c771 --- /dev/null +++ b/source/MaaRestful/Handle/RootDispatcher.cpp @@ -0,0 +1,37 @@ +#include "Handle/RootDispatcher.hpp" +#include "MaaFramework/MaaAPI.h" +#include "Utils/Format.hpp" + +MAA_RESTFUL_NS_BEGIN + +bool RootDispatcher::handle(Context& ctx, std::vector url_segs) +{ + if (url_segs.size() == 0) { + switch (ctx.req_.method()) { + case http::verb::get: + ctx.json_body({ { "msg", "hello world!" } }); + break; + default: + ctx.bad_request(MAA_FMT::format("bad verb {}", std::string_view(ctx.req_.method_string()))); + } + return true; + } + else { + auto seg0 = url_segs[0]; + + if (seg0 == "version") { + switch (ctx.req_.method()) { + case http::verb::get: + ctx.json_body({ { "version", MaaVersion() } }); + break; + default: + ctx.bad_request(MAA_FMT::format("bad verb {}", std::string_view(ctx.req_.method_string()))); + } + return true; + } + + return device_.handle(ctx, url_segs); + } +} + +MAA_RESTFUL_NS_END diff --git a/source/MaaRestful/Handle/RootDispatcher.hpp b/source/MaaRestful/Handle/RootDispatcher.hpp new file mode 100644 index 000000000..dffa0eb16 --- /dev/null +++ b/source/MaaRestful/Handle/RootDispatcher.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "Handle/DeviceDispatcher.hpp" + +MAA_RESTFUL_NS_BEGIN + +struct RootDispatcher : public Dispatcher +{ + virtual bool handle(Context& ctx, std::vector url_segs) override; + + DeviceDispatcher device_; +}; + +MAA_RESTFUL_NS_END diff --git a/source/MaaRestful/Helper/Forward.hpp b/source/MaaRestful/Helper/Forward.hpp new file mode 100644 index 000000000..3c4ff7195 --- /dev/null +++ b/source/MaaRestful/Helper/Forward.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "Conf/Conf.h" +#include "Utils/Boost.hpp" + +namespace beast = boost::beast; +namespace http = beast::http; +namespace asio = boost::asio; +using tcp = asio::ip::tcp; diff --git a/source/MaaRestful/Helper/Log.hpp b/source/MaaRestful/Helper/Log.hpp new file mode 100644 index 000000000..d4b1204e8 --- /dev/null +++ b/source/MaaRestful/Helper/Log.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "Helper/Forward.hpp" +#include "Utils/Logger.h" + +MAA_RESTFUL_NS_BEGIN + +inline void fail(beast::error_code ec, char const* what) +{ + LogError << what << ec.message(); +} + +MAA_RESTFUL_NS_END diff --git a/source/MaaRestful/Helper/Mime.cpp b/source/MaaRestful/Helper/Mime.cpp new file mode 100644 index 000000000..1e26a878c --- /dev/null +++ b/source/MaaRestful/Helper/Mime.cpp @@ -0,0 +1,38 @@ +#include "Helper/Mime.hpp" + +MAA_RESTFUL_NS_BEGIN + +beast::string_view mime_type(beast::string_view path) +{ + using beast::iequals; + + auto const ext = [&path] { + auto const pos = path.rfind("."); + if (pos == beast::string_view::npos) return beast::string_view {}; + return path.substr(pos); + }(); + if (iequals(ext, ".htm")) return "text/html"; + if (iequals(ext, ".html")) return "text/html"; + if (iequals(ext, ".php")) return "text/html"; + if (iequals(ext, ".css")) return "text/css"; + if (iequals(ext, ".txt")) return "text/plain"; + if (iequals(ext, ".js")) return "application/javascript"; + if (iequals(ext, ".json")) return "application/json"; + if (iequals(ext, ".xml")) return "application/xml"; + if (iequals(ext, ".swf")) return "application/x-shockwave-flash"; + if (iequals(ext, ".flv")) return "video/x-flv"; + if (iequals(ext, ".png")) return "image/png"; + if (iequals(ext, ".jpe")) return "image/jpeg"; + if (iequals(ext, ".jpeg")) return "image/jpeg"; + if (iequals(ext, ".jpg")) return "image/jpeg"; + if (iequals(ext, ".gif")) return "image/gif"; + if (iequals(ext, ".bmp")) return "image/bmp"; + if (iequals(ext, ".ico")) return "image/vnd.microsoft.icon"; + if (iequals(ext, ".tiff")) return "image/tiff"; + if (iequals(ext, ".tif")) return "image/tiff"; + if (iequals(ext, ".svg")) return "image/svg+xml"; + if (iequals(ext, ".svgz")) return "image/svg+xml"; + return "application/text"; +} + +MAA_RESTFUL_NS_END diff --git a/source/MaaRestful/Helper/Mime.hpp b/source/MaaRestful/Helper/Mime.hpp new file mode 100644 index 000000000..8e87a19e5 --- /dev/null +++ b/source/MaaRestful/Helper/Mime.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "Helper/Forward.hpp" + +MAA_RESTFUL_NS_BEGIN + +beast::string_view mime_type(beast::string_view path); + +MAA_RESTFUL_NS_END diff --git a/source/MaaRestful/Listener/Listener.hpp b/source/MaaRestful/Listener/Listener.hpp new file mode 100644 index 000000000..8572e0883 --- /dev/null +++ b/source/MaaRestful/Listener/Listener.hpp @@ -0,0 +1,76 @@ +#pragma once + +#include "Helper/Forward.hpp" +#include "Helper/Log.hpp" +#include "Session/Session.hpp" + +#include + +MAA_RESTFUL_NS_BEGIN + +// Accepts incoming connections and launches the sessions +class Listener : public std::enable_shared_from_this +{ +public: + Listener(asio::io_context& ioc, tcp::endpoint endpoint) : ioc_(ioc), acceptor_(asio::make_strand(ioc)) + { + beast::error_code ec; + + // Open the acceptor + acceptor_.open(endpoint.protocol(), ec); + if (ec) { + fail(ec, "open"); + return; + } + + // Allow address reuse + acceptor_.set_option(asio::socket_base::reuse_address(true), ec); + if (ec) { + fail(ec, "set_option"); + return; + } + + // Bind to the server address + acceptor_.bind(endpoint, ec); + if (ec) { + fail(ec, "bind"); + return; + } + + // Start listening for connections + acceptor_.listen(asio::socket_base::max_listen_connections, ec); + if (ec) { + fail(ec, "listen"); + return; + } + } + + // Start accepting incoming connections + void run() { do_accept(); } + +private: + void do_accept() + { + // The new connection gets its own strand + acceptor_.async_accept(asio::make_strand(ioc_), + beast::bind_front_handler(&Listener::on_accept, shared_from_this())); + } + + void on_accept(beast::error_code ec, tcp::socket socket) + { + if (ec) { + fail(ec, "accept"); + return; + } + else { + std::make_shared(std::move(socket))->run(); + } + + do_accept(); + } + + asio::io_context& ioc_; + tcp::acceptor acceptor_; +}; + +MAA_RESTFUL_NS_END diff --git a/source/MaaRestful/Session/Session.hpp b/source/MaaRestful/Session/Session.hpp new file mode 100644 index 000000000..61dea04c2 --- /dev/null +++ b/source/MaaRestful/Session/Session.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include "Handle/Dispatcher.hpp" +#include "Helper/Forward.hpp" +#include "Helper/Log.hpp" + +#include + +MAA_RESTFUL_NS_BEGIN + +// Handles an HTTP server connection +class Session : public std::enable_shared_from_this +{ +public: + // Take ownership of the stream + Session(tcp::socket&& socket) : stream_(std::move(socket)) {} + + // Start the asynchronous operation + void run() + { + asio::dispatch(stream_.get_executor(), beast::bind_front_handler(&Session::do_read, shared_from_this())); + } + + void do_read() + { + req_ = {}; + + stream_.expires_after(std::chrono::seconds(30)); + + http::async_read(stream_, buffer_, req_, beast::bind_front_handler(&Session::on_read, shared_from_this())); + } + + void on_read(beast::error_code ec, std::size_t bytes_transferred) + { + std::ignore = bytes_transferred; + + if (ec == http::error::end_of_stream) { + return do_close(); + } + + if (ec) { + return fail(ec, "read"); + } + + send_response(handle_request(std::move(req_))); + } + + void send_response(http::message_generator&& msg) + { + bool keep_alive = msg.keep_alive(); + + // Write the response + beast::async_write(stream_, std::move(msg), + beast::bind_front_handler(&Session::on_write, shared_from_this(), keep_alive)); + } + + void on_write(bool keep_alive, beast::error_code ec, std::size_t bytes_transferred) + { + boost::ignore_unused(bytes_transferred); + + if (ec) { + return fail(ec, "write"); + } + + if (!keep_alive) { + return do_close(); + } + + do_read(); + } + + void do_close() + { + // Send a TCP shutdown + beast::error_code ec; + stream_.socket().shutdown(tcp::socket::shutdown_send, ec); + + // At this point the connection is closed gracefully + } + +private: + beast::tcp_stream stream_; + beast::flat_buffer buffer_; + http::request req_; +}; + +MAA_RESTFUL_NS_END diff --git a/source/MaaRestful/main.cpp b/source/MaaRestful/main.cpp new file mode 100644 index 000000000..5700889c9 --- /dev/null +++ b/source/MaaRestful/main.cpp @@ -0,0 +1,22 @@ +#include "Helper/Forward.hpp" +#include "Listener/Listener.hpp" + +int main() +{ + int threads = 4; + + asio::io_context ioc { threads }; + + // Create and launch a listening port + std::make_shared(ioc, tcp::endpoint { asio::ip::make_address("127.0.0.1"), 8080u }) + ->run(); + + // Run the I/O service on the requested number of threads + std::vector v; + v.reserve(threads); + for (auto i = threads; i > 0; --i) + v.emplace_back([&ioc] { ioc.run(); }); + ioc.run(); + + return EXIT_SUCCESS; +} diff --git a/source/include/Conf/Conf.h b/source/include/Conf/Conf.h index 0cca69ddf..3cd88b146 100644 --- a/source/include/Conf/Conf.h +++ b/source/include/Conf/Conf.h @@ -156,3 +156,9 @@ namespace MAA_TOOLKIT_SERVER_NS \ { #define MAA_TOOLKIT_SERVER_NS_END } + +#define MAA_RESTFUL_NS MAA_NS::RestfulNS +#define MAA_RESTFUL_NS_BEGIN \ + namespace MAA_RESTFUL_NS \ + { +#define MAA_RESTFUL_NS_END } diff --git a/source/include/Utils/Boost.hpp b/source/include/Utils/Boost.hpp index 21a50bcdd..2fcd2e295 100644 --- a/source/include/Utils/Boost.hpp +++ b/source/include/Utils/Boost.hpp @@ -12,11 +12,20 @@ MAA_SUPPRESS_BOOST_WARNINGS_BEGIN #include +#include #include -#ifdef _WIN32 -#include -#endif #include #include #include + +#ifdef _WIN32 +#include +#endif + +#ifdef WITH_RESTFUL +#include +#include +#include +#include +#endif MAA_SUPPRESS_BOOST_WARNINGS_END