Skip to content
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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "docs/doxygen-awesome-css"]
path = docs/doxygen-awesome-css
url = https://github.com/jothepro/doxygen-awesome-css.git
[submodule "deps/drogon"]
path = deps/drogon
url = https://github.com/drogonframework/drogon.git
113 changes: 99 additions & 14 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,30 +1,46 @@
cmake_minimum_required(VERSION 3.8.2)
cmake_minimum_required(VERSION 3.15)

project(
topgg
LANGUAGES CXX
HOMEPAGE_URL "https://docs.top.gg/docs"
DESCRIPTION "The official C++ wrapper for the Top.gg API."
DESCRIPTION "A simple API wrapper for Top.gg written in C++."
)

set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build type")
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type")

option(BUILD_SHARED_LIBS "Build shared libraries" ON)
option(ENABLE_CORO "Support for C++20 coroutines" OFF)
option(ENABLE_API "Build primary API support" ON)
option(ENABLE_CPP_HTTPLIB_WEBHOOKS "Build support for webhooks via cpp-httplib" OFF)
option(ENABLE_DROGON_WEBHOOKS "Build support for webhooks via drogon" OFF)
option(ENABLE_CORO "Add support for C++20 coroutines" OFF)
option(TESTING "Enable this only if you are testing the library" OFF)

if(ENABLE_API)
file(GLOB TOPGG_SOURCE_FILES src/*.cpp)
endif()

if(ENABLE_CPP_HTTPLIB_WEBHOOKS)
set(TOPGG_SOURCE_FILES ${TOPGG_SOURCE_FILES} src/webhooks/cpp-httplib.cpp src/webhooks/models.cpp)
elseif(ENABLE_DROGON_WEBHOOKS)
set(TOPGG_SOURCE_FILES ${TOPGG_SOURCE_FILES} src/webhooks/drogon.cpp src/webhooks/models.cpp)
endif()

if(BUILD_SHARED_LIBS)
add_library(topgg SHARED ${TOPGG_SOURCE_FILES})

if(WIN32)
target_sources(topgg PRIVATE ${CMAKE_SOURCE_DIR}/topgg.rc)
target_sources(topgg PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/topgg.rc)
target_compile_definitions(topgg PRIVATE __TOPGG_BUILDING_DLL__)
endif()
else()
add_library(topgg STATIC ${TOPGG_SOURCE_FILES})
endif()

if(WIN32)
target_compile_definitions(topgg PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:__TOPGG_BUILDING_DLL__:DPP_STATIC TOPGG_STATIC>)
target_compile_definitions(topgg PUBLIC DPP_STATIC TOPGG_STATIC)
endif()
endif()

if(ENABLE_CORO)
Expand All @@ -34,26 +50,95 @@ else()
set(TOPGG_CXX_STANDARD 17)
endif()

if(TESTING)
target_compile_definitions(topgg PUBLIC __TOPGG_TESTING__)
endif()

set_target_properties(topgg PROPERTIES
OUTPUT_NAME topgg
CXX_STANDARD ${TOPGG_CXX_STANDARD}
CXX_STANDARD_REQUIRED ON
)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
if(ENABLE_API)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)

find_package(DPP REQUIRED)
endif()

if(ENABLE_CPP_HTTPLIB_WEBHOOKS)
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/include/cpp-httplib/cpp-httplib.h")
execute_process(COMMAND git clone https://github.com/yhirose/cpp-httplib.git --depth 1 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/include/cpp-httplib")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/cpp-httplib")
endif()
file(RENAME "${CMAKE_CURRENT_SOURCE_DIR}/cpp-httplib/httplib.h" "${CMAKE_CURRENT_SOURCE_DIR}/include/cpp-httplib/cpp-httplib.h")
file(REMOVE_RECURSE "${CMAKE_CURRENT_SOURCE_DIR}/cpp-httplib")
endif()

if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/include/nlohmann/json.hpp")
execute_process(COMMAND git clone https://github.com/nlohmann/json.git --depth 1 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/include/nlohmann")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/nlohmann")
endif()
file(RENAME "${CMAKE_CURRENT_SOURCE_DIR}/json/single_include/nlohmann/json.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/include/nlohmann/json.hpp")
file(REMOVE_RECURSE "${CMAKE_CURRENT_SOURCE_DIR}/json")
endif()
endif()

if(ENABLE_DROGON_WEBHOOKS)
if(WIN32)
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/conan_toolchain.cmake")

include(${CMAKE_CURRENT_SOURCE_DIR}/conan_toolchain.cmake)
endif()

set(DROGON_LIBRARY drogon)

set(
TRANTOR_INCLUDE_DIR
"${CMAKE_CURRENT_SOURCE_DIR}/deps/drogon/trantor"
"${CMAKE_BINARY_DIR}/deps/drogon/trantor/exports"
)

set(
DROGON_INCLUDE_DIR
"${CMAKE_CURRENT_SOURCE_DIR}/deps/drogon/lib/inc"
"${CMAKE_CURRENT_SOURCE_DIR}/deps/drogon/orm_lib/inc"
"${CMAKE_CURRENT_SOURCE_DIR}/deps/drogon/nosql_lib/redis/inc"
"${CMAKE_BINARY_DIR}/deps/drogon/exports"
)

set(BUILD_CTL OFF)
set(BUILD_EXAMPLES OFF)
set(BUILD_BROTLI OFF)
set(BUILD_YAML_CONFIG OFF)
set(USE_SUBMODULE ON)

add_subdirectory(deps/drogon)

target_compile_definitions(topgg PUBLIC __TOPGG_DROGON_WEBHOOKS__)

if(WIN32)
target_compile_definitions(topgg PRIVATE _CRT_SECURE_NO_WARNINGS)
cmake_policy(SET CMP0091 NEW)
endif()
endif()

target_compile_definitions(topgg PRIVATE __TOPGG_BUILDING__)

if(MSVC)
target_compile_options(topgg PUBLIC $<$<CONFIG:Debug>:/diagnostics:caret /MTd> $<$<CONFIG:Release>:/MT /O2 /Oi /Oy /Gy>)
target_compile_options(topgg PRIVATE /nologo $<$<CONFIG:Debug>:/diagnostics:caret /MDd /DDEBUG /D_DEBUG> $<$<CONFIG:Release>:/MD /O2 /Oi /Oy /Gy /DNDEBUG>)
else()
target_compile_options(topgg PUBLIC $<$<CONFIG:Release>:-O3> -Wall -Wextra -Wpedantic -Wformat=2 -Wnull-dereference -Wuninitialized -Wdeprecated)
target_compile_options(topgg PRIVATE $<$<CONFIG:Release>:-O3> -Wall -Wextra -Wpedantic -Wformat=2 -Wnull-dereference -Wuninitialized -Wdeprecated)
endif()

target_include_directories(topgg PUBLIC
${CMAKE_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/include
${DPP_INCLUDE_DIR}
${JSONCPP_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIR}
${TRANTOR_INCLUDE_DIR}
${DROGON_INCLUDE_DIR}
)

target_link_libraries(topgg ${DPP_LIBRARIES})
target_link_libraries(topgg PUBLIC ${DPP_LIBRARIES} ${JSONCPP_LIBRARIES} ${DROGON_LIBRARY})
3 changes: 3 additions & 0 deletions conanfile.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[requires]
jsoncpp/1.9.4
zlib/1.2.11
1 change: 1 addition & 0 deletions deps/drogon
Submodule drogon added at 065899
82 changes: 82 additions & 0 deletions include/topgg/webhooks/cpp-httplib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* @module topgg
* @file cpp-httplib.h
* @brief A community-maintained C++ API Client for the Top.gg API.
* @authors Top.gg, null8626
* @copyright Copyright (c) 2024-2025 Top.gg & null8626
* @date 2025-10-02
* @version 2.1.0
*/

#pragma once

#ifndef CPPHTTPLIB_HTTPLIB_H
#include <cpp-httplib/cpp-httplib.h>
#endif

#include <topgg/webhooks/models.h>

#include <type_traits>
#include <functional>
#include <optional>
#include <string>

namespace topgg {
namespace webhook {
class internal_cpp_httplib {
protected:
const std::string m_authorization;

std::optional<json> parse(const httplib::Request& request, httplib::Response& response) const noexcept;

inline internal_cpp_httplib(const std::string& authorization): m_authorization(authorization) {}

public:
internal_cpp_httplib() = delete;
};

using cpp_httplib_endpoint = std::function<void(const httplib::Request&, httplib::Response&)>;

/**
* @brief An abstract class that receives a Top.gg webhook event. Designed for use in cpp-httplib.
*
* @see topgg::webhook::vote_event
* @since 2.1.0
*/
template<class T>
class cpp_httplib: private internal_cpp_httplib {
public:
cpp_httplib() = delete;

inline cpp_httplib(const std::string& authorization): internal_cpp_httplib(authorization) {
static_assert(std::is_constructible_v<T, const json&>, "T must be a valid model class.");
}

/**
* @brief Returns the endpoint callback to be used in a cpp-httplib server route.
*
* @return cpp_httplib_endpoint The endpoint callback.
* @since 2.1.0
*/
inline cpp_httplib_endpoint endpoint() noexcept {
return [this](const httplib::Request& request, httplib::Response& response) {
const auto json_data{this->parse(request, response)};

if (json_data.has_value()) {
const T data{json_data.value()};

this->callback(data);
}
};
}

/**
* @brief The virtual callback that will be called whenever an incoming webhook request to the endpoint has been authenticated.
*
* @param T data The webhook event data.
* @since 2.1.0
*/
virtual void callback(const T& data) = 0;
};
}; // namespace webhook
}; // namespace topgg
84 changes: 84 additions & 0 deletions include/topgg/webhooks/drogon.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* @module topgg
* @file drogon.h
* @brief A community-maintained C++ API Client for the Top.gg API.
* @authors Top.gg, null8626
* @copyright Copyright (c) 2024-2025 Top.gg & null8626
* @date 2025-10-02
* @version 2.1.0
*/

#pragma once

#ifndef __TOPGG_DROGON_WEBHOOKS__
#define __TOPGG_DROGON_WEBHOOKS__
#endif

#include <topgg/webhooks/models.h>

#include <drogon/drogon.h>

#include <type_traits>
#include <functional>
#include <utility>
#include <string>

#define TOPGG_DROGON_WEBHOOK() \
void asyncHandleHttpRequest(const ::drogon::HttpRequestPtr& request, std::function<void(const ::drogon::HttpResponsePtr &)>&& response) override { \
__handle(request, std::forward<std::function<void(const ::drogon::HttpResponsePtr &)>>(response)); \
}

namespace topgg {
namespace webhook {
class internal_drogon {
protected:
const std::string m_authorization;

std::optional<json> parse(const ::drogon::HttpRequestPtr& request, const ::drogon::HttpResponsePtr& response) const noexcept;

inline internal_drogon(const std::string& authorization): m_authorization(authorization) {}

public:
internal_drogon() = delete;
};

/**
* @brief An abstract class that receives a Top.gg webhook event. Designed for use as a drogon::HttpSimpleController in drogon.
*
* @see topgg::webhook::vote_event
* @since 2.1.0
*/
template<class T>
class drogon: private internal_drogon {
public:
drogon() = delete;

inline drogon(const std::string& authorization): internal_drogon(authorization) {
static_assert(std::is_constructible_v<T, const json&>, "T must be a valid model class.");
}

void __handle(const ::drogon::HttpRequestPtr& request, std::function<void(const ::drogon::HttpResponsePtr &)>&& response) {
const auto response_data{::drogon::HttpResponse::newHttpResponse()};
const auto json_data{parse(request, response_data)};

if (json_data.has_value()) {
const T data{json_data.value()};

callback(data);
}

response(response_data);
}

/**
* @brief The virtual callback that will be called whenever an incoming webhook request to the endpoint has been authenticated.
*
* @param T data The webhook event data.
* @since 2.1.0
*/
virtual void callback(const T& data) = 0;
};
}; // namespace webhook
}; // namespace topgg

#undef __TOPGG_DROGON_WEBHOOKS__
Loading