Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
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 simple API wrapper for Top.gg written in C++.
* @authors Top.gg, null8626
* @copyright Copyright (c) 2024-2025 Top.gg & null8626
* @date 2025-09-13
* @version 3.0.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 3.0.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 3.0.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 3.0.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 simple API wrapper for Top.gg written in C++.
* @authors Top.gg, null8626
* @copyright Copyright (c) 2024-2025 Top.gg & null8626
* @date 2025-09-13
* @version 3.0.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 3.0.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 3.0.0
*/
virtual void callback(const T& data) = 0;
};
}; // namespace webhook
}; // namespace topgg

#undef __TOPGG_DROGON_WEBHOOKS__
Loading