Compare commits
No commits in common. "main" and "main" have entirely different histories.
|
@ -8,7 +8,7 @@ set(Boost_USE_MULTITHREADED ON)
|
|||
set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "C:/Users/Public/Libraries/boost_1_84_0")
|
||||
set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "C:/Users/Public/Libraries/boost_1_84_0/stage/lib")
|
||||
|
||||
find_package(Boost 1.78.0 REQUIRED COMPONENTS filesystem json log)
|
||||
find_package(Boost 1.78.0 REQUIRED COMPONENTS filesystem json)
|
||||
if (Boost_FOUND)
|
||||
include_directories(${Boost_INCLUDE_DIR})
|
||||
endif ()
|
||||
|
@ -17,7 +17,6 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
|
|||
find_package(Threads REQUIRED)
|
||||
|
||||
configure_file(config.json ${CMAKE_BUILD_RPATH} config.json COPYONLY)
|
||||
file(COPY public DESTINATION ${CMAKE_BINARY_DIR})
|
||||
|
||||
add_executable(hello_async
|
||||
main.cpp
|
||||
|
@ -29,32 +28,6 @@ add_executable(hello_async
|
|||
src/session_base.cpp
|
||||
src/listener.h
|
||||
src/listener.cpp
|
||||
src/sdk.h
|
||||
src/handlers/GetMapsHandler.cpp
|
||||
src/handlers/GetMapsHandler.h
|
||||
src/content_type.h
|
||||
src/handlers/GetMapByIdHandler.cpp
|
||||
src/handlers/GetMapByIdHandler.h
|
||||
src/handlers/GetStaticAssetHandler.cpp
|
||||
src/handlers/GetStaticAssetHandler.h
|
||||
src/routes.h
|
||||
src/Logger.h
|
||||
src/Logger.cpp
|
||||
src/model/Office.h
|
||||
src/model/Office.cpp
|
||||
src/model/Road.h
|
||||
src/model/Road.cpp
|
||||
src/model/Map.h
|
||||
src/model/Map.cpp
|
||||
src/model/Game.h
|
||||
src/model/Game.cpp
|
||||
src/model/Building.h
|
||||
src/model/Building.cpp
|
||||
)
|
||||
src/sdk.h)
|
||||
target_include_directories(hello_async PUBLIC ${Boost_INCLUDE_DIR})
|
||||
target_link_libraries(hello_async PRIVATE
|
||||
Threads::Threads
|
||||
Boost::filesystem
|
||||
Boost::json
|
||||
Boost::log
|
||||
)
|
||||
target_link_libraries(hello_async PRIVATE Threads::Threads Boost::filesystem Boost::json)
|
||||
|
|
92
main.cpp
92
main.cpp
|
@ -2,24 +2,14 @@
|
|||
//
|
||||
#include <boost/json.hpp>
|
||||
#include <boost/json/src.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/core.hpp>
|
||||
#include <boost/log/expressions.hpp>
|
||||
#include <boost/log/utility/setup/file.hpp>
|
||||
#include <boost/asio/signal_set.hpp>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "src/http_server.h"
|
||||
#include "src/Logger.h"
|
||||
#include "src/routes.h"
|
||||
#include "src/handlers/GetMapsHandler.h"
|
||||
#include "src/handlers/GetMapByIdHandler.h"
|
||||
#include "src/handlers/GetStaticAssetHandler.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -28,35 +18,57 @@ using namespace std::literals;
|
|||
namespace sys = boost::system;
|
||||
namespace json = boost::json;
|
||||
namespace http = boost::beast::http;
|
||||
namespace keywords = boost::log::keywords;
|
||||
|
||||
using namespace std;
|
||||
using namespace http_server;
|
||||
using net::ip::tcp;
|
||||
|
||||
// Запрос, тело которого представлено в виде строки
|
||||
using StringRequest = http::request<http::string_body>;
|
||||
// Ответ, тело которого представлено в виде строки
|
||||
using StringResponse = http::response<http::string_body>;
|
||||
using FileResponse = http::response<http::file_body>;
|
||||
|
||||
struct content_type
|
||||
{
|
||||
content_type() = delete;
|
||||
constexpr static std::string_view k_TextHTML = "text/html"sv;
|
||||
constexpr static std::string_view k_JSON = "application/json"sv;
|
||||
// При необходимости внутрь content_type можно добавить и другие типы контента
|
||||
};
|
||||
|
||||
StringResponse HandleRequest(StringRequest&& req)
|
||||
{
|
||||
constexpr static string_view k_MapsPattern = "/api/v1/maps"sv;
|
||||
const auto route = req.target();
|
||||
|
||||
if (equal(k_MapsRoute.begin(),
|
||||
k_MapsRoute.end(),
|
||||
if (equal(k_MapsPattern.begin(),
|
||||
k_MapsPattern.end(),
|
||||
route.begin(),
|
||||
route.end()))
|
||||
{
|
||||
return GetMapsHandler(req);
|
||||
ifstream stream("./config.json"s);
|
||||
string config;
|
||||
string buf;
|
||||
|
||||
while (std::getline(stream, buf))
|
||||
{
|
||||
config += buf;
|
||||
}
|
||||
|
||||
string_view config_ref {config.begin(), config.end()};
|
||||
auto parsed_config = json::parse(config_ref);
|
||||
StringResponse res(http::status::ok, 1);
|
||||
res.set(http::field::content_type, content_type::k_JSON);
|
||||
res.body() = json::serialize(parsed_config.as_object().at("maps"sv).as_array());
|
||||
res.content_length(res.body().size());
|
||||
res.keep_alive(true);
|
||||
|
||||
return res;
|
||||
}
|
||||
else if (equal(k_MapsRoute.begin(),
|
||||
k_MapsRoute.end(),
|
||||
else if (equal(k_MapsPattern.begin(),
|
||||
k_MapsPattern.end(),
|
||||
route.begin(),
|
||||
route.begin() + k_MapsRoute.size()))
|
||||
route.begin() + k_MapsPattern.size()))
|
||||
{
|
||||
return GetMapByIdHandler(req);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -74,11 +86,6 @@ StringResponse HandleRequest(StringRequest&& req)
|
|||
}
|
||||
}
|
||||
|
||||
FileResponse HandleRequestFile(StringRequest&& req)
|
||||
{
|
||||
return GetStaticAssetHandler(req);
|
||||
}
|
||||
|
||||
// Запускает функцию fn на n потоках, включая текущий
|
||||
template<typename Fn>
|
||||
void RunWorkers(unsigned n, const Fn& fn)
|
||||
|
@ -98,11 +105,6 @@ void RunWorkers(unsigned n, const Fn& fn)
|
|||
|
||||
int main()
|
||||
{
|
||||
boost::log::add_file_log(keywords::file_name = "./public/my_logs.txt",
|
||||
keywords::format = "[%TimeStamp%]: %Message%");
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Server started!"sv;
|
||||
|
||||
const unsigned num_threads = std::thread::hardware_concurrency();
|
||||
|
||||
net::io_context ioc(num_threads);
|
||||
|
@ -125,33 +127,7 @@ int main()
|
|||
constexpr net::ip::port_type port = 8080;
|
||||
http_server::ServeHttp(ioc, {address, port}, [](auto&& req, auto&& sender)
|
||||
{
|
||||
const auto route = req.target();
|
||||
|
||||
if (req.target() == "/"sv || find(route.begin(), route.end(), '.') != route.end())
|
||||
{
|
||||
auto res = HandleRequestFile(std::forward<decltype(req)>(req));
|
||||
|
||||
if (res.result() == http::status::not_found)
|
||||
{
|
||||
StringResponse errres(http::status::bad_request, 1);
|
||||
errres.set(http::field::content_type, content_type::k_JSON);
|
||||
string body = "{\n"
|
||||
" \"code\": \"badRequest\",\n"
|
||||
" \"message\": \"Bad request\"\n"
|
||||
"} "s;
|
||||
errres.body() = body;
|
||||
errres.content_length(body.size());
|
||||
errres.keep_alive(true);
|
||||
sender(errres);
|
||||
}
|
||||
else
|
||||
{
|
||||
sender(res);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
sender(HandleRequest(std::forward<decltype(req)>(req)));
|
||||
sender(HandleRequest(std::forward<decltype(req)>(req)));
|
||||
});
|
||||
|
||||
net::steady_timer t {ioc, 30s};
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Это просто мой файл
|
|
@ -1 +0,0 @@
|
|||
console.log(123);
|
|
@ -1,11 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>My title</title>
|
||||
<script src="cript.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
123412341324
|
||||
</body>
|
||||
</html>
|
|
@ -1,20 +0,0 @@
|
|||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <ctime>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
namespace http_server
|
||||
{
|
||||
Logger& Logger::GetInstance()
|
||||
{
|
||||
static Logger s_Instance;
|
||||
|
||||
return s_Instance;
|
||||
}
|
||||
|
||||
void Logger::SetOutStream(ostream& stream)
|
||||
{
|
||||
stream_ptr_ = &stream;
|
||||
}
|
||||
}
|
59
src/Logger.h
59
src/Logger.h
|
@ -1,59 +0,0 @@
|
|||
#pragma once
|
||||
#include "sdk.h"
|
||||
// boost.beast будет использовать std::string_view вместо boost::string_view
|
||||
#define BOOST_BEAST_USE_STD_STRING_VIEW
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "session.h"
|
||||
|
||||
namespace http_server
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
class Logger
|
||||
{
|
||||
mutex mtx_;
|
||||
ostream* stream_ptr_;
|
||||
|
||||
Logger() = default;
|
||||
|
||||
public:
|
||||
static Logger& GetInstance();
|
||||
|
||||
void SetOutStream(ostream& stream);
|
||||
|
||||
auto GetTimeStamp()
|
||||
{
|
||||
const auto now = std::chrono::system_clock::now();
|
||||
const auto t_c = std::chrono::system_clock::to_time_t(now);
|
||||
|
||||
return std::put_time(std::localtime(&t_c), "%F %T");
|
||||
}
|
||||
|
||||
template<class First, class... Args>
|
||||
void Log(First fst, Args... args)
|
||||
{
|
||||
lock_guard guard(mtx_);
|
||||
|
||||
*stream_ptr_ << GetTimeStamp() << ": "s;
|
||||
|
||||
LogImpl(fst, args...);
|
||||
}
|
||||
|
||||
private:
|
||||
template<class First, class... Args>
|
||||
void LogImpl(First fst, Args... args)
|
||||
{
|
||||
*stream_ptr_ << fst;
|
||||
|
||||
LogImpl(args...);
|
||||
}
|
||||
|
||||
template<class First>
|
||||
void LogImpl(First fst)
|
||||
{
|
||||
*stream_ptr_ << fst << '\n';
|
||||
}
|
||||
};
|
||||
} // namespace http_server
|
|
@ -1,29 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace http_server
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
struct content_type
|
||||
{
|
||||
content_type() = delete;
|
||||
constexpr inline static std::string_view k_TextHtml = "text/html"sv;
|
||||
constexpr inline static std::string_view k_TextCsv = "text/csv"sv;
|
||||
constexpr inline static std::string_view k_TextPlain = "text/plain"sv;
|
||||
constexpr inline static std::string_view k_JSON = "application/json"sv;
|
||||
constexpr inline static std::string_view k_Audio = "audio/mpeg"sv;
|
||||
constexpr inline static std::string_view k_AudioExample = "audio/example"sv;
|
||||
constexpr inline static std::string_view k_FontWoff = "font/woff"sv;
|
||||
constexpr inline static std::string_view k_FontTtf = "font/ttf"sv;
|
||||
constexpr inline static std::string_view k_FontOtf = "font/otf"sv;
|
||||
constexpr inline static std::string_view k_ImagePng = "image/png"sv;
|
||||
constexpr inline static std::string_view k_ImageJpeg = "image/jpeg"sv;
|
||||
constexpr inline static std::string_view k_ImageGif = "image/gif"sv;
|
||||
constexpr inline static std::string_view k_Model = "model/vrml"sv;
|
||||
constexpr inline static std::string_view k_VideoMp4 = "video/mp4"sv;
|
||||
constexpr inline static std::string_view k_VideoWebm = "video/webm"sv;
|
||||
constexpr inline static std::string_view k_Binary = "application/octet-stream"sv;
|
||||
};
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
#include <fstream>
|
||||
|
||||
#include "../routes.h"
|
||||
#include "GetMapByIdHandler.h"
|
||||
|
||||
namespace http_server
|
||||
{
|
||||
StringResponse GetMapByIdHandler(const StringRequest& req)
|
||||
{
|
||||
const auto route = req.target();
|
||||
ifstream stream("./config.json"s);
|
||||
string config;
|
||||
string buf;
|
||||
|
||||
while (std::getline(stream, buf))
|
||||
{
|
||||
config += buf;
|
||||
}
|
||||
|
||||
string_view config_ref {config.begin(), config.end()};
|
||||
auto parsed_config = json::parse(config_ref);
|
||||
string_view map_id {route.begin() + k_MapsRoute.size() + 1, route.end()};
|
||||
StringResponse res(http::status::ok, 1);
|
||||
res.set(http::field::content_type, content_type::k_JSON);
|
||||
|
||||
const auto& maps = parsed_config.as_object().at("maps"sv).as_array();
|
||||
|
||||
const auto finded = find_if(maps.begin(), maps.end(), [&map_id](auto& elem) -> bool
|
||||
{
|
||||
const auto& value = elem.as_object().at("id"sv).as_string();
|
||||
|
||||
return value == map_id;
|
||||
});
|
||||
|
||||
if (finded == maps.end())
|
||||
{
|
||||
StringResponse res(http::status::bad_request, 1);
|
||||
res.set(http::field::content_type, content_type::k_JSON);
|
||||
string body = "{\n"
|
||||
" \"code\": \"mapNotFound\",\n"
|
||||
" \"message\": \"Map not found\"\n"
|
||||
"}"s;
|
||||
res.body() = body;
|
||||
res.content_length(body.size());
|
||||
res.keep_alive(true);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
res.body() = json::serialize(*finded);
|
||||
res.content_length(res.body().size());
|
||||
res.keep_alive(true);
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/json.hpp>
|
||||
|
||||
#include "../content_type.h"
|
||||
|
||||
namespace http_server
|
||||
{
|
||||
namespace net = boost::asio;
|
||||
using namespace std::literals;
|
||||
namespace sys = boost::system;
|
||||
namespace json = boost::json;
|
||||
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>;
|
||||
|
||||
StringResponse GetMapByIdHandler(const StringRequest&);
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
#include "GetMapsHandler.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace http_server
|
||||
{
|
||||
StringResponse GetMapsHandler(const StringRequest& req)
|
||||
{
|
||||
ifstream stream("./config.json"s);
|
||||
string config;
|
||||
string buf;
|
||||
|
||||
while (std::getline(stream, buf))
|
||||
{
|
||||
config += buf;
|
||||
}
|
||||
|
||||
string_view config_ref {config.begin(), config.end()};
|
||||
auto parsed_config = json::parse(config_ref);
|
||||
StringResponse res(http::status::ok, 1);
|
||||
res.set(http::field::content_type, content_type::k_JSON);
|
||||
res.body() = json::serialize(parsed_config.as_object().at("maps"sv).as_array());
|
||||
res.content_length(res.body().size());
|
||||
res.keep_alive(true);
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/json.hpp>
|
||||
|
||||
#include "../content_type.h"
|
||||
|
||||
namespace http_server
|
||||
{
|
||||
namespace net = boost::asio;
|
||||
using namespace std::literals;
|
||||
namespace sys = boost::system;
|
||||
namespace json = boost::json;
|
||||
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>;
|
||||
|
||||
StringResponse GetMapsHandler(const StringRequest&);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
#include "GetStaticAssetHandler.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
namespace beast = boost::beast;
|
||||
using namespace std;
|
||||
|
||||
namespace http_server
|
||||
{
|
||||
FileResponse GetStaticAssetHandler(const StringRequest& req)
|
||||
{
|
||||
string rel_path_str {req.target().begin(), req.target().end()};
|
||||
fs::path base_path("./public/"s);
|
||||
fs::path rel_path("."s + rel_path_str);
|
||||
fs::path abs_path = fs::weakly_canonical(base_path / rel_path);
|
||||
|
||||
http::file_body::value_type file;
|
||||
|
||||
FileResponse res;
|
||||
res.version(11);
|
||||
|
||||
if (sys::error_code ec; file.open(abs_path.string().c_str(), beast::file_mode::read, ec), ec)
|
||||
{
|
||||
res.result(http::status::not_found);
|
||||
res.content_length(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
res.result(http::status::ok);
|
||||
res.body() = std::move(file);
|
||||
res.prepare_payload();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/json.hpp>
|
||||
|
||||
#include "../content_type.h"
|
||||
|
||||
namespace http_server
|
||||
{
|
||||
namespace net = boost::asio;
|
||||
using namespace std::literals;
|
||||
namespace sys = boost::system;
|
||||
namespace json = boost::json;
|
||||
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>;
|
||||
using FileResponse = http::response<http::file_body>;
|
||||
|
||||
FileResponse GetStaticAssetHandler(const StringRequest&);
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
#include "Building.h"
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace model
|
||||
{
|
||||
class Building
|
||||
{};
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
#include "Dog.h"
|
|
@ -1,5 +0,0 @@
|
|||
namespace model
|
||||
{
|
||||
class Dog
|
||||
{};
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
#include "Game.h"
|
|
@ -1,15 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Map.h"
|
||||
#include "GameSession.h"
|
||||
|
||||
namespace model
|
||||
{
|
||||
class Game
|
||||
{
|
||||
std::vector<Map> maps_;
|
||||
std::vector<GameSession> sessions_;
|
||||
};
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
#include "GameSession.h"
|
|
@ -1,14 +0,0 @@
|
|||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "Dog.h"
|
||||
#include "Map.h"
|
||||
|
||||
namespace model
|
||||
{
|
||||
class GameSession
|
||||
{
|
||||
std::vector<Dog> dogs_;
|
||||
std::shared_ptr<Map> map_;
|
||||
};
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
#include "Map.h"
|
|
@ -1,18 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "Office.h"
|
||||
#include "Building.h"
|
||||
#include "Road.h"
|
||||
|
||||
namespace model
|
||||
{
|
||||
class Map
|
||||
{
|
||||
std::vector<Road> roads_;
|
||||
std::vector<Road> buildings_;
|
||||
std::vector<Road> office_;
|
||||
};
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
#include "Office.h"
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace model
|
||||
{
|
||||
class Office
|
||||
{};
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
#include "Road.h"
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace model
|
||||
{
|
||||
class Road
|
||||
{};
|
||||
}
|
12
src/routes.h
12
src/routes.h
|
@ -1,12 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace http_server
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
constexpr static string_view k_MapsRoute = "/api/v1/maps"sv;
|
||||
constexpr static string_view k_StaticAssetsRoute = "/public"sv;
|
||||
|
||||
}
|
Loading…
Reference in New Issue