diff --git a/.github/workflows/MODULE_TESTS_CI.yml b/.github/workflows/MODULE_TESTS_CI.yml index 6ccd5ee..61e64e5 100644 --- a/.github/workflows/MODULE_TESTS_CI.yml +++ b/.github/workflows/MODULE_TESTS_CI.yml @@ -54,12 +54,14 @@ env: libspdlog-dev libfmt-dev libmysqlcppconn-dev + libgtest-dev BUILD_JOBS: 2 jobs: umbrella-tests: name: Umbrella Tests (${{ matrix.compiler }}) runs-on: ubuntu-latest + timeout-minutes: 90 strategy: fail-fast: false @@ -90,6 +92,7 @@ jobs: test -f modules/ui/CMakeLists.txt test -f modules/note/CMakeLists.txt test -f modules/requests/CMakeLists.txt + test -f modules/realtime/CMakeLists.txt - name: Select compiler run: | @@ -148,6 +151,11 @@ jobs: -DVIX_ENABLE_REQUESTS=ON \ -DVIX_REQUESTS_BUILD_TESTS=ON \ -DVIX_REQUESTS_BUILD_EXAMPLES=OFF \ + -DVIX_ENABLE_REALTIME=ON \ + -DVIX_REALTIME_BUILD_TESTS=ON \ + -DVIX_REALTIME_BUILD_EXAMPLES=OFF \ + -DVIX_REALTIME_WITH_WEBSOCKET=ON \ + -DVIX_REALTIME_WITH_POSTGRES=OFF \ -DVIX_ENABLE_VALIDATION=ON \ -DVIX_ENABLE_CACHE=ON \ -DVIX_ENABLE_P2P=ON \ @@ -181,11 +189,26 @@ jobs: - name: Run tests run: | - ctest --test-dir build-tests --output-on-failure + set -euxo pipefail + + echo "=== Runner resources ===" + free -h + df -h + nproc + ulimit -a + + stdbuf -oL -eL ctest \ + --test-dir build-tests \ + --output-on-failure \ + --parallel 1 \ + --timeout 180 \ + -E '^(vix_cli_git_dependencies|vix_cli_init_and_auto_git)$' \ + -V module-tests-light: name: Module Tests Light Profile runs-on: ubuntu-latest + timeout-minutes: 60 steps: - name: Checkout umbrella repository @@ -211,6 +234,7 @@ jobs: test -f modules/ui/CMakeLists.txt test -f modules/note/CMakeLists.txt test -f modules/requests/CMakeLists.txt + test -f modules/realtime/CMakeLists.txt - name: Configure light module tests run: | @@ -264,7 +288,12 @@ jobs: -DVIX_ENABLE_WEBSOCKET=OFF \ -DVIX_ENABLE_REQUESTS=ON \ -DVIX_REQUESTS_BUILD_TESTS=ON \ - -DVIX_REQUESTS_BUILD_EXAMPLES=OFF + -DVIX_REQUESTS_BUILD_EXAMPLES=OFF \ + -DVIX_ENABLE_REALTIME=ON \ + -DVIX_REALTIME_BUILD_TESTS=ON \ + -DVIX_REALTIME_BUILD_EXAMPLES=OFF \ + -DVIX_REALTIME_WITH_WEBSOCKET=OFF \ + -DVIX_REALTIME_WITH_POSTGRES=OFF - name: Build light module tests run: | @@ -281,4 +310,17 @@ jobs: - name: Run light module tests run: | - ctest --test-dir build-module-light --output-on-failure + set -euxo pipefail + + echo "=== Runner resources ===" + free -h + df -h + nproc + ulimit -a + + stdbuf -oL -eL ctest \ + --test-dir build-module-light \ + --output-on-failure \ + --parallel 1 \ + --timeout 180 \ + -V diff --git a/.github/workflows/SECURITY_CI.yml b/.github/workflows/SECURITY_CI.yml index 50f6f6a..e691bfa 100644 --- a/.github/workflows/SECURITY_CI.yml +++ b/.github/workflows/SECURITY_CI.yml @@ -75,6 +75,7 @@ env: libfmt-dev libmysqlcppconn-dev libgtk-3-dev + libgtest-dev BUILD_JOBS: 2 @@ -359,8 +360,20 @@ jobs: - name: Run module tests run: | set -euxo pipefail - ctest --test-dir build-tests --output-on-failure --timeout 180 + echo "=== Resources before module tests ===" + free -h + df -h + ulimit -a + nproc + + stdbuf -oL -eL ctest \ + --test-dir build-tests \ + --output-on-failure \ + --parallel 1 \ + --timeout 180 \ + -E '^(vix_cli_git_dependencies|vix_cli_init_and_auto_git)$' \ + -V sanitized-module-tests: name: Sanitized Module Tests runs-on: ubuntu-latest @@ -426,11 +439,11 @@ jobs: - name: Run sanitized module tests run: | set -euxo pipefail + ctest --test-dir build-san-tests \ --output-on-failure \ --timeout 180 \ - -E "^ShutdownTest$" - + -E "^(ShutdownTest|vix_cli_git_dependencies|vix_cli_init_and_auto_git)$" runtime-smoke: name: Runtime Smoke and CLI Checks runs-on: ubuntu-latest @@ -730,7 +743,7 @@ jobs: ! -path '*/CMakeFiles/*' \ ! -path '*/_deps/*' \ | grep -E '(^|/)([^/]*test[^/]*|[^/]*tests[^/]*)$' \ - | grep -Ev '(_bench|benchmark|cmake|ctest|vix$|vix_cli$|ScopeTest$|ShutdownTest$|TaskCancellationTest$|ThreadPoolTest$|runtime_worker_test$)' \ + | grep -Ev '(_bench|benchmark|cmake|ctest|vix$|vix_cli$|ScopeTest$|ShutdownTest$|TaskCancellationTest$|ThreadPoolTest$|runtime_worker_test$|websocket_metrics_server_lifecycle_test$|websocket_metrics_server_request_test$)' \ | sort -u ) diff --git a/.github/workflows/build-safety.yml b/.github/workflows/build-safety.yml index 58bfa3f..78d36b2 100644 --- a/.github/workflows/build-safety.yml +++ b/.github/workflows/build-safety.yml @@ -12,12 +12,21 @@ on: - dev - release/** +permissions: + contents: read + +concurrency: + group: build-safety-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build-safety: + name: Build safety (Ubuntu) runs-on: ubuntu-latest + timeout-minutes: 45 steps: - - name: Checkout + - name: Checkout repository uses: actions/checkout@v4 with: submodules: recursive @@ -25,6 +34,8 @@ jobs: - name: Install system dependencies run: | + set -euxo pipefail + sudo apt-get update sudo apt-get install -y --no-install-recommends \ build-essential \ @@ -58,6 +69,8 @@ jobs: - name: Configure Vix CLI run: | + set -euxo pipefail + cmake -S . -B build-ci -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ @@ -81,22 +94,32 @@ jobs: - name: Build Vix CLI run: | + set -euxo pipefail cmake --build build-ci --target vix -- -j"$(nproc)" - name: Show Vix version run: | + set -x ./build-ci/vix --version || ./build-ci/vix version || true - name: Run build safety tests run: | + set -euxo pipefail VIX_BIN="$PWD/build-ci/vix" scripts/test-build-safety.sh - name: Run build benchmark smoke test run: | - VIX_BIN="$PWD/build-ci/vix" RUNS=3 WARMUP=1 TARGET=vix scripts/bench-build.sh + set -euxo pipefail + VIX_BIN="$PWD/build-ci/vix" \ + RUNS=3 \ + WARMUP=1 \ + TARGET=vix \ + scripts/bench-build.sh - name: Upload benchmark report + if: always() uses: actions/upload-artifact@v4 with: - name: vix-build-benchmark + name: vix-build-benchmark-${{ github.run_id }} path: .vix/bench/reports/ + if-no-files-found: warn diff --git a/.gitmodules b/.gitmodules index 7513598..cb54787 100644 --- a/.gitmodules +++ b/.gitmodules @@ -167,3 +167,7 @@ path = modules/engine url = https://github.com/vixcpp/engine.git branch = dev +[submodule "modules/realtime"] + path = modules/realtime + url = https://github.com/vixcpp/realtime.git + branch = dev diff --git a/CHANGELOG.md b/CHANGELOG.md index 12c73a7..5902278 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,458 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +# Vix v2.8.0 + +## Added + +### Stateful realtime applications + +Added the new `vix::realtime` module for building authoritative, stateful realtime applications in C++. + +The module introduces a transport-independent runtime based on: + +- stateful rooms; +- serialized commands; +- deterministic events; +- logical sessions; +- room membership; +- presence; +- snapshots; +- event replay; +- reconnection; +- interchangeable persistence stores. + +Applications can now define their own room state and command handlers while the runtime manages command execution, event persistence, state application, room versions, snapshots, recovery, and session routing. + +### Authoritative rooms + +Added rooms with one authoritative state and one serialized command execution path. + +Rooms support: + +- explicit opening and closing; +- application-defined room types; +- custom state implementations; +- custom command handlers; +- session joins and leaves; +- queued and immediate commands; +- event broadcasting; +- command backpressure; +- room metadata; +- configurable lifecycle behavior; +- deterministic failure handling. + +Commands are executed serially to prevent concurrent mutations of authoritative room state. + +### Commands and events + +Added typed room commands with: + +- room identifiers; +- session identifiers; +- request identifiers; +- correlation identifiers; +- expected room versions; +- JSON payloads; +- metadata; +- creation timestamps; +- validation. + +Accepted commands can produce one or more events. + +Events receive authoritative event identifiers and room versions before being persisted and applied to room state. + +### Event audiences + +Added event audience controls for delivering events to: + +- the complete room; +- only the sending session; +- every session except the sender; +- selected sessions. + +The room runtime remains independent from the network transport responsible for delivering those events. + +### Snapshots and event replay + +Added snapshot-based room recovery. + +Rooms can now: + +- create snapshots after a configured number of events; +- create snapshots explicitly; +- create a final snapshot when closing; +- retain a configurable number of recent snapshots; +- restore the latest available snapshot; +- replay events created after the snapshot; +- replay the complete history when no snapshot exists. + +Recovery preserves: + +- authoritative room state; +- room version; +- latest event identifier; +- deterministic event ordering. + +Reopening a room does not duplicate already persisted events. + +### Logical sessions + +Added logical sessions that are independent from individual network connections. + +Sessions support: + +- stable session identifiers; +- identity information; +- metadata; +- room memberships; +- connection attachment and detachment; +- connection replacement; +- resume tokens; +- per-room acknowledgement positions. + +A session can remain recoverable after its underlying transport connection is lost. + +### Session reconnection + +Added session recovery using resume tokens and acknowledged event positions. + +Reconnect flows can now: + +- validate a resume token; +- replace the previous connection; +- restore session memberships; +- replay missing room events; +- continue from the last acknowledged event; +- maintain independent replay positions across rooms. + +### Snapshot fallback + +Added snapshot fallback for clients that are too far behind for a bounded event replay. + +The recovery flow can send: + +1. the latest available room snapshot; +2. events persisted after that snapshot; +3. the final replay position. + +This allows stale clients to recover without replaying the entire room history. + +### Presence + +Added local presence tracking for room sessions. + +Presence records support: + +- room and session identifiers; +- identity; +- node ownership; +- connection identifiers; +- metadata; +- heartbeat timestamps; +- present, detached, and left states; +- expiration and stale-record cleanup. + +### Room management + +Added `RoomManager` for coordinating rooms, sessions, factories, stores, presence, and command routing. + +The manager supports: + +- room factory registration; +- opening and locating rooms; +- closing rooms; +- creating and locating sessions; +- joining and leaving rooms; +- attaching and detaching connections; +- routing room commands; +- configured room and session limits; +- inactive room cleanup; +- controlled runtime shutdown. + +### Room directory and ownership + +Added room directory and ownership abstractions. + +Active rooms can be associated with the node responsible for their authoritative execution, providing the foundation for future multi-process and distributed routing. + +### Persistence stores + +Added persistence interfaces for: + +- room events; +- room snapshots; +- presence records. + +The initial runtime includes: + +- `MemoryEventStore`; +- `MemorySnapshotStore`; +- local in-memory presence storage. + +Event and snapshot stores can be replaced without changing application room state or command handlers. + +### Optional PostgreSQL persistence + +Added optional PostgreSQL event and snapshot store support. + +PostgreSQL persistence is disabled by default and can be enabled independently from the realtime transport layer. + +### Optional WebSocket adapter + +Added an optional adapter between `vix::realtime` and `vix::websocket`. + +The adapter handles: + +- connection lifecycle events; +- realtime protocol parsing; +- session opening and resumption; +- room joins and leaves; +- command forwarding; +- event delivery; +- acknowledgements; +- protocol errors; +- connection backpressure. + +The authoritative realtime core can be built and used without WebSocket support. + +### Realtime protocol + +Added a versioned protocol envelope for communication between realtime clients and servers. + +Protocol messages cover: + +- session opening; +- session resumption; +- room joining; +- room leaving; +- room commands; +- command acceptance; +- command rejection; +- room events; +- room snapshots; +- event acknowledgements; +- replay completion; +- presence updates; +- ping and pong; +- protocol errors; +- server draining notifications. + +Protocol messages include version validation and structured parsing errors. + +### Public API + +Added the stable realtime umbrella header: + +```cpp +#include +``` + +Advanced APIs remain available through module-specific headers: + +```cpp +#include +``` + +The public CMake targets are: + +```cmake +vix_realtime +vix::realtime +``` + +### Realtime package + +Added standalone package metadata for: + +```text +vix/realtime +``` + +The first standalone module version is: + +```text +0.1.0 +``` + +Added: + +- `vix.json`; +- CMake package configuration; +- package version generation; +- exported CMake target definitions; +- optional dependency configuration; +- standalone install preparation. + +### Examples + +Added four complete realtime examples. + +#### Counter + +Demonstrates: + +- room commands; +- deterministic events; +- automatic snapshots; +- state restoration; +- continued event and room versions. + +#### Shared room + +Demonstrates: + +- multiple sessions in one room; +- authoritative shared state; +- room membership; +- object placement and removal; +- room-wide event broadcasting. + +#### Chat + +Demonstrates: + +- persistent chat messages; +- session membership; +- room history; +- snapshots; +- room restoration; +- continued message state. + +#### Reconnect + +Demonstrates: + +- event acknowledgements; +- temporary disconnection; +- replay of missing events; +- resume-token validation; +- snapshot fallback; +- restoration of authoritative state. + +### Realtime strict CI + +Added a dedicated strict CI workflow for the realtime module. + +The workflow validates: + +- GCC and Clang builds; +- Debug and Release configurations; +- WebSocket enabled and disabled builds; +- examples enabled and disabled builds; +- AddressSanitizer and UndefinedBehaviorSanitizer; +- the complete realtime test suite; +- compiler warning enforcement; +- execution of all four examples; +- static analysis with `clang-tidy`; +- static analysis with `cppcheck`; +- Valgrind memory checks; +- PostgreSQL store compilation; +- package metadata consistency; +- CMake package contract consistency. + +## Improved + +### Realtime transport separation + +Realtime application state is no longer coupled to WebSocket-specific behavior. + +Rooms, sessions, commands, events, snapshots, replay, and presence belong to the transport-independent runtime. WebSocket is implemented as an optional adapter around that runtime. + +This allows additional transports to reuse the same authoritative application model. + +### Deterministic recovery + +Room restoration now follows one consistent recovery sequence: + +1. load the latest snapshot when available; +2. restore the snapshot state and schema version; +3. replay persisted events after the snapshot; +4. restore the latest room version and event identifier; +5. continue accepting new commands from the recovered position. + +Multiple restorations from the same persisted history produce the same state and version. + +### Realtime configuration + +Added configuration for: + +- maximum active rooms; +- maximum sessions per room; +- maximum queued commands; +- snapshot frequency; +- snapshot creation during room shutdown; +- retained snapshot count; +- room restoration during opening; +- session recovery windows; +- replay limits; +- presence expiration. + +## Validation + +The realtime module was validated with: + +- identifier and version tests; +- command and event tests; +- protocol parsing tests; +- protocol validation tests; +- protocol round-trip tests; +- room state tests; +- event application tests; +- memory event store tests; +- memory snapshot store tests; +- snapshot policy tests; +- logical session tests; +- session disconnection tests; +- presence join, leave, heartbeat, expiration, and visibility tests; +- room construction and opening tests; +- room command tests; +- room event tests; +- room membership tests; +- room broadcast tests; +- room snapshot and restoration tests; +- room lifecycle tests; +- command backpressure tests; +- room shutdown and failure tests; +- room directory and ownership tests; +- room manager tests; +- WebSocket adapter tests; +- resume-token tests; +- reconnection replay tests; +- snapshot fallback tests; +- complete realtime session flow tests; +- deterministic snapshot and replay integration tests. + +The complete module builds successfully with tests and examples enabled. + +The following example flows were executed successfully: + +```text +counter +shared_room +chat +reconnect +``` + +Validation confirmed: + +- deterministic command execution; +- monotonic room versions; +- monotonic event identifiers; +- event persistence; +- automatic snapshots; +- snapshot restoration; +- replay after snapshots; +- complete replay without snapshots; +- no duplicated persisted events after reopening; +- continued command execution after recovery; +- session membership changes; +- shared authoritative room state; +- persistent chat history; +- replay from acknowledged positions; +- snapshot fallback for stale clients; +- restoration of the final authoritative state. + # Vix v2.7.8 ## Added diff --git a/CMakeLists.txt b/CMakeLists.txt index ddc3967..447a3a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,6 +84,7 @@ set(_VIX_SDK_PROFILE_OPTION_VARS VIX_ENABLE_CRYPTO VIX_ENABLE_WEBRPC VIX_ENABLE_REQUESTS + VIX_ENABLE_REALTIME VIX_ENABLE_TIME VIX_ENABLE_TESTS_MODULE VIX_ENABLE_TEMPLATE @@ -250,7 +251,7 @@ option(VIX_ENABLE_CPPCHECK "Enable cppcheck if available" option(VIX_ENABLE_COVERAGE "Enable coverage flags (Debug only)" OFF) option(VIX_ENABLE_SANITIZERS "Enable ASan+UBSan (GCC/Clang only)" OFF) option(VIX_BUILD_EXAMPLES "Build umbrella examples in ./examples" ON) -option(VIX_BUILD_TESTS "Build unit tests (GoogleTest)" ON) +option(VIX_BUILD_TESTS "Build unit tests (GoogleTest)" OFF) option(VIX_ENABLE_ORM "Build Vix ORM module" ON) option(VIX_ENABLE_WEBSOCKET "Build Vix WebSocket module" ON) option(VIX_ENABLE_CLI "Build Vix CLI module" ON) @@ -272,6 +273,11 @@ option(VIX_ENABLE_VALIDATION "Build Vix Validation module" option(VIX_ENABLE_CRYPTO "Build Vix Crypto module" ON) option(VIX_ENABLE_WEBRPC "Build Vix WebRPC module" ON) option(VIX_ENABLE_REQUESTS "Build Vix Requests module" ON) +option(VIX_ENABLE_REALTIME "Build Vix Realtime module" ON) +option(VIX_REALTIME_BUILD_TESTS "Build vix::realtime tests" ${VIX_BUILD_TESTS}) +option(VIX_REALTIME_BUILD_EXAMPLES "Build vix::realtime examples" OFF) +option(VIX_REALTIME_WITH_WEBSOCKET "Build vix::realtime WebSocket transport adapter" ${VIX_ENABLE_WEBSOCKET}) +option(VIX_REALTIME_WITH_POSTGRES "Build vix::realtime PostgreSQL stores" OFF) option(VIX_REQUESTS_BUILD_TESTS "Build vix::requests tests" ${VIX_BUILD_TESTS}) option(VIX_REQUESTS_BUILD_EXAMPLES "Build vix::requests examples" OFF) option(VIX_ENABLE_TIME "Build Vix Time module" ON) @@ -347,6 +353,7 @@ function(vix_sdk_profile_common) vix_sdk_profile_default(VIX_ENABLE_CRYPTO OFF) vix_sdk_profile_default(VIX_ENABLE_WEBRPC OFF) vix_sdk_profile_default(VIX_ENABLE_REQUESTS OFF) + vix_sdk_profile_default(VIX_ENABLE_REALTIME OFF) vix_sdk_profile_default(VIX_ENABLE_TIME ON) vix_sdk_profile_default(VIX_ENABLE_TESTS_MODULE OFF) vix_sdk_profile_default(VIX_ENABLE_TEMPLATE ON) @@ -374,6 +381,7 @@ if (NOT _VIX_SDK_PROFILE_EFFECTIVE STREQUAL "legacy") vix_sdk_profile_default(VIX_ENABLE_CRYPTO ON) vix_sdk_profile_default(VIX_ENABLE_WEBRPC ON) vix_sdk_profile_default(VIX_ENABLE_REQUESTS ON) + vix_sdk_profile_default(VIX_ENABLE_REALTIME ON) elseif (_VIX_SDK_PROFILE_EFFECTIVE STREQUAL "data") vix_sdk_profile_default(VIX_ENABLE_DB ON) vix_sdk_profile_default(VIX_ENABLE_ORM ON) @@ -410,6 +418,7 @@ if (NOT _VIX_SDK_PROFILE_EFFECTIVE STREQUAL "legacy") vix_sdk_profile_default(VIX_ENABLE_CRYPTO ON) vix_sdk_profile_default(VIX_ENABLE_WEBRPC ON) vix_sdk_profile_default(VIX_ENABLE_REQUESTS ON) + vix_sdk_profile_default(VIX_ENABLE_REALTIME ON) vix_sdk_profile_default(VIX_ENABLE_KV ON) vix_sdk_profile_default(VIX_ENABLE_AGENT ON) vix_sdk_profile_default(VIX_ENABLE_GAME ON) @@ -446,6 +455,7 @@ set(_VIX_SDK_PACKAGE_P2P ON) set(_VIX_SDK_PACKAGE_P2P_HTTP ON) set(_VIX_SDK_PACKAGE_AGENT ON) set(_VIX_SDK_PACKAGE_GAME ON) +set(_VIX_SDK_PACKAGE_REALTIME ON) if (NOT _VIX_SDK_PROFILE_EFFECTIVE STREQUAL "legacy") vix_sdk_profile_user_set(_VIX_SDK_USER_DB VIX_ENABLE_DB) @@ -455,6 +465,7 @@ if (NOT _VIX_SDK_PROFILE_EFFECTIVE STREQUAL "legacy") vix_sdk_profile_user_set(_VIX_SDK_USER_P2P_HTTP VIX_ENABLE_P2P_HTTP) vix_sdk_profile_user_set(_VIX_SDK_USER_AGENT VIX_ENABLE_AGENT) vix_sdk_profile_user_set(_VIX_SDK_USER_GAME VIX_ENABLE_GAME) + vix_sdk_profile_user_set(_VIX_SDK_USER_REALTIME VIX_ENABLE_REALTIME) set(_VIX_SDK_PACKAGE_DB OFF) set(_VIX_SDK_PACKAGE_ORM OFF) @@ -463,6 +474,7 @@ if (NOT _VIX_SDK_PROFILE_EFFECTIVE STREQUAL "legacy") set(_VIX_SDK_PACKAGE_P2P_HTTP OFF) set(_VIX_SDK_PACKAGE_AGENT OFF) set(_VIX_SDK_PACKAGE_GAME OFF) + set(_VIX_SDK_PACKAGE_REALTIME OFF) if (_VIX_SDK_PROFILE_EFFECTIVE STREQUAL "data" OR _VIX_SDK_PROFILE_EFFECTIVE STREQUAL "all" OR (_VIX_SDK_USER_DB AND VIX_ENABLE_DB)) set(_VIX_SDK_PACKAGE_DB ON) @@ -485,6 +497,9 @@ if (NOT _VIX_SDK_PROFILE_EFFECTIVE STREQUAL "legacy") if (_VIX_SDK_PROFILE_EFFECTIVE STREQUAL "game" OR _VIX_SDK_PROFILE_EFFECTIVE STREQUAL "all" OR (_VIX_SDK_USER_GAME AND VIX_ENABLE_GAME)) set(_VIX_SDK_PACKAGE_GAME ON) endif() + if (_VIX_SDK_PROFILE_EFFECTIVE STREQUAL "web" OR _VIX_SDK_PROFILE_EFFECTIVE STREQUAL "all" OR (_VIX_SDK_USER_REALTIME AND VIX_ENABLE_REALTIME)) + set(_VIX_SDK_PACKAGE_REALTIME ON) + endif() endif() # ---------------------------------------------------- # Module test defaults @@ -507,6 +522,7 @@ set(VIX_CONVERSION_BUILD_TESTS ${VIX_BUILD_TESTS} CACHE BOOL "Build vix::convers set(VIX_VALIDATION_BUILD_TESTS ${VIX_BUILD_TESTS} CACHE BOOL "Build vix::validation tests") set(VIX_WEBRPC_BUILD_TESTS ${VIX_BUILD_TESTS} CACHE BOOL "Build vix::webrpc tests") set(VIX_REQUESTS_BUILD_TESTS ${VIX_BUILD_TESTS} CACHE BOOL "Build vix::requests tests") +set(VIX_REALTIME_BUILD_TESTS ${VIX_BUILD_TESTS} CACHE BOOL "Build vix::realtime tests") set(VIX_NET_BUILD_TESTS ${VIX_BUILD_TESTS} CACHE BOOL "Build vix::net tests") set(VIX_SYNC_BUILD_TESTS ${VIX_BUILD_TESTS} CACHE BOOL "Build vix::sync tests") set(VIX_CACHE_BUILD_TESTS ${VIX_BUILD_TESTS} CACHE BOOL "Build vix::cache tests") @@ -1526,6 +1542,51 @@ else() message(STATUS "WebSocket: disabled or not present.") endif() +# --- Realtime (optional) --- +set(VIX_HAS_REALTIME OFF) +if (VIX_ENABLE_REALTIME AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/realtime/CMakeLists.txt") + if (NOT VIX_HAS_ASYNC) + message(FATAL_ERROR "Realtime requires Async module. Enable it with -DVIX_ENABLE_ASYNC=ON.") + endif() + if (NOT VIX_HAS_TIME) + message(FATAL_ERROR "Realtime requires Time module. Enable it with -DVIX_ENABLE_TIME=ON.") + endif() + if (NOT VIX_HAS_SYNC) + message(FATAL_ERROR "Realtime requires Sync module. Ensure modules/sync exists and configures successfully.") + endif() + + message(STATUS "Adding 'modules/realtime'...") + + if (VIX_REALTIME_WITH_WEBSOCKET AND NOT VIX_HAS_WEBSOCKET) + message(WARNING "Realtime WebSocket adapter requested but WebSocket module is missing -> disabling adapter") + set(VIX_REALTIME_WITH_WEBSOCKET OFF CACHE BOOL "Build vix::realtime WebSocket transport adapter" FORCE) + endif() + + if (VIX_REALTIME_WITH_POSTGRES AND NOT VIX_HAS_DB) + message(FATAL_ERROR "Realtime PostgreSQL stores require DB module. Enable VIX_ENABLE_DB=ON or disable VIX_REALTIME_WITH_POSTGRES.") + endif() + + set(VIX_REALTIME_FETCH_DEPENDENCIES ${VIX_FETCH_DEPS} CACHE BOOL "Fetch missing Vix dependencies" FORCE) + set(VIX_REALTIME_BUILD_TESTS ${VIX_REALTIME_BUILD_TESTS} CACHE BOOL "Build realtime module tests" FORCE) + set(VIX_REALTIME_BUILD_EXAMPLES ${VIX_REALTIME_BUILD_EXAMPLES} CACHE BOOL "Build realtime module examples" FORCE) + set(VIX_REALTIME_WITH_WEBSOCKET ${VIX_REALTIME_WITH_WEBSOCKET} CACHE BOOL "Build the Vix WebSocket transport adapter" FORCE) + set(VIX_REALTIME_WITH_POSTGRES ${VIX_REALTIME_WITH_POSTGRES} CACHE BOOL "Build PostgreSQL event and snapshot stores" FORCE) + set(VIX_REALTIME_ENABLE_INSTALL ${_VIX_SDK_PACKAGE_REALTIME} CACHE BOOL "Generate install rules for the realtime package" FORCE) + + add_subdirectory(modules/realtime realtime_build) + + if (TARGET vix::realtime OR TARGET vix_realtime) + set(VIX_HAS_REALTIME ON) + if (TARGET vix_realtime AND NOT TARGET vix::realtime) + add_library(vix::realtime ALIAS vix_realtime) + endif() + else() + message(WARNING "Realtime module added but no vix::realtime target was exported.") + endif() +else() + message(STATUS "Realtime: disabled or not present.") +endif() + # --- Engine (optional, before CLI) --- if (VIX_ENABLE_ENGINE AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/engine/CMakeLists.txt") message(STATUS "Adding 'modules/engine'...") @@ -1711,6 +1772,10 @@ if (TARGET vix::requests) target_link_libraries(vix INTERFACE vix::requests) endif() +if (TARGET vix::realtime AND _VIX_SDK_PACKAGE_REALTIME) + target_link_libraries(vix INTERFACE vix::realtime) +endif() + # Link websocket only if it exists if (TARGET vix::websocket) target_link_libraries(vix INTERFACE vix::websocket) @@ -1942,6 +2007,11 @@ if (VIX_HAS_REQUESTS) set(VIX_WITH_REQUESTS ON) endif() +set(VIX_WITH_REALTIME OFF) +if (VIX_HAS_REALTIME AND _VIX_SDK_PACKAGE_REALTIME) + set(VIX_WITH_REALTIME ON) +endif() + if ((VIX_HAS_DB AND VIX_DB_USE_SQLITE) OR VIX_HAS_WEBSOCKET) set(VIX_WITH_SQLITE ON) endif() @@ -1949,7 +2019,7 @@ endif() if (VIX_ENABLE_INSTALL) if (_VIX_SDK_PROFILE_EFFECTIVE STREQUAL "legacy") - set(_VIX_INSTALL_MODULES error path fs io env os log tests core utils json websocket webrpc requests crypto time conversion validation async process threadpool kv agent game net cache sync p2p p2p_http middleware db orm template ui note) + set(_VIX_INSTALL_MODULES error path fs io env os log tests core utils json websocket webrpc requests realtime crypto time conversion validation async process threadpool kv agent game net cache sync p2p p2p_http middleware db orm template ui note) else() set(_VIX_INSTALL_MODULES error path fs io env os log core utils json time conversion async process threadpool template ui note net sync crypto) if (VIX_HAS_WEBRPC) @@ -1958,6 +2028,9 @@ if (VIX_ENABLE_INSTALL) if (VIX_HAS_REQUESTS) list(APPEND _VIX_INSTALL_MODULES requests) endif() + if (VIX_HAS_REALTIME AND _VIX_SDK_PACKAGE_REALTIME) + list(APPEND _VIX_INSTALL_MODULES realtime) + endif() if (VIX_HAS_VALIDATION) list(APPEND _VIX_INSTALL_MODULES validation) endif() @@ -2172,6 +2245,9 @@ if (VIX_ENABLE_INSTALL) set(VIX_HAS_REQUESTS ${VIX_HAS_REQUESTS}) set(VIX_WITH_REQUESTS ${VIX_WITH_REQUESTS}) + set(VIX_HAS_REALTIME ${VIX_WITH_REALTIME}) + set(VIX_WITH_REALTIME ${VIX_WITH_REALTIME}) + set(VIX_WITH_AGENT OFF) if (VIX_HAS_AGENT AND _VIX_SDK_PACKAGE_AGENT) set(VIX_WITH_AGENT ON) @@ -2253,6 +2329,7 @@ message(STATUS "JSON backend : ${_VIX_JSON_BACKEND}") message(STATUS "Time module : ${VIX_HAS_TIME}") message(STATUS "WebRPC built : ${VIX_HAS_WEBRPC}") message(STATUS "Requests built : ${VIX_HAS_REQUESTS}") +message(STATUS "Realtime built : ${VIX_HAS_REALTIME}") message(STATUS "WebSocket built : ${VIX_HAS_WEBSOCKET}") message(STATUS "Process built : ${VIX_HAS_PROCESS}") message(STATUS "ThreadPool built : ${VIX_HAS_THREADPOOL}") @@ -2276,5 +2353,5 @@ message(STATUS "Sanitizers : ${VIX_ENABLE_SANITIZERS}") message(STATUS "Coverage : ${VIX_ENABLE_COVERAGE}") message(STATUS "LTO : ${VIX_ENABLE_LTO}") message(STATUS "Install/Export : ${VIX_ENABLE_INSTALL}") -message(STATUS "Flags exported : JSON=${VIX_WITH_JSON} CONVERSION=${VIX_WITH_CONVERSION} VALIDATION=${VIX_WITH_VALIDATION} WEBRPC=${VIX_WITH_WEBRPC} REQUESTS=${VIX_WITH_REQUESTS} CRYPTO=${VIX_WITH_CRYPTO} BOOST_FS=${VIX_WITH_BOOST_FS} OPENSSL=${VIX_WITH_OPENSSL} SQLITE=${VIX_WITH_SQLITE} MYSQL=${VIX_WITH_MYSQL} HAS_ORM=${VIX_HAS_ORM} CACHE=${VIX_WITH_CACHE} P2P=${VIX_WITH_P2P} TEMPLATE=${VIX_WITH_TEMPLATE} UI=${VIX_WITH_UI} UI_WEBVIEW=${VIX_WITH_UI_LINUX_WEBVIEW} NOTE=${VIX_WITH_NOTE} THREADPOOL=${VIX_WITH_THREADPOOL} KV=${VIX_WITH_KV} AGENT=${VIX_WITH_AGENT} GAME=${VIX_WITH_GAME} GAME_SDL=${VIX_WITH_GAME_SDL} GAME_SDL_OPENGL=${VIX_WITH_GAME_SDL_OPENGL}") +message(STATUS "Flags exported : JSON=${VIX_WITH_JSON} CONVERSION=${VIX_WITH_CONVERSION} VALIDATION=${VIX_WITH_VALIDATION} WEBRPC=${VIX_WITH_WEBRPC} REQUESTS=${VIX_WITH_REQUESTS} REALTIME=${VIX_WITH_REALTIME} CRYPTO=${VIX_WITH_CRYPTO} BOOST_FS=${VIX_WITH_BOOST_FS} OPENSSL=${VIX_WITH_OPENSSL} SQLITE=${VIX_WITH_SQLITE} MYSQL=${VIX_WITH_MYSQL} HAS_ORM=${VIX_HAS_ORM} CACHE=${VIX_WITH_CACHE} P2P=${VIX_WITH_P2P} TEMPLATE=${VIX_WITH_TEMPLATE} UI=${VIX_WITH_UI} UI_WEBVIEW=${VIX_WITH_UI_LINUX_WEBVIEW} NOTE=${VIX_WITH_NOTE} THREADPOOL=${VIX_WITH_THREADPOOL} KV=${VIX_WITH_KV} AGENT=${VIX_WITH_AGENT} GAME=${VIX_WITH_GAME} GAME_SDL=${VIX_WITH_GAME_SDL} GAME_SDL_OPENGL=${VIX_WITH_GAME_SDL_OPENGL}") message(STATUS "------------------------------------------------------") diff --git a/cmake/VixConfig.cmake.in b/cmake/VixConfig.cmake.in index 03a5e0e..4df4fda 100644 --- a/cmake/VixConfig.cmake.in +++ b/cmake/VixConfig.cmake.in @@ -357,6 +357,16 @@ if (VIX_WITH_REQUESTS AND NOT TARGET vix::requests) set(VIX_WITH_REQUESTS OFF) endif() +set(VIX_HAS_REALTIME @VIX_HAS_REALTIME@) +if (VIX_HAS_REALTIME AND NOT TARGET vix::realtime) + set(VIX_HAS_REALTIME OFF) +endif() + +set(VIX_WITH_REALTIME @VIX_WITH_REALTIME@) +if (VIX_WITH_REALTIME AND NOT TARGET vix::realtime) + set(VIX_WITH_REALTIME OFF) +endif() + set(VIX_WITH_CONVERSION @VIX_WITH_CONVERSION@) if (VIX_WITH_CONVERSION AND NOT TARGET vix::conversion) set(VIX_WITH_CONVERSION OFF) diff --git a/modules/cli b/modules/cli index d28fa01..ae6d75a 160000 --- a/modules/cli +++ b/modules/cli @@ -1 +1 @@ -Subproject commit d28fa0114d00f96e3f914d48a85a8397ed90a2bd +Subproject commit ae6d75a99ad52284777a380bf34dbf2afe6f2491 diff --git a/modules/core b/modules/core index a427ab7..663472d 160000 --- a/modules/core +++ b/modules/core @@ -1 +1 @@ -Subproject commit a427ab79f5488d6d025de09b3a2b741753c813a0 +Subproject commit 663472d4ee29090e73d83765e81560a3eeb5da1a diff --git a/modules/engine b/modules/engine index cb193ce..65a6baf 160000 --- a/modules/engine +++ b/modules/engine @@ -1 +1 @@ -Subproject commit cb193ce9538af8e7e2ece6df6ee900c8f0126fd8 +Subproject commit 65a6baf97155061cae31ffec3e9321de332311b2 diff --git a/modules/io b/modules/io index 795a09c..350d564 160000 --- a/modules/io +++ b/modules/io @@ -1 +1 @@ -Subproject commit 795a09c2c4ef1a554e6cc37993b5446ef82e4978 +Subproject commit 350d56414e40bb2b748fa28c2f18f1305cfd9e5e diff --git a/modules/json b/modules/json index a4d071b..8b09521 160000 --- a/modules/json +++ b/modules/json @@ -1 +1 @@ -Subproject commit a4d071b98c04ec16589d7e6dd4862f4fbc3d257e +Subproject commit 8b095215a8ab357acb42284e04f8c2ff39bbaba4 diff --git a/modules/realtime b/modules/realtime new file mode 160000 index 0000000..7585ac0 --- /dev/null +++ b/modules/realtime @@ -0,0 +1 @@ +Subproject commit 7585ac032753587978b3973ef7ce82c3c578e33c diff --git a/modules/threadpool b/modules/threadpool index 112bcb2..aa511f1 160000 --- a/modules/threadpool +++ b/modules/threadpool @@ -1 +1 @@ -Subproject commit 112bcb2f1522a82ae35aa19b4c772ee02a4f366f +Subproject commit aa511f1d11e1ee6f983535c08fe9222bbc4d2e82 diff --git a/modules/websocket b/modules/websocket index e487146..6b9b04d 160000 --- a/modules/websocket +++ b/modules/websocket @@ -1 +1 @@ -Subproject commit e48714643157c0e50be461ea1c712bced5c13fb7 +Subproject commit 6b9b04de017937919aa5511f1f8b96fbc34a7ac6 diff --git a/vix/all.hpp b/vix/all.hpp index 37d363d..7ff174b 100644 --- a/vix/all.hpp +++ b/vix/all.hpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include diff --git a/vix/realtime.hpp b/vix/realtime.hpp new file mode 100644 index 0000000..82c22d6 --- /dev/null +++ b/vix/realtime.hpp @@ -0,0 +1,31 @@ +/** + * + * @file realtime.hpp + * @author Gaspard Kirira + * + * @brief Public entry point for the Vix Realtime module. + * + * Provides stateful realtime rooms, commands, events, snapshots, + * replay, logical sessions, presence, and optional transports/stores. + * + * Usage: + * #include + * + * For advanced usage, include specific components from: + * + * + * Copyright 2026, Gaspard Kirira. + * All rights reserved. + * https://github.com/vixcpp/vix + * + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Vix.cpp + */ +#ifndef VIX_REALTIME_HPP +#define VIX_REALTIME_HPP + +#include + +#endif // VIX_REALTIME_HPP