mirror of
https://github.com/Naios/continuable.git
synced 2025-12-06 16:56:44 +08:00
Started to work on a basic example using boost asio and beast
This commit is contained in:
parent
17a4e8a8da
commit
fc9830aa24
@ -14,4 +14,8 @@ if (CTI_CONTINUABLE_WITH_TESTS OR CTI_CONTINUABLE_WITH_EXAMPLES)
|
|||||||
if(NOT TARGET asio)
|
if(NOT TARGET asio)
|
||||||
add_subdirectory(asio)
|
add_subdirectory(asio)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(NOT TARGET boost)
|
||||||
|
add_subdirectory(boost)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
36
dep/boost/CMakeLists.txt
Normal file
36
dep/boost/CMakeLists.txt
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
if(WIN32)
|
||||||
|
if(CMAKE_SIZEOF_VOID_P MATCHES 8)
|
||||||
|
set(PLATFORM 64)
|
||||||
|
else()
|
||||||
|
set(PLATFORM 32)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(DEFINED ENV{BOOST_ROOT})
|
||||||
|
set(BOOST_ROOT $ENV{BOOST_ROOT})
|
||||||
|
set(BOOST_LIBRARYDIR ${BOOST_ROOT}/lib${PLATFORM}-msvc-14.1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
|
set(Boost_USE_MULTITHREADED ON)
|
||||||
|
set(Boost_USE_STATIC_RUNTIME OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(Boost 1.66
|
||||||
|
COMPONENTS
|
||||||
|
system
|
||||||
|
iostreams)
|
||||||
|
|
||||||
|
if (${Boost_FOUND})
|
||||||
|
add_library(boost INTERFACE)
|
||||||
|
|
||||||
|
target_link_libraries(boost
|
||||||
|
INTERFACE
|
||||||
|
Boost::system
|
||||||
|
Boost::iostreams)
|
||||||
|
|
||||||
|
target_compile_definitions(boost
|
||||||
|
INTERFACE
|
||||||
|
-DBOOST_DATE_TIME_NO_LIB
|
||||||
|
-DBOOST_REGEX_NO_LIB
|
||||||
|
-DBOOST_CHRONO_NO_LIB)
|
||||||
|
endif()
|
||||||
@ -1,2 +1,3 @@
|
|||||||
|
add_subdirectory(example-boost)
|
||||||
add_subdirectory(example-asio)
|
add_subdirectory(example-asio)
|
||||||
add_subdirectory(example-ai)
|
add_subdirectory(example-ai)
|
||||||
|
|||||||
23
examples/example-boost/CMakeLists.txt
Normal file
23
examples/example-boost/CMakeLists.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
if (NOT ${Boost_FOUND})
|
||||||
|
message(STATUS "Boost not found, skipping boost examples")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_executable(example-boost
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/server.hpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/server.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/example-boost.cpp)
|
||||||
|
|
||||||
|
target_include_directories(example-boost
|
||||||
|
PRIVATE
|
||||||
|
${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
|
target_link_libraries(example-boost
|
||||||
|
PRIVATE
|
||||||
|
continuable
|
||||||
|
boost)
|
||||||
|
|
||||||
|
target_compile_definitions(example-boost
|
||||||
|
PUBLIC
|
||||||
|
-DCONTINUABLE_WITH_NO_EXCEPTIONS)
|
||||||
|
|
||||||
84
examples/example-boost/example-boost.cpp
Normal file
84
examples/example-boost/example-boost.cpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
https://github.com/Naios/continuable
|
||||||
|
v2.0.0
|
||||||
|
|
||||||
|
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files(the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions :
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <server.hpp>
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <boost/asio/io_context.hpp>
|
||||||
|
#include <boost/asio/signal_set.hpp>
|
||||||
|
#include <boost/beast/http.hpp>
|
||||||
|
#include <boost/beast/version.hpp>
|
||||||
|
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
|
||||||
|
#include <continuable/continuable.hpp>
|
||||||
|
|
||||||
|
int main(int, char**) {
|
||||||
|
namespace http = boost::beast::http;
|
||||||
|
|
||||||
|
auto server = http_server::create("0.0.0.0", 8080);
|
||||||
|
|
||||||
|
boost::asio::deadline_timer t
|
||||||
|
|
||||||
|
server->listen([](request_t const& req) -> cti::continuable<response_t> {
|
||||||
|
return cti::make_continuable<response_t>([&](auto&& promise) {
|
||||||
|
http::response<http::string_body> res{http::status::ok, req.version()};
|
||||||
|
|
||||||
|
// Build the response
|
||||||
|
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() = "Hello World!";
|
||||||
|
res.prepare_payload();
|
||||||
|
|
||||||
|
// Resolve the request asynchronously
|
||||||
|
promise.set_value(res);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Construct a signal set registered for process termination.
|
||||||
|
boost::asio::signal_set signals(context);
|
||||||
|
signals.add(SIGTERM);
|
||||||
|
signals.add(SIGINT);
|
||||||
|
|
||||||
|
// Run the I/O service on the requested number of threads
|
||||||
|
{
|
||||||
|
auto const threads = std::thread::hardware_concurrency();
|
||||||
|
std::vector<std::thread> v;
|
||||||
|
v.reserve(threads - 1);
|
||||||
|
for (auto i = threads - 1; i > 0; --i)
|
||||||
|
v.emplace_back([&context] { context.run(); });
|
||||||
|
context.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
249
examples/example-boost/server.cpp
Normal file
249
examples/example-boost/server.cpp
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
https://github.com/Naios/continuable
|
||||||
|
v2.0.0
|
||||||
|
|
||||||
|
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files(the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions :
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
**/
|
||||||
|
|
||||||
|
// This file is based on the original boost beast example located at
|
||||||
|
// http://www.boost.org/doc/libs/1_66_0/libs/beast/example/http/server/async/http_server_async.cpp
|
||||||
|
// with the following license:
|
||||||
|
//
|
||||||
|
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Official repository: https://github.com/boostorg/beast
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <server.hpp>
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <boost/asio/bind_executor.hpp>
|
||||||
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
|
#include <boost/asio/strand.hpp>
|
||||||
|
#include <boost/beast/core.hpp>
|
||||||
|
#include <boost/beast/http.hpp>
|
||||||
|
#include <boost/beast/version.hpp>
|
||||||
|
|
||||||
|
#include <function2/function2.hpp>
|
||||||
|
|
||||||
|
using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
|
||||||
|
namespace http = boost::beast::http; // from <boost/beast/http.hpp>
|
||||||
|
|
||||||
|
// Report a failure
|
||||||
|
void fail(boost::system::error_code ec, char const* what) {
|
||||||
|
std::cerr << what << ": " << ec.message() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles an HTTP server connection
|
||||||
|
class session : public std::enable_shared_from_this<session> {
|
||||||
|
tcp::socket socket_;
|
||||||
|
handler_t const& callback_;
|
||||||
|
boost::asio::strand<boost::asio::io_context::executor_type> strand_;
|
||||||
|
boost::beast::flat_buffer buffer_;
|
||||||
|
http::request<http::string_body> req_;
|
||||||
|
std::shared_ptr<void> res_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Take ownership of the socket
|
||||||
|
explicit session(tcp::socket socket, handler_t const& callback)
|
||||||
|
: socket_(std::move(socket)), callback_(callback),
|
||||||
|
strand_(socket_.get_executor()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the asynchronous operation
|
||||||
|
void run() {
|
||||||
|
do_read();
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_read() {
|
||||||
|
// Read a request
|
||||||
|
http::async_read(
|
||||||
|
socket_, buffer_, req_,
|
||||||
|
boost::asio::bind_executor(
|
||||||
|
strand_, std::bind(&session::on_read, shared_from_this(),
|
||||||
|
std::placeholders::_1, std::placeholders::_2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_read(boost::system::error_code ec, std::size_t bytes_transferred) {
|
||||||
|
boost::ignore_unused(bytes_transferred);
|
||||||
|
|
||||||
|
// This means they closed the connection
|
||||||
|
if (ec == http::error::end_of_stream)
|
||||||
|
return do_close();
|
||||||
|
|
||||||
|
if (ec)
|
||||||
|
return fail(ec, "read");
|
||||||
|
|
||||||
|
// Send the response
|
||||||
|
callback_(std::move(req_)).then([this](auto&& msg) {
|
||||||
|
// The lifetime of the message has to extend
|
||||||
|
// for the duration of the async operation so
|
||||||
|
// we use a shared_ptr to manage it.
|
||||||
|
auto sp = std::make_shared<std::decay_t<decltype(msg)>>(std::move(msg));
|
||||||
|
|
||||||
|
// Store a type-erased version of the shared
|
||||||
|
// pointer in the class to keep it alive.
|
||||||
|
res_ = sp;
|
||||||
|
|
||||||
|
// Write the response
|
||||||
|
http::async_write(
|
||||||
|
socket_, *sp,
|
||||||
|
boost::asio::bind_executor(
|
||||||
|
strand_, std::bind(&session::on_write, shared_from_this(),
|
||||||
|
std::placeholders::_1, std::placeholders::_2,
|
||||||
|
sp->need_eof())));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_write(boost::system::error_code ec, std::size_t bytes_transferred,
|
||||||
|
bool close) {
|
||||||
|
boost::ignore_unused(bytes_transferred);
|
||||||
|
|
||||||
|
if (ec)
|
||||||
|
return fail(ec, "write");
|
||||||
|
|
||||||
|
if (close) {
|
||||||
|
// This means we should close the connection, usually because
|
||||||
|
// the response indicated the "Connection: close" semantic.
|
||||||
|
return do_close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're done with the response so delete it
|
||||||
|
res_ = nullptr;
|
||||||
|
|
||||||
|
// Read another request
|
||||||
|
do_read();
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_close() {
|
||||||
|
// Send a TCP shutdown
|
||||||
|
boost::system::error_code ec;
|
||||||
|
socket_.shutdown(tcp::socket::shutdown_send, ec);
|
||||||
|
|
||||||
|
// At this point the connection is closed gracefully
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Accepts incoming connections and launches the sessions
|
||||||
|
class listener : public std::enable_shared_from_this<listener> {
|
||||||
|
tcp::acceptor acceptor_;
|
||||||
|
tcp::socket socket_;
|
||||||
|
handler_t callback_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
listener(boost::asio::io_context& ioc, tcp::endpoint endpoint,
|
||||||
|
handler_t&& callback)
|
||||||
|
: acceptor_(ioc), socket_(ioc), callback_(std::move(callback)) {
|
||||||
|
boost::system::error_code ec;
|
||||||
|
|
||||||
|
// Open the acceptor
|
||||||
|
acceptor_.open(endpoint.protocol(), ec);
|
||||||
|
if (ec) {
|
||||||
|
fail(ec, "open");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind to the server address
|
||||||
|
acceptor_.bind(endpoint, ec);
|
||||||
|
if (ec) {
|
||||||
|
fail(ec, "bind");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start listening for connections
|
||||||
|
acceptor_.listen(boost::asio::socket_base::max_listen_connections, ec);
|
||||||
|
if (ec) {
|
||||||
|
fail(ec, "listen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start accepting incoming connections
|
||||||
|
void run() {
|
||||||
|
if (!acceptor_.is_open())
|
||||||
|
return;
|
||||||
|
do_accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_accept() {
|
||||||
|
acceptor_.async_accept(socket_,
|
||||||
|
std::bind(&listener::on_accept, shared_from_this(),
|
||||||
|
std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_accept(boost::system::error_code ec) {
|
||||||
|
if (ec) {
|
||||||
|
fail(ec, "accept");
|
||||||
|
} else {
|
||||||
|
// Create the session and run it
|
||||||
|
std::make_shared<session>(std::move(socket_), callback_)->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept another connection
|
||||||
|
do_accept();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct http_server_impl : http_server
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<http_server> http_server::create(std::string address, unsigned short port) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return std::make_shared<>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void create_server(std::string address, unsigned short port,
|
||||||
|
handler_t callback) {
|
||||||
|
|
||||||
|
auto const target = boost::asio::ip::make_address(address.c_str());
|
||||||
|
|
||||||
|
// Create and launch a listening port
|
||||||
|
std::make_shared<listener>(context, tcp::endpoint{target, port},
|
||||||
|
std::move(callback))
|
||||||
|
->run();
|
||||||
|
}
|
||||||
63
examples/example-boost/server.hpp
Normal file
63
examples/example-boost/server.hpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
https://github.com/Naios/continuable
|
||||||
|
v2.0.0
|
||||||
|
|
||||||
|
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files(the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions :
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef CONTINUABLE_EXAMPLES_SERVER_HPP_INCLUDED
|
||||||
|
#define CONTINUABLE_EXAMPLES_SERVER_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <boost/asio/io_context.hpp>
|
||||||
|
#include <boost/beast/http.hpp>
|
||||||
|
#include <continuable/continuable.hpp>
|
||||||
|
#include <function2/function2.hpp>
|
||||||
|
|
||||||
|
using request_t = boost::beast::http::request<boost::beast::http::string_body>;
|
||||||
|
using response_t =
|
||||||
|
boost::beast::http::response<boost::beast::http::string_body>;
|
||||||
|
|
||||||
|
using handler_t =
|
||||||
|
fu2::unique_function<cti::continuable<response_t>(request_t const&) const>;
|
||||||
|
|
||||||
|
struct http_server {
|
||||||
|
virtual ~http_server() = default;
|
||||||
|
|
||||||
|
/// Creates a minimal asynchronous http server using boost asio and beast
|
||||||
|
static std::shared_ptr<http_server> create(std::string address,
|
||||||
|
unsigned short port);
|
||||||
|
|
||||||
|
virtual void listen(handler_t);
|
||||||
|
|
||||||
|
virtual boost::asio::io_context& context();
|
||||||
|
|
||||||
|
virtual void stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CONTINUABLE_EXAMPLES_SERVER_HPP_INCLUDED
|
||||||
Loading…
x
Reference in New Issue
Block a user