Skip to content

Reimplement REST interface using HTTP/2 #371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ else()
option(OPENCMW_ENABLE_COVERAGE "Enable Coverage" OFF)
endif()
option(OPENCMW_ENABLE_CONCEPTS "Enable Concepts Builds" ${opencmw_MASTER_PROJECT})
option(OPENCMW_DEBUG_HTTP "Enable verbose HTTP output for debugging" OFF)
option(OPENCMW_PROFILE_HTTP "Enable verbose HTTP output for profiling" OFF)

# Very basic PCH example
option(ENABLE_PCH "Enable Precompiled Headers" OFF)
Expand All @@ -124,6 +126,14 @@ if(ENABLE_PCH)
<utility>)
endif()

if(OPENCMW_DEBUG_HTTP)
target_compile_definitions(opencmw_project_options INTERFACE -DOPENCMW_DEBUG_HTTP)
endif()

if(OPENCMW_PROFILE_HTTP)
target_compile_definitions(opencmw_project_options INTERFACE -DOPENCMW_PROFILE_HTTP)
endif()

if(OPENCMW_ENABLE_TESTING)
enable_testing()
message("Building Tests.")
Expand Down
26 changes: 26 additions & 0 deletions cmake/DependenciesNative.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,29 @@ FetchContent_Declare(
FetchContent_MakeAvailable(cpp-httplib zeromq openssl-source)

list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/contrib) # replace contrib by extras for catch2 v3.x.x

option(ENABLE_NGHTTP2_DEBUG "Enable verbose nghttp2 debug output" OFF)

include(ExternalProject)
ExternalProject_Add(Nghttp2Project
GIT_REPOSITORY https://github.com/nghttp2/nghttp2
GIT_TAG v1.65.0
GIT_SHALLOW ON
BUILD_BYPRODUCTS ${CMAKE_BINARY_DIR}/nghttp2-install/lib/libnghttp2.a
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/nghttp2-install
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
-DENABLE_LIB_ONLY:BOOL=ON
-DENABLE_HTTP3:BOOL=OFF
-DENABLE_DEBUG:BOOL=${ENABLE_NGHTTP2_DEBUG}
-DBUILD_STATIC_LIBS:BOOL=ON
-BUILD_SHARED_LIBS:BOOL=OFF
-DENABLE_DOC:BOOL=OFF
)

add_library(nghttp2-static STATIC IMPORTED STATIC GLOBAL)
set_target_properties(nghttp2-static PROPERTIES
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/nghttp2-install/lib/libnghttp2.a"
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_BINARY_DIR}/nghttp2-install/include"
)
add_dependencies(nghttp2-static Nghttp2Project)
17 changes: 7 additions & 10 deletions concepts/client/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
if(NOT EMSCRIPTEN)
add_executable(RestSubscription_example RestSubscription_example.cpp)
target_link_libraries(
RestSubscription_example
PRIVATE core
client
opencmw_project_options
opencmw_project_warnings
assets::rest)
endif()
add_executable(LoadTest_client LoadTest_client.cpp)
target_link_libraries(
LoadTest_client
PRIVATE core
client
opencmw_project_options
opencmw_project_warnings)

add_executable(RestSubscription_client RestSubscription_client.cpp)
target_link_libraries(
Expand Down
68 changes: 68 additions & 0 deletions concepts/client/LoadTest_client.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include <atomic>
#include <chrono>
#include <string_view>
#include <thread>

#include <MIME.hpp>
#include <RestClient.hpp>
#include <URI.hpp>

#include "ClientCommon.hpp"
#include "helpers.hpp"

using namespace std::chrono_literals;

std::string schema() {
if (auto env = ::getenv("DISABLE_REST_HTTPS"); env != nullptr && std::string_view(env) == "1") {
return "http";
} else {
return "https";
}
}


int main() {
constexpr auto kServerPort = 8080;
constexpr auto kNClients = 80UZ;
constexpr auto kNSubscriptions = 10UZ;
constexpr auto kNUpdates = 5000UZ;
constexpr auto kIntervalMs = 40UZ;
constexpr auto kPayloadSize = 4096UZ;

std::array<std::unique_ptr<opencmw::client::RestClient>, kNClients> clients;
for (std::size_t i = 0; i < clients.size(); i++) {
clients[i] = std::make_unique<opencmw::client::RestClient>(opencmw::client::DefaultContentTypeHeader(opencmw::MIME::BINARY), opencmw::client::VerifyServerCertificates(false));
}
std::atomic<std::size_t> responseCount = 0;

const auto start = std::chrono::system_clock::now();

for (std::size_t i = 0; i < kNClients; i++) {
for (std::size_t j = 0; j < kNSubscriptions; j++) {
opencmw::client::Command cmd;
cmd.command = opencmw::mdp::Command::Subscribe;
cmd.serviceName = "/loadTest";
cmd.topic = opencmw::URI<>(fmt::format("{}://localhost:{}/loadTest?initialDelayMs=1000&topic={}&intervalMs={}&payloadSize={}&nUpdates={}", schema(), kServerPort, /*i,*/ j, kIntervalMs, kPayloadSize, kNUpdates));
cmd.callback = [&responseCount](const auto &msg) {
responseCount++;
};
clients[i]->request(std::move(cmd));
}
}

constexpr auto expectedResponses = kNClients * kNSubscriptions * kNUpdates;

std::uint64_t counter = 0;
while (responseCount < expectedResponses) {
counter += 50;
std::this_thread::sleep_for(std::chrono::milliseconds(50));
if (counter % 20 == 0) {
fmt::println("Received {} of {} responses", responseCount.load(), expectedResponses);
}
}

const auto end = std::chrono::system_clock::now();
const auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
fmt::println("Elapsed time: {} ms", elapsed);
return 0;
}
9 changes: 4 additions & 5 deletions concepts/client/RestSubscription_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ using namespace std::chrono_literals;
// These are not main-local, as JS doesn't end when
// C++ main ends
namespace test_state {
#ifndef __EMSCRIPTEN__
opencmw::client::RestClient client(opencmw::client::VerifyServerCertificates(false));
#else
opencmw::client::RestClient client;

#endif
std::string schema() {
if (auto env = ::getenv("DISABLE_REST_HTTPS"); env != nullptr && std::string_view(env) == "1") {
return "http";
Expand All @@ -39,10 +42,6 @@ auto run = rest_test_runner(
} // namespace test_state

int main() {
#ifndef __EMSCRIPTEN__
opencmw::client::RestClient::CHECK_CERTIFICATES = false;
#endif

using namespace test_state;

#ifndef __EMSCRIPTEN__
Expand Down
127 changes: 0 additions & 127 deletions concepts/client/RestSubscription_example.cpp

This file was deleted.

14 changes: 10 additions & 4 deletions concepts/client/dns_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
#include <emscripten/trace.h>
#endif // EMSCRIPTEN

#include <RestClient.hpp>

#include <string_view>
#include <thread>

using namespace std::chrono_literals;
using namespace opencmw;
Expand All @@ -32,12 +33,17 @@ using namespace opencmw::service::dns;
void run_dns_server(std::string_view httpAddress, std::string_view mdpAddress) {
majordomo::Broker<> broker{ "Broker", {} };
std::string rootPath{ "./" };
auto fs = cmrc::assets::get_filesystem();
majordomo::RestBackend<majordomo::PLAIN_HTTP, decltype(fs)> rest_backend{ broker, fs, URI<>{ std::string{ httpAddress } } };
majordomo::rest::Settings rest;
rest.handlers = { majordomo::rest::cmrcHandler("/assets/*", "", std::make_shared<cmrc::embedded_filesystem>(cmrc::assets::get_filesystem()), "") };

if (const auto bound = broker.bindRest(rest); !bound) {
fmt::println(std::cerr, "failed to bind REST: {}", bound.error());
std::exit(1);
return;
}
DnsWorkerType dnsWorker{ broker, DnsHandler{} };
broker.bind(URI<>{ std::string{ mdpAddress } }, majordomo::BindOption::Router);

RunInThread restThread(rest_backend);
RunInThread dnsThread(dnsWorker);
RunInThread brokerThread(broker);

Expand Down
10 changes: 10 additions & 0 deletions concepts/majordomo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ target_link_libraries(
assets::rest
assets::testImages)

add_executable(MajordomoRest_LoadTestServer MajordomoRest_LoadTestServer.cpp)
target_include_directories(MajordomoRest_LoadTestServer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(
MajordomoRest_LoadTestServer
PRIVATE majordomo
opencmw_project_options
opencmw_project_warnings
assets::rest
assets::testImages)

if(NOT
CMAKE_CXX_COMPILER_ID
MATCHES
Expand Down
Loading