Skip to content
Merged
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
93 changes: 93 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ option(VIX_ENABLE_WEBSOCKET "Build Vix WebSocket module" ON)
option(VIX_ENABLE_CLI "Build Vix CLI module" ON)

option(VIX_FORCE_FETCH_JSON "Fetch JSON backend if modules/json missing" ON)
option(VIX_BENCH_MODE "Disable heavy security/logging checks for benchmarks" OFF)
option(VIX_ENABLE_MIDDLEWARE "Build Vix middleware module" ON)
option(VIX_ENABLE_HTTP_COMPRESSION "Enable HTTP compression middleware deps (zlib/brotli)" ON)

# ----------------------------------------------------
# Tooling / Static analysis
Expand Down Expand Up @@ -184,6 +187,35 @@ endif()
add_library(vix INTERFACE)
add_library(vix::vix ALIAS vix)

# ----------------------------------------------------
# Optional deps: HTTP compression (zlib + brotli)
# Propagate defs/libs to all consumers through vix::vix
# ----------------------------------------------------
if (VIX_ENABLE_HTTP_COMPRESSION)
# ---- zlib (gzip) ----
find_package(ZLIB QUIET)
if (ZLIB_FOUND)
message(STATUS "Compression: zlib found -> gzip enabled")
target_compile_definitions(vix INTERFACE VIX_HAS_ZLIB=1)
target_link_libraries(vix INTERFACE ZLIB::ZLIB)
else()
message(STATUS "Compression: zlib not found -> gzip disabled")
endif()

# ---- brotli (br) ----
find_library(BROTLI_ENC NAMES brotlienc)
find_library(BROTLI_COMMON NAMES brotlicommon)

if (BROTLI_ENC AND BROTLI_COMMON)
message(STATUS "Compression: brotli found -> br enabled")
target_compile_definitions(vix INTERFACE VIX_HAS_BROTLI=1)
target_link_libraries(vix INTERFACE ${BROTLI_ENC} ${BROTLI_COMMON})
else()
message(STATUS "Compression: brotli not found -> br disabled")
endif()
endif()


# Attach warnings/coverage to umbrella (propagates to consumers)
if (TARGET vix_warnings)
target_link_libraries(vix INTERFACE vix_warnings)
Expand Down Expand Up @@ -268,6 +300,48 @@ else()
message(FATAL_ERROR "Missing 'modules/core'. Run: git submodule update --init --recursive")
endif()

# --- Middleware (optional) ---
set(VIX_HAS_MIDDLEWARE OFF)
if (VIX_ENABLE_MIDDLEWARE AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/middleware/CMakeLists.txt")
message(STATUS "Adding 'modules/middleware'...")
add_subdirectory(modules/middleware middleware_build)

# Normalise: expose vix::middleware
if (TARGET vix::middleware OR TARGET vix_middleware)
set(VIX_HAS_MIDDLEWARE ON)
if (TARGET vix_middleware AND NOT TARGET vix::middleware)
add_library(vix::middleware ALIAS vix_middleware)
endif()
else()
message(WARNING "Middleware module added but no vix::middleware target was exported.")
endif()
else()
message(STATUS "Middleware: disabled or not present.")
endif()

# Bench mode (compile-time flags)
if (VIX_BENCH_MODE)
message(STATUS "Bench mode enabled: defining VIX_BENCH_MODE")

# Resolve the real core target (vix::core is an ALIAS in your tree)
set(_VIX_CORE_REAL "")

if (TARGET vix_core)
set(_VIX_CORE_REAL vix_core)
elseif (TARGET vix-core)
set(_VIX_CORE_REAL vix-core)
elseif (TARGET core)
set(_VIX_CORE_REAL core)
endif()

if (_VIX_CORE_REAL)
target_compile_definitions(${_VIX_CORE_REAL} PUBLIC VIX_BENCH_MODE=1)
else()
message(WARNING "Bench mode requested but could not find real core target (tried: vix_core, vix-core, core).")
endif()
endif()


# --- WebSocket (optional) ---
set(VIX_HAS_WEBSOCKET OFF)
if (VIX_ENABLE_WEBSOCKET AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/websocket/CMakeLists.txt")
Expand Down Expand Up @@ -330,6 +404,14 @@ elseif (TARGET vix_websocket)
target_link_libraries(vix INTERFACE vix::websocket)
endif()

# Link middleware only if it exists
if (TARGET vix::middleware)
target_link_libraries(vix INTERFACE vix::middleware)
elseif (TARGET vix_middleware)
add_library(vix::middleware ALIAS vix_middleware)
target_link_libraries(vix INTERFACE vix::middleware)
endif()

# Propagate sanitizers to consumers (umbrella)
if (TARGET vix_sanitizers)
target_link_libraries(vix INTERFACE vix_sanitizers)
Expand Down Expand Up @@ -511,6 +593,11 @@ set(VIX_WITH_OPENSSL ON) # adjust if you ever disable SSL in core
set(VIX_WITH_MYSQL OFF) # do NOT require MySQL for consumers by default
set(VIX_WITH_SQLITE OFF) # will be set ON only if websocket exists

set(VIX_WITH_ZLIB OFF)
if (VIX_ENABLE_HTTP_COMPRESSION AND ZLIB_FOUND)
set(VIX_WITH_ZLIB ON)
endif()

if (TARGET vix::websocket OR TARGET vix_websocket)
set(VIX_WITH_SQLITE ON)
endif()
Expand Down Expand Up @@ -542,6 +629,11 @@ if (VIX_ENABLE_INSTALL)
FILES_MATCHING PATTERN "*.hpp" PATTERN "*.h")
endif()

if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/middleware/include")
install(DIRECTORY modules/middleware/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN "*.hpp" PATTERN "*.h")
endif()

# Export umbrella target (modules must also export their targets into VixTargets)
install(TARGETS vix EXPORT VixTargets)

Expand Down Expand Up @@ -605,6 +697,7 @@ message(STATUS "Project version : ${PROJECT_VERSION}")
message(STATUS "JSON backend : ${_VIX_JSON_BACKEND}")
message(STATUS "WebSocket built : ${VIX_HAS_WEBSOCKET}")
message(STATUS "ORM packaged : ${VIX_HAS_ORM}")
message(STATUS "Middleware built : ${VIX_HAS_MIDDLEWARE}")
message(STATUS "Examples : ${VIX_BUILD_EXAMPLES}")
message(STATUS "Tests : ${VIX_BUILD_TESTS}")
message(STATUS "Sanitizers : ${VIX_ENABLE_SANITIZERS}")
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ using namespace Vix;
int main() {
App app;

app.get("/", [](Request req, Response res) {
res.json({ "message", "Hello world" });
app.get("/", [](Request&, Response& res){
res.send("Hello from Vix.cpp 🚀");
});

app.run(8080);
Expand Down
25 changes: 21 additions & 4 deletions cmake/VixConfig.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,32 @@ include(CMakeFindDependencyMacro)
# MUST be defined BEFORE including VixTargets.cmake
# -------------------------------------------------------

# MySQLCppConn is ONLY needed if vix::orm was built with MySQL,
# but VixTargets.cmake may reference MySQLCppConn::MySQLCppConn.
# We DO NOT force consumers to have MySQL installed.
# If the real package exists, it will define the target; otherwise we create a stub.
find_package(MySQLCppConn QUIET CONFIG)
if (NOT TARGET MySQLCppConn::MySQLCppConn)
add_library(MySQLCppConn::MySQLCppConn INTERFACE IMPORTED)
endif()

# -------------------------------------------------------
# 0bis) Compression deps (optional) — MUST exist before VixTargets.cmake
# -------------------------------------------------------
if (@VIX_WITH_ZLIB@)
find_dependency(ZLIB QUIET)

# Safety net: if ZLIB was found but did not create the target
if (ZLIB_FOUND AND NOT TARGET ZLIB::ZLIB)
add_library(ZLIB::ZLIB INTERFACE IMPORTED)
target_include_directories(ZLIB::ZLIB INTERFACE "${ZLIB_INCLUDE_DIRS}")
target_link_libraries(ZLIB::ZLIB INTERFACE "${ZLIB_LIBRARIES}")
endif()

# If Vix exports ZLIB::ZLIB, we must have it
if (NOT TARGET ZLIB::ZLIB)
message(FATAL_ERROR
"Vix was built with gzip support (VIX_WITH_ZLIB=ON), but ZLIB::ZLIB is not available on this system."
)
endif()
endif()

# -------------------------------------------------------
# 1) Load exported Vix targets
# -------------------------------------------------------
Expand Down
24 changes: 24 additions & 0 deletions config/config copy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"database": {
"default": {
"ENGINE": "mysql",
"NAME": "mydb",
"USER": "myuser",
"PASSWORD": "",
"HOST": "localhost",
"PORT": 3306
}
},

"server": {
"port": 8080,
"request_timeout": 5000
},

"websocket": {
"port": 9090,
"max_message_size": 65536,
"idle_timeout": 60,
"ping_interval": 30
}
}
29 changes: 11 additions & 18 deletions config/config.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
{
"database": {
"default": {
"ENGINE": "mysql",
"NAME": "mydb",
"USER": "myuser",
"PASSWORD": "",
"HOST": "localhost",
"PORT": 3306
}
},

"server": {
"port": 8080,
"request_timeout": 5000
"request_timeout": 2000,
"io_threads": 0
},
"logging": {
"async": true,
"queue_max": 20000,
"drop_on_overflow": true
},

"websocket": {
"port": 9090,
"max_message_size": 65536,
"idle_timeout": 60,
"ping_interval": 30
"waf": {
"mode": "basic",
"max_target_len": 4096,
"max_body_bytes": 1048576
}
}
83 changes: 83 additions & 0 deletions examples/auth/api_key_app_simple.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// ============================================================================
// api_key_app_simple.cpp — API Key auth example (Vix.cpp)
// ----------------------------------------------------------------------------
// Run:
// vix run api_key_app_simple.cpp
//
// Test:
// # Missing key -> 401
// curl -i http://localhost:8080/secure
//
// # Invalid key -> 403
// curl -i -H "x-api-key: wrong" http://localhost:8080/secure
// curl -i "http://localhost:8080/secure?api_key=wrong"
//
// # Valid key -> 200
// curl -i -H "x-api-key: secret" http://localhost:8080/secure
// curl -i "http://localhost:8080/secure?api_key=secret"
// ============================================================================

#include <iostream>
#include <string>

#include <vix.hpp>
#include <vix/middleware/app/presets.hpp>

using namespace vix;

static void print_help()
{
std::cout
<< "Vix API Key example running:\n"
<< " http://localhost:8080/\n"
<< " http://localhost:8080/secure\n\n"
<< "Valid key:\n"
<< " secret\n\n"
<< "Try:\n"
<< " curl -i http://localhost:8080/secure\n"
<< " curl -i -H \"x-api-key: wrong\" http://localhost:8080/secure\n"
<< " curl -i -H \"x-api-key: secret\" http://localhost:8080/secure\n"
<< " curl -i \"http://localhost:8080/secure?api_key=wrong\"\n"
<< " curl -i \"http://localhost:8080/secure?api_key=secret\"\n\n";
}

int main()
{
App app;

// ---------------------------------------------------------------------
// API key protection (preset)
// - Header: x-api-key
// - Query : ?api_key=
// - Allowed key: "secret"
// ---------------------------------------------------------------------
app.use("/secure", middleware::app::api_key_dev("secret"));
// app.use(
// "/secure",
// middleware::app::api_key_auth({
// .header = "x-api-key",
// .query_param = "api_key",
// .allowed_keys = {"secret"},
// }));

// ---------------------------------------------------------------------
// Routes
// ---------------------------------------------------------------------
app.get("/", [](Request &, Response &res)
{ res.send(
"API Key example:\n"
" /secure requires x-api-key: secret OR ?api_key=secret\n"); });

app.get("/secure", [](Request &req, Response &res)
{
auto &key = req.state<vix::middleware::auth::ApiKey>();

res.json({
"ok", true,
"api_key", key.value
}); });

print_help();
app.run(8080);
return 0;
}
Loading
Loading