delete unnecessary

This commit is contained in:
Антон 2024-03-16 13:05:42 +03:00
parent ed3bcc6f4a
commit dbbb04264d
11 changed files with 2 additions and 442 deletions

View File

@ -23,13 +23,5 @@ configure_file(config.json ${CMAKE_BUILD_RPATH} config.json COPYONLY)
add_executable(hello_async
main.cpp
src/http_server.cpp
src/http_server.h
src/session.h
src/session.cpp
src/session_base.h
src/session_base.cpp
src/listener.h
src/listener.cpp
src/sdk.h)
)
target_link_libraries(hello_async PRIVATE Threads::Threads)

104
main.cpp
View File

@ -6,109 +6,7 @@
#include <thread>
#include <vector>
#include "src/http_server.h"
namespace
{
namespace net = boost::asio;
using namespace std::literals;
namespace sys = boost::system;
namespace http = boost::beast::http;
using namespace std;
using net::ip::tcp;
// Запрос, тело которого представлено в виде строки
using StringRequest = http::request<http::string_body>;
// Ответ, тело которого представлено в виде строки
using StringResponse = http::response<http::string_body>;
struct content_type
{
content_type() = delete;
constexpr static std::string_view k_TextHTML = "text/html"sv;
// При необходимости внутрь content_type можно добавить и другие типы контента
};
// Создаёт StringResponse с заданными параметрами
StringResponse MakeStringResponse(http::status status,
std::string_view body,
unsigned http_version,
bool keep_alive,
std::string_view content_type = content_type::k_TextHTML)
{
StringResponse response(status, http_version);
response.set(http::field::content_type, content_type);
response.body() = body;
response.content_length(body.size());
response.keep_alive(keep_alive);
return response;
}
StringResponse HandleRequest(StringRequest&& req)
{
auto route = req.target();
return MakeStringResponse(http::status::ok,
"Hello, World!"sv,
req.version(),
req.keep_alive());
}
// Запускает функцию fn на n потоках, включая текущий
template<typename Fn>
void RunWorkers(unsigned n, const Fn& fn)
{
n = std::max(1u, n);
std::vector<std::jthread> workers;
workers.reserve(n - 1);
// Запускаем n-1 рабочих потоков, выполняющих функцию fn
while (--n)
{
workers.emplace_back(fn);
}
fn();
}
} // namespace
int main()
{
const unsigned num_threads = std::thread::hardware_concurrency();
net::io_context ioc(num_threads);
tcp::acceptor acceptor(net::make_strand(ioc));
// Подписываемся на сигналы и при их получении завершаем работу сервера
net::signal_set signals(ioc, SIGINT, SIGTERM);
signals.async_wait([&ioc](const sys::error_code& ec,
[[maybe_unused]] int signal_number)
{
if (!ec)
{
cout << "Signal "sv << signal_number << " received"sv
<< endl;
ioc.stop();
}
});
const auto address = net::ip::make_address("0.0.0.0");
constexpr net::ip::port_type port = 8080;
http_server::ServeHttp(ioc, {address, port}, [](auto&& req, auto&& sender)
{
sender(HandleRequest(std::forward<decltype(req)>(req)));
});
net::steady_timer t {ioc, 30s};
t.async_wait([](sys::error_code ec)
{
cout << "Timer expired"sv << endl;
});
std::cout << "Server has started..."sv << std::endl;
RunWorkers(num_threads, [&ioc]
{
ioc.run();
});
return EXIT_SUCCESS
}

View File

@ -1,8 +0,0 @@
#include "http_server.h"
#include <boost/asio/dispatch.hpp>
#include <iostream>
namespace http_server
{
}

View File

@ -1,27 +0,0 @@
#pragma once
#include "sdk.h"
// boost.beast будет использовать std::string_view вместо boost::string_view
#define BOOST_BEAST_USE_STD_STRING_VIEW
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/strand.hpp>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include "listener.h"
#include "session.h"
namespace http_server
{
template<typename RequestHandler>
void ServeHttp(net::io_context& ioc,
const tcp::endpoint& endpoint,
RequestHandler&& handler)
{
using MyListener = Listener<std::decay_t < RequestHandler>>;
std::make_shared<MyListener>(ioc,
endpoint,
std::forward<RequestHandler>(handler))->Run();
}
}

View File

@ -1,8 +0,0 @@
#include "http_server.h"
#include <boost/asio/dispatch.hpp>
#include <iostream>
namespace http_server
{
} // namespace http_server

View File

@ -1,74 +0,0 @@
#pragma once
#include "sdk.h"
// boost.beast будет использовать std::string_view вместо boost::string_view
#define BOOST_BEAST_USE_STD_STRING_VIEW
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/strand.hpp>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include "session.h"
namespace http_server
{
namespace net = boost::asio;
namespace sys = boost::system;
using tcp = net::ip::tcp;
namespace beast = boost::beast;
namespace http = beast::http;
template<typename RequestHandler>
class Listener : public std::enable_shared_from_this<Listener<RequestHandler>>
{
net::io_context& ioc_;
tcp::acceptor acceptor_;
RequestHandler request_handler_;
public:
template<class Handler>
Listener(net::io_context& ioc,
const tcp::endpoint& endpoint,
Handler&& request_handler)
: ioc_(ioc),
acceptor_(net::make_strand(ioc)),
request_handler_(std::forward<Handler>(request_handler))
{
acceptor_.open(endpoint.protocol());
acceptor_.set_option(net::socket_base::reuse_address(true));
acceptor_.bind(endpoint);
acceptor_.listen(net::socket_base::max_listen_connections);
}
void Run()
{
DoAccept();
}
private:
void DoAccept()
{
acceptor_.async_accept(net::make_strand(ioc_),
beast::bind_front_handler(&Listener::OnAccept,
this->shared_from_this()));
}
void OnAccept(sys::error_code ec, tcp::socket socket)
{
if (ec)
{
return ReportError(ec, "accept"sv);
}
AsyncRunSession(std::move(socket));
DoAccept();
}
void AsyncRunSession(tcp::socket&& socket)
{
std::make_shared<Session<RequestHandler>>(std::move(socket),
request_handler_)->Run();
}
};
} // namespace http_server

View File

@ -1,4 +0,0 @@
#pragma once
#ifdef WIN32
#include <sdkddkver.h>
#endif

View File

@ -1,8 +0,0 @@
#include "http_server.h"
#include <boost/asio/dispatch.hpp>
#include <iostream>
namespace http_server
{
} // namespace http_server

View File

@ -1,51 +0,0 @@
#pragma once
#include "sdk.h"
// boost.beast будет использовать std::string_view вместо boost::string_view
#define BOOST_BEAST_USE_STD_STRING_VIEW
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/strand.hpp>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include "session_base.h"
namespace http_server
{
namespace net = boost::asio;
using tcp = net::ip::tcp;
namespace beast = boost::beast;
namespace http = beast::http;
template<typename RequestHandler>
class Session
: public SessionBase,
public std::enable_shared_from_this<Session<RequestHandler>>
{
RequestHandler request_handler_;
public:
template<class Handler>
Session(tcp::socket&& socket, Handler&& request_handler)
: SessionBase(std::move(socket)), request_handler_(request_handler) {}
std::shared_ptr<SessionBase> GetSharedThis() override
{
return this->shared_from_this();
}
private:
void HandleRequest(HttpRequest&& request) override
{
// Захватываем умный указатель на текущий объект Session в лямбде,
// чтобы продлить время жизни сессии до вызова лямбды.
// Используется generic-лямбда функция, способная принять response произвольного типа
request_handler_(std::move(request),
[self = this->shared_from_this()](auto&& response)
{
self->Write(std::move(response));
});
}
};
} // namespace http_server

View File

@ -1,73 +0,0 @@
#include "http_server.h"
#include "session_base.h"
#include <boost/asio/dispatch.hpp>
#include <iostream>
namespace http_server
{
void ReportError(beast::error_code ec, std::string_view what)
{
std::cerr << what << ": "sv << ec.message() << std::endl;
}
SessionBase::SessionBase(tcp::socket&& socket)
: stream_(std::move(socket))
{
}
void SessionBase::Run()
{
net::dispatch(stream_.get_executor(),
beast::bind_front_handler(&SessionBase::Read,
GetSharedThis()));
}
void SessionBase::Read()
{
using namespace std::literals;
request_ = {};
stream_.expires_after(30s);
http::async_read(stream_, buffer_, request_,
beast::bind_front_handler(&SessionBase::OnRead,
GetSharedThis()));
}
void SessionBase::OnRead(beast::error_code ec, size_t bytes_read)
{
if (ec == http::error::end_of_stream)
{
return Close();
}
if (ec)
{
return ReportError(ec, "read"sv);
}
HandleRequest(std::move(request_));
}
void SessionBase::Close()
{
beast::error_code ec;
stream_.socket().shutdown(tcp::socket::shutdown_send, ec);
}
void SessionBase::OnWrite(bool close,
boost::beast::error_code ec,
std::size_t bytes_written)
{
if (ec)
{
return ReportError(ec, "write"sv);
}
if (close)
{
// Семантика ответа требует закрыть соединение
return Close();
}
// Считываем следующий запрос
Read();
}
} // namespace http_server

View File

@ -1,77 +0,0 @@
#pragma once
#include "sdk.h"
// boost.beast будет использовать std::string_view вместо boost::string_view
#define BOOST_BEAST_USE_STD_STRING_VIEW
#include <iostream>
#include <string_view>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/strand.hpp>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
namespace http_server
{
namespace net = boost::asio;
using tcp = net::ip::tcp;
namespace beast = boost::beast;
namespace http = beast::http;
using namespace std::literals;
void ReportError(beast::error_code ec, std::string_view what);
class SessionBase
{
protected:
using HttpRequest = http::request<http::string_body>;
virtual ~SessionBase() = default;
public:
SessionBase(const SessionBase&) = delete;
SessionBase& operator =(const SessionBase&) = delete;
void Run();
void Read();
virtual std::shared_ptr<SessionBase> GetSharedThis() = 0;
protected:
explicit SessionBase(tcp::socket&& socket);
template<typename Body, typename Fields>
void Write(http::response<Body, Fields>&& response)
{
// Запись выполняется асинхронно, поэтому response перемещаем в область кучи
auto safe_response = std::make_shared < http::response
< Body, Fields>>(std::move(response));
auto self = GetSharedThis();
http::async_write(stream_, *safe_response,
[safe_response, self](beast::error_code ec,
std::size_t bytes_written)
{
self->OnWrite(safe_response->need_eof(),
ec,
bytes_written);
});
}
private:
beast::tcp_stream stream_;
beast::flat_buffer buffer_;
HttpRequest request_;
void OnRead(beast::error_code ec, [[maybe_unused]] size_t bytes_read);
void Close();
virtual void HandleRequest(HttpRequest&& request) = 0;
void OnWrite(bool close,
beast::error_code ec,
[[maybe_unused]] std::size_t bytes_written);
};
} // namespace http_server