Skip to content

Commit 85d9e26

Browse files
committed
feat: release v1.0.0 — shared mux, cross-process IPC, examples
Upgrade slick-net to v3.0.0 and overhaul the WebSocket data path: - Replace SlickQueue<char> with slick::stream_buffer_multiplexer for inter-thread delivery — zero-copy, lock-free, multiplexed across multiple WebSocketClient instances - Add producer_offset to both WebSocketClient constructors so multiple clients share one mux with non-overlapping producer ID ranges - Add second WebSocketClient constructor accepting an external mux - Add shm name params (md_read_buffer_shm_name, user_read_buffer_shm_name) for named shared-memory producer buffers enabling cross-process IPC - Add ProducerType enum (MD_DATA, USER_DATA, MD_CTRL, USER_CTRL) for typed producer-buffer routing; remove MessageType::MARKET_DATA/USER_DATA - Add buffer-sizing params and accessors (marketDataUrl, userDataUrl, streamBufferMultiplexer) to WebSocketClient Add five runnable examples (BUILD_COINBASE_ADVANCED_EXAMPLES): market_data_ws_callbacks, market_data_user_thread_callbacks, multi_websockets_ws_callbacks, multi_websockets_user_thread_callbacks, multi_websockets_ws_callbacks_reader (cross-process reader — attaches to the named-shm mux written by multi_websockets_ws_callbacks) BREAKING CHANGES: - UserThreadWebsocketCallbacks ctor: queue_size param removed - WebSocketClient::logData(): data_queue_size param removed - WebSocketChannel::__COUNT__ renamed to _CHANNEL_COUNT_ - slick-net v3.0.0 required (bundles slick-stream-buffer-multiplexer and slick-dynamic-buffer)
1 parent f96d2b8 commit 85d9e26

16 files changed

Lines changed: 3760 additions & 2310 deletions

CHANGELOG.md

Lines changed: 200 additions & 175 deletions
Large diffs are not rendered by default.

CMakeLists.txt

Lines changed: 136 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,136 @@
1-
cmake_minimum_required(VERSION 3.20)
2-
3-
set(CMAKE_CXX_STANDARD 20)
4-
5-
project(coinbase-advanced-cpp
6-
VERSION 0.3.0
7-
LANGUAGES CXX)
8-
9-
if (CMAKE_BUILD_TYPE MATCHES Debug)
10-
add_definitions(-DDEBUG)
11-
endif()
12-
13-
if (CMAKE_BUILD_TYPE MATCHES Release)
14-
add_definitions(-DNDEBUG)
15-
endif()
16-
17-
find_package(nlohmann_json CONFIG REQUIRED)
18-
find_package(OpenSSL CONFIG REQUIRED)
19-
find_package(jwt-cpp CONFIG REQUIRED)
20-
21-
find_package(slick-net 2.1.0 CONFIG QUIET)
22-
if (NOT slick-net_FOUND)
23-
message(STATUS "fetching slick-net...")
24-
include(FetchContent)
25-
FetchContent_Declare(
26-
slick-net
27-
GIT_REPOSITORY https://github.com/SlickQuant/slick-net.git
28-
GIT_TAG v2.1.0
29-
)
30-
FetchContent_MakeAvailable(slick-net)
31-
else()
32-
message(STATUS "Found slick-net: ${slick-net_VERSION}")
33-
endif()
34-
35-
add_library(coinbase-advanced-cpp STATIC
36-
src/auth.cpp
37-
src/rest.cpp
38-
src/rest_awaitable.cpp
39-
src/websocket.cpp
40-
src/utils.cpp
41-
src/logging.cpp
42-
)
43-
add_library(slick::coinbase-advanced-cpp ALIAS coinbase-advanced-cpp)
44-
target_include_directories(coinbase-advanced-cpp PUBLIC
45-
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
46-
$<INSTALL_INTERFACE:include>
47-
)
48-
target_link_libraries(coinbase-advanced-cpp PUBLIC slick::net jwt-cpp::jwt-cpp)
49-
50-
# PRIVATE precompiled headers for faster static library compilation
51-
target_precompile_headers(coinbase-advanced-cpp PRIVATE
52-
<nlohmann/json.hpp>
53-
<string>
54-
<vector>
55-
<memory>
56-
<coroutine>
57-
)
58-
59-
if (MSVC)
60-
add_definitions(-D_WIN32_WINNT=0x0A00)
61-
set(CMAKE_SUPPRESS_REGENERATION true) # supress zero_check
62-
set_target_properties(coinbase-advanced-cpp PROPERTIES LINK_INCREMENTAL ON)
63-
target_compile_options(coinbase-advanced-cpp PRIVATE
64-
/MP
65-
/FS
66-
/bigobj
67-
/wd4101
68-
/W4
69-
$<$<CONFIG:Release>:/O2>
70-
$<$<CONFIG:Release>:/GL> # Whole program optimization
71-
)
72-
# Faster linking
73-
target_link_options(coinbase-advanced-cpp PRIVATE
74-
$<$<CONFIG:Debug>:/DEBUG:FASTLINK>
75-
)
76-
else()
77-
target_compile_options(coinbase-advanced-cpp PRIVATE
78-
-Wall -Wextra -Wpedantic
79-
$<$<CONFIG:Release>:-O3>
80-
)
81-
endif()
82-
83-
set(BUILD_COINBASE_ADVANCED_TESTS_DEFAULT ON)
84-
if (NOT CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
85-
set(BUILD_COINBASE_ADVANCED_TESTS_DEFAULT OFF)
86-
endif()
87-
option(BUILD_COINBASE_ADVANCED_TESTS "Build tests" ${BUILD_COINBASE_ADVANCED_TESTS_DEFAULT})
88-
if (BUILD_COINBASE_ADVANCED_TESTS)
89-
message(STATUS "Building coinbase-advanced-cpp tests")
90-
enable_testing()
91-
add_subdirectory(tests)
92-
else()
93-
message(STATUS "Skipping coinbase-advanced-cpp tests")
94-
endif()
95-
96-
# Installation rules
97-
install(DIRECTORY include/ DESTINATION include)
98-
99-
# Install CMake package configuration files for vcpkg
100-
install(TARGETS coinbase-advanced-cpp EXPORT coinbase-advanced-cppTargets)
101-
102-
install(EXPORT coinbase-advanced-cppTargets
103-
FILE coinbase-advanced-cppTargets.cmake
104-
NAMESPACE slick::
105-
DESTINATION lib/cmake/coinbase-advanced-cpp
106-
)
107-
108-
include(CMakePackageConfigHelpers)
109-
110-
# Generate the config file
111-
configure_package_config_file(
112-
${CMAKE_CURRENT_SOURCE_DIR}/cmake/coinbase-advanced-cppConfig.cmake.in
113-
${CMAKE_CURRENT_BINARY_DIR}/coinbase-advanced-cppConfig.cmake
114-
INSTALL_DESTINATION lib/cmake/coinbase-advanced-cpp
115-
)
116-
117-
# Generate version file
118-
write_basic_package_version_file(
119-
${CMAKE_CURRENT_BINARY_DIR}/coinbase-advanced-cppConfigVersion.cmake
120-
VERSION ${PROJECT_VERSION}
121-
COMPATIBILITY SameMajorVersion
122-
)
123-
124-
# Install config files
125-
install(FILES
126-
${CMAKE_CURRENT_BINARY_DIR}/coinbase-advanced-cppConfig.cmake
127-
${CMAKE_CURRENT_BINARY_DIR}/coinbase-advanced-cppConfigVersion.cmake
128-
DESTINATION lib/cmake/coinbase-advanced-cpp
129-
)
130-
131-
message(STATUS "${PROJECT_NAME}: ${PROJECT_VERSION}")
1+
cmake_minimum_required(VERSION 3.21)
2+
3+
set(CMAKE_CXX_STANDARD 20)
4+
5+
project(coinbase-advanced-cpp
6+
VERSION 1.0.0
7+
LANGUAGES CXX)
8+
9+
option(BUILD_COINBASE_ADVANCED_TESTS "Build coinbase advanced tests" ${PROJECT_IS_TOP_LEVEL})
10+
option(BUILD_COINBASE_ADVANCED_EXAMPLES "Build coinbas advanced examples" ${PROJECT_IS_TOP_LEVEL})
11+
12+
if (CMAKE_BUILD_TYPE MATCHES Debug)
13+
add_definitions(-DDEBUG)
14+
endif()
15+
16+
if (CMAKE_BUILD_TYPE MATCHES Release)
17+
add_definitions(-DNDEBUG)
18+
endif()
19+
20+
find_package(nlohmann_json CONFIG REQUIRED)
21+
find_package(OpenSSL CONFIG REQUIRED)
22+
find_package(jwt-cpp CONFIG REQUIRED)
23+
24+
find_package(slick-net 3.0.0 CONFIG QUIET)
25+
if (NOT slick-net_FOUND)
26+
message(STATUS "fetching slick-net...")
27+
include(FetchContent)
28+
FetchContent_Declare(
29+
slick-net
30+
GIT_REPOSITORY https://github.com/SlickQuant/slick-net.git
31+
GIT_TAG v3.0.0
32+
)
33+
FetchContent_MakeAvailable(slick-net)
34+
else()
35+
message(STATUS "Found slick-net ${slick-net_VERSION}: ${slick-net_DIR}")
36+
endif()
37+
38+
add_library(coinbase-advanced-cpp STATIC
39+
src/auth.cpp
40+
src/rest.cpp
41+
src/rest_awaitable.cpp
42+
src/websocket.cpp
43+
src/utils.cpp
44+
src/logging.cpp
45+
)
46+
add_library(slick::coinbase-advanced-cpp ALIAS coinbase-advanced-cpp)
47+
target_include_directories(coinbase-advanced-cpp PUBLIC
48+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
49+
$<INSTALL_INTERFACE:include>
50+
)
51+
target_link_libraries(coinbase-advanced-cpp PUBLIC slick::net slick::stream_buffer_multiplexer jwt-cpp::jwt-cpp)
52+
53+
# PRIVATE precompiled headers for faster static library compilation
54+
target_precompile_headers(coinbase-advanced-cpp PRIVATE
55+
<nlohmann/json.hpp>
56+
<string>
57+
<vector>
58+
<memory>
59+
<coroutine>
60+
)
61+
62+
if (MSVC)
63+
add_definitions(-D_WIN32_WINNT=0x0A00)
64+
set(CMAKE_SUPPRESS_REGENERATION true) # supress zero_check
65+
set_target_properties(coinbase-advanced-cpp PROPERTIES LINK_INCREMENTAL ON)
66+
target_compile_options(coinbase-advanced-cpp PRIVATE
67+
/MP
68+
/FS
69+
/bigobj
70+
/wd4101
71+
/W4
72+
$<$<CONFIG:Release>:/O2>
73+
$<$<CONFIG:Release>:/GL> # Whole program optimization
74+
)
75+
# Faster linking
76+
target_link_options(coinbase-advanced-cpp PRIVATE
77+
$<$<CONFIG:Debug>:/DEBUG:FASTLINK>
78+
)
79+
else()
80+
target_compile_options(coinbase-advanced-cpp PRIVATE
81+
-Wall -Wextra -Wpedantic
82+
$<$<CONFIG:Release>:-O3>
83+
)
84+
endif()
85+
86+
if (BUILD_COINBASE_ADVANCED_TESTS)
87+
message(STATUS "Building coinbase-advanced-cpp tests")
88+
enable_testing()
89+
add_subdirectory(tests)
90+
else()
91+
message(STATUS "Skipping coinbase-advanced-cpp tests")
92+
endif()
93+
94+
if (BUILD_COINBASE_ADVANCED_EXAMPLES)
95+
message(STATUS "Building coinbase-advanced-cpp examples")
96+
add_subdirectory(examples)
97+
else()
98+
message(STATUS "Skipping coinbase-advanced-cpp examples")
99+
endif()
100+
101+
# Installation rules
102+
install(DIRECTORY include/ DESTINATION include)
103+
104+
# Install CMake package configuration files for vcpkg
105+
install(TARGETS coinbase-advanced-cpp EXPORT coinbase-advanced-cppTargets)
106+
107+
install(EXPORT coinbase-advanced-cppTargets
108+
FILE coinbase-advanced-cppTargets.cmake
109+
NAMESPACE slick::
110+
DESTINATION lib/cmake/coinbase-advanced-cpp
111+
)
112+
113+
include(CMakePackageConfigHelpers)
114+
115+
# Generate the config file
116+
configure_package_config_file(
117+
${CMAKE_CURRENT_SOURCE_DIR}/cmake/coinbase-advanced-cppConfig.cmake.in
118+
${CMAKE_CURRENT_BINARY_DIR}/coinbase-advanced-cppConfig.cmake
119+
INSTALL_DESTINATION lib/cmake/coinbase-advanced-cpp
120+
)
121+
122+
# Generate version file
123+
write_basic_package_version_file(
124+
${CMAKE_CURRENT_BINARY_DIR}/coinbase-advanced-cppConfigVersion.cmake
125+
VERSION ${PROJECT_VERSION}
126+
COMPATIBILITY SameMajorVersion
127+
)
128+
129+
# Install config files
130+
install(FILES
131+
${CMAKE_CURRENT_BINARY_DIR}/coinbase-advanced-cppConfig.cmake
132+
${CMAKE_CURRENT_BINARY_DIR}/coinbase-advanced-cppConfigVersion.cmake
133+
DESTINATION lib/cmake/coinbase-advanced-cpp
134+
)
135+
136+
message(STATUS "${PROJECT_NAME}: ${PROJECT_VERSION}")

README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ A modern C++ SDK for interacting with the Coinbase Advanced API, providing both
1515
- Connection lifecycle callbacks for connect/disconnect events
1616
- Per-client sequence number tracking for multiple concurrent connections
1717
- Explicit shutdown control with `stop()` method
18+
- **Shared Multiplexer**: Multiple `WebSocketClient` instances share one `slick::stream_buffer_multiplexer` — unified lock-free ring-buffer allocation and a single fan-in queue across all symbols
19+
- **Cross-process IPC**: Producer buffers and the fan-in queue can be placed in named shared memory; a second process can attach and read the same raw JSON stream without an extra network connection
1820
- **Comprehensive Order Types**: Support for market, limit, stop limit, bracket, and TWAP orders
1921
- **Type Safety**: Full C++ type definitions for all API responses with JSON serialization/deserialization
2022
- **Modern C++**: Uses C++20 features, RAII, smart pointers, and modern C++ best practices
@@ -271,6 +273,48 @@ client.stop();
271273
- **`WebsocketCallbacks`**: Immediate processing on WebSocket I/O thread. Simple but can block WebSocket operations if callbacks are slow.
272274
- **`UserThreadWebsocketCallbacks`**: Deferred processing on your thread. Better performance and control, but requires calling `processData()` regularly. Uses lock-free queues for efficient data transfer between threads.
273275

276+
##### Multiple symbols with a shared multiplexer
277+
278+
Multiple `WebSocketClient` instances can share one `slick::stream_buffer_multiplexer`. Each client is assigned a non-overlapping range of producer IDs via `producer_offset`. A single `processData()` drains messages from all symbols in arrival order.
279+
280+
```cpp
281+
slick::stream_buffer_multiplexer mux(1u << 17);
282+
283+
// BTC uses producer IDs 0–3, ETH uses 4–7
284+
coinbase::WebSocketClient ws_btc(&callbacks, mux, MD_URL, "", 0);
285+
coinbase::WebSocketClient ws_eth(&callbacks, mux, MD_URL, "",
286+
coinbase::ProducerType::_PRODUCER_TYPE_COUNT_);
287+
288+
while (running) {
289+
callbacks.processData(200); // drains both symbols
290+
}
291+
```
292+
293+
##### Cross-process market data logging
294+
295+
Passing `md_read_buffer_shm_name` to the `WebSocketClient` constructor places the MD_DATA producer buffer in named shared memory. Combining this with a shared-memory fan-in queue lets a second process attach and read the same raw JSON stream — no extra network connection required.
296+
297+
```cpp
298+
// Process A — producer
299+
slick::stream_buffer_multiplexer mux(1u << 17, "my_mux_queue");
300+
coinbase::WebSocketClient ws(&callbacks, mux, MD_URL, "", 0,
301+
1u << 26, 1u << 16, "my_btc_md_buf");
302+
303+
// Process B — reader (no WebSocket, no coinbase parsing)
304+
slick::stream_buffer_multiplexer reader_mux("my_mux_queue");
305+
reader_mux.add_producer(0 /*MD_DATA producer_id*/, "my_btc_md_buf");
306+
307+
uint64_t cursor = reader_mux.initial_reading_index();
308+
while (running) {
309+
if (auto rec = reader_mux.read(cursor)) {
310+
// rec.data points to raw JSON bytes; rec.length is the frame size
311+
std::cout.write(reinterpret_cast<const char*>(rec.data), rec.length);
312+
}
313+
}
314+
```
315+
316+
See `examples/multi_websockets_ws_callbacks.cpp` (producer) and `examples/multi_websockets_ws_callbacks_reader.cpp` (cross-process reader) for a complete two-symbol demo.
317+
274318
## API Endpoints
275319

276320
### REST API
@@ -314,6 +358,20 @@ The SDK supports multiple order types:
314358

315359
The SDK handles JWT authentication automatically using the `coinbase::generate_coinbase_jwt` function. You need to provide your API key and secret.
316360

361+
## Examples
362+
363+
The `examples/` directory contains five self-contained programs. Build them with `-DBUILD_COINBASE_ADVANCED_EXAMPLES=ON`:
364+
365+
| Executable | Description |
366+
|---|---|
367+
| `market_data_ws_callbacks` | Single-client market data with `WebsocketCallbacks` (I/O thread) |
368+
| `market_data_user_thread_callbacks` | Single-client market data with `UserThreadWebsocketCallbacks`; also queries REST endpoints |
369+
| `multi_websockets_ws_callbacks` | BTC-USD + ETH-USD, one `WebSocketClient` each, shared mux; callbacks on I/O thread; mux and MD buffers in **named shared memory** |
370+
| `multi_websockets_user_thread_callbacks` | BTC-USD + ETH-USD, shared mux, single `processData()` loop; per-symbol order books printed every 5 s |
371+
| `multi_websockets_ws_callbacks_reader` | Cross-process reader — attaches to the shared memory written by `multi_websockets_ws_callbacks` and logs raw JSON; start the producer first |
372+
373+
All examples require no API credentials for public market-data channels (TICKER, LEVEL2, MARKET_TRADES).
374+
317375
## Testing
318376

319377
The SDK includes comprehensive unit tests using Google Test. To run tests:
Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
1-
@PACKAGE_INIT@
2-
3-
include(CMakeFindDependencyMacro)
4-
5-
find_dependency(nlohmann_json CONFIG REQUIRED)
6-
find_dependency(OpenSSL CONFIG REQUIRED)
7-
find_dependency(jwt-cpp CONFIG REQUIRED)
8-
find_dependency(slick-net 1.2.4 CONFIG QUIET)
9-
10-
if(NOT slick-net_FOUND)
11-
message(STATUS "Fetching slick-net...")
12-
include(FetchContent)
13-
set(BUILD_SLICK_NET_EXAMPLES OFF CACHE BOOL "" FORCE)
14-
set(BUILD_SLICK_NET_TESTS OFF CACHE BOOL "" FORCE)
15-
FetchContent_Declare(
16-
slick-net
17-
GIT_REPOSITORY https://github.com/SlickQuant/slick-net.git
18-
GIT_TAG v1.2.4
19-
)
20-
FetchContent_MakeAvailable(slick-net)
21-
endif()
22-
23-
include("${CMAKE_CURRENT_LIST_DIR}/coinbase-advanced-cppTargets.cmake")
24-
25-
check_required_components(coinbase-advanced-cpp)
1+
@PACKAGE_INIT@
2+
3+
include(CMakeFindDependencyMacro)
4+
5+
find_dependency(nlohmann_json CONFIG REQUIRED)
6+
find_dependency(OpenSSL CONFIG REQUIRED)
7+
find_dependency(jwt-cpp CONFIG REQUIRED)
8+
9+
find_dependency(slick-net 3.0.0 CONFIG QUIET)
10+
if(NOT slick-net_FOUND)
11+
message(STATUS "Fetching slick-net...")
12+
include(FetchContent)
13+
set(BUILD_SLICK_NET_EXAMPLES OFF CACHE BOOL "" FORCE)
14+
set(BUILD_SLICK_NET_TESTS OFF CACHE BOOL "" FORCE)
15+
FetchContent_Declare(
16+
slick-net
17+
GIT_REPOSITORY https://github.com/SlickQuant/slick-net.git
18+
GIT_TAG v3.0.0
19+
)
20+
FetchContent_MakeAvailable(slick-net)
21+
endif()
22+
23+
include("${CMAKE_CURRENT_LIST_DIR}/coinbase-advanced-cppTargets.cmake")
24+
25+
check_required_components(coinbase-advanced-cpp)

0 commit comments

Comments
 (0)