Skip to content

Commit 5a4c5b3

Browse files
committed
Templatize Websocket on read-buffer type; add slick stream-buffer backends (v3.0.0)
Replace the monolithic session-based implementation with a header-only template core (detail/websocket_impl.hpp) that accepts any Beast-compatible read buffer. Explicitly instantiate flat_buffer (default), slick::dynamic_buffer<stream_buffer>, and slick::dynamic_buffer<producer_buffer> backends for lock-free zero-copy streaming. Shared-backend reconnect reuses the same ring across open() cycles for slick buffer types. Fix URL parsing for bare host:port forms and eliminate the tight-loop send regression that fired before the socket reached CONNECTED. Add slick_buffer_tests, three new buffer-specific examples, slick-stream-buffer/-multiplexer dependencies, and .editorconfig.
1 parent 64e1be3 commit 5a4c5b3

21 files changed

Lines changed: 2486 additions & 1722 deletions

.editorconfig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
root = true
2+
3+
[*]
4+
end_of_line = lf
5+
insert_final_newline = true
6+
7+
# 4-space indentation for all files
8+
[*.{py,js,ts,json}]
9+
indent_style = space
10+
indent_size = 4
11+
12+
# 2-space indentation for markup
13+
[*.{html,css,md,yml,yaml}]
14+
indent_style = space
15+
indent_size = 2
16+
17+
# Trims trailing whitespace for all files except Makefiles
18+
[*.{cs,java,cpp,h}]
19+
trim_trailing_whitespace = true

CHANGELOG.md

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,53 @@
1-
# [v3.0.0] - 2026-06-12
1+
# [v3.0.0] - 2026-06-16
22

33
## Added
4-
- Shared-buffer WebSocket read path built on `slick::dynamic_buffer` / `slick::stream_buffer`.
5-
- Configurable WebSocket buffer sizing and optional shared-memory naming via the `Websocket` constructor.
6-
- `Websocket::drain_data()` and `Websocket::initial_reading_index()` for draining published messages from a caller-owned thread.
7-
- New example `websocket_reading_from_different_thread.cpp` showing service-thread callbacks plus caller-thread draining.
8-
- Additional same-object reconnect tests covering deferred reconnect while disconnecting, rapid reconnect buffer handoff, and cancellation of a pending deferred open.
4+
- `Websocket<BufferT>` is now a class template parameterized on the read-buffer
5+
type. Default is `boost::beast::flat_buffer`, and the library explicitly
6+
instantiates the supported slick stream-buffer backends.
7+
- New constructor overload accepting a `std::shared_ptr<BackendT>`:
8+
```cpp
9+
Websocket<slick::dynamic_buffer<slick::stream_buffer>> ws(url, callbacks..., sb);
10+
Websocket<slick::dynamic_buffer<producer_buffer>> ws(url, callbacks..., pb);
11+
```
12+
This allows `slick::dynamic_buffer<stream_buffer>` and
13+
`slick::dynamic_buffer<stream_buffer_multiplexer::producer_buffer>` as read-buffer
14+
backends for lock-free zero-copy streaming while keeping application code on the
15+
public `<slick/net/websocket.hpp>` include.
16+
- Shared-backend reconnect: for slick dynamic-buffer types the same backend is
17+
reused across `open()` cycles — records from all sessions accumulate in the ring.
18+
For `flat_buffer` each reconnect starts a fresh buffer.
19+
- `slick_buffer_tests` — new test binary exercising the `stream_buffer` and
20+
`producer_buffer` paths end-to-end (construction, data round-trip, reconnect).
21+
- Additional same-object reconnect tests covering deferred reconnect while
22+
disconnecting, rapid reconnect buffer handoff, and cancellation of a pending
23+
deferred open.
24+
- Custom buffer types can opt into template definitions by defining
25+
`SLICK_NET_WEBSOCKET_HEADER_ONLY` before including `<slick/net/websocket.hpp>`.
26+
- `websocket_with_custom_buffer_example` demonstrates the custom-buffer opt-in path.
927
1028
## Changed
1129
- **BREAKING:** `Websocket::reset_callbacks()` was replaced by `Websocket::detach()`.
12-
- `Websocket::open()` now defers a same-object reconnect until the previous session's read loop releases the shared read buffer.
13-
- `Websocket::close()` can now cancel a pending deferred `open()` before the new session starts.
14-
- `Websocket::send()` and `Websocket::send_binary_data()` now accept an optional `suppress_log` flag.
15-
- The packaged CMake dependency wiring now finds or fetches `slick-dynamic-buffer` for both source builds and installed-package consumers.
16-
- GoogleTest discovery now runs in `PRE_TEST` mode to avoid slow first-launch failures during the build step.
30+
- `Websocket::open()` now defers a same-object reconnect until the previous
31+
session's read loop releases the shared backend (shared-buffer path only;
32+
`flat_buffer` starts immediately).
33+
- `Websocket::close()` can now cancel a pending deferred `open()` before the new
34+
session starts.
35+
- `Websocket::send()` and `Websocket::send_binary_data()` now accept an optional
36+
`suppress_log` flag.
37+
- GoogleTest discovery now runs in `PRE_TEST` mode to avoid slow first-launch
38+
failures during the build step.
1739
1840
## Fixed
19-
- Rapid same-object reconnect no longer allows overlapping producers to touch the shared read buffer.
20-
- Detached or superseded WebSocket sessions now suppress stale error and disconnect callbacks during teardown.
21-
- Partial read data from an interrupted session is discarded before the next session starts reading on the shared buffer.
41+
- Rapid same-object reconnect no longer allows overlapping producers to touch the
42+
shared read buffer.
43+
- Detached or superseded WebSocket sessions now suppress stale error and disconnect
44+
callbacks during teardown.
45+
- Partial read data from an interrupted session is discarded before the next session
46+
starts reading on the shared buffer.
47+
- Queued sends made while a connection is still handshaking no longer repost
48+
writes in a tight loop before the socket reaches `CONNECTED`.
49+
- URL parsing now handles normal short `host:port` forms such as `abc:9000`
50+
instead of treating the colon as part of the host.
2251
2352
# [v2.1.0] - 2026-06-04
2453

CMakeLists.txt

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
cmake_minimum_required(VERSION 3.20)
22

3-
option(LINK_STATICALLY "Link statically" OFF)
3+
option(LINK_STATICALLY "Link Boost and OpenSSL statically" OFF)
4+
option(ENABLE_ASAN "Enable AddressSanitizer" OFF)
5+
option(BUILD_SLICK_NET_TESTS "Build tests" ${PROJECT_IS_TOP_LEVEL})
6+
option(BUILD_SLICK_NET_EXAMPLES "Build examples" ${PROJECT_IS_TOP_LEVEL})
7+
48
if (LINK_STATICALLY)
59
if (MSVC)
610
set(VCPKG_TARGET_TRIPLET x64-windows-static)
@@ -37,7 +41,7 @@ if (slick-shm_FOUND)
3741
message(STATUS "slick-shm: ${slick-shm_VERSION}")
3842
endif()
3943

40-
find_package(slick-queue 1.2.2 CONFIG QUIET)
44+
find_package(slick-queue 1.5.0 CONFIG QUIET)
4145
if (NOT slick-queue_FOUND)
4246
message(STATUS "Fetching slick-queue...")
4347
include(FetchContent)
@@ -46,27 +50,56 @@ if (NOT slick-queue_FOUND)
4650
FetchContent_Declare(
4751
slick-queue
4852
GIT_REPOSITORY https://github.com/SlickQuant/slick-queue.git
49-
GIT_TAG v1.4.1 # See https://github.com/SlickQuant/slick-queue/releases for latest version
53+
GIT_TAG v1.5.0 # See https://github.com/SlickQuant/slick-queue/releases for latest version
5054
)
5155
FetchContent_MakeAvailable(slick-queue)
5256
else()
53-
message(STATUS "slick-queue: ${slick-queue_VERSION}")
57+
message(STATUS "Found slick-queue: ${slick-queue_VERSION}")
58+
endif()
59+
60+
find_package(slick-stream-buffer 1.0.5 CONFIG QUIET)
61+
if (NOT slick-stream-buffer_FOUND)
62+
message(STATUS "Fetching slick-stream-buffer...")
63+
include(FetchContent)
64+
set(BUILD_SLICK_STREAM_BUFFER_TESTS OFF CACHE BOOL "" FORCE)
65+
FetchContent_Declare(
66+
slick-stream-buffer
67+
GIT_REPOSITORY https://github.com/SlickQuant/slick-stream-buffer.git
68+
GIT_TAG v1.0.5
69+
)
70+
FetchContent_MakeAvailable(slick-stream-buffer)
71+
else()
72+
message(STATUS "Found slick-stream-buffer: ${slick-stream-buffer_VERSION}")
5473
endif()
5574

56-
find_package(slick-dynamic-buffer CONFIG QUIET)
75+
find_package(slick-stream-buffer-multiplexer 1.0.1 CONFIG QUIET)
76+
if (NOT slick-stream-buffer-multiplexer_FOUND)
77+
message(STATUS "Fetching slick-stream-buffer-multiplexer...")
78+
include(FetchContent)
79+
set(BUILD_SLICK_STREAM_BUFFER_MULTIPLEXER_TESTS OFF CACHE BOOL "" FORCE)
80+
FetchContent_Declare(
81+
slick-stream-buffer-multiplexer
82+
GIT_REPOSITORY https://github.com/SlickQuant/slick-stream-buffer-multiplexer.git
83+
GIT_TAG v1.0.1
84+
)
85+
FetchContent_MakeAvailable(slick-stream-buffer-multiplexer)
86+
else()
87+
message(STATUS "Found slick-stream-buffer-multiplexer: ${slick-stream-buffer-multiplexer_VERSION}")
88+
endif()
89+
90+
find_package(slick-dynamic-buffer 1.0.1 CONFIG QUIET)
5791
if (NOT slick-dynamic-buffer_FOUND)
5892
message(STATUS "Fetching slick-dynamic-buffer...")
5993
include(FetchContent)
60-
# Disable tests for slick-dynamic-buffer
6194
set(BUILD_SLICK_DYNAMIC_BUFFER_TESTS OFF CACHE BOOL "" FORCE)
6295
FetchContent_Declare(
6396
slick-dynamic-buffer
6497
GIT_REPOSITORY https://github.com/SlickQuant/slick-dynamic-buffer.git
65-
GIT_TAG v1.0.0 # See https://github.com/SlickQuant/slick-dynamic-buffer/releases for latest version
98+
GIT_TAG v1.0.1
6699
)
67100
FetchContent_MakeAvailable(slick-dynamic-buffer)
68101
else()
69-
message(STATUS "slick-dynamic-buffer: ${slick-dynamic-buffer_VERSION}")
102+
message(STATUS "Found slick-dynamic-buffer: ${slick-dynamic-buffer_VERSION}")
70103
endif()
71104

72105
message(STATUS "OpenSSL: ${OPENSSL_INCLUDE_DIR}")
@@ -76,7 +109,8 @@ add_library(slick-net STATIC
76109
src/http.cpp
77110
src/http_stream.cpp
78111
src/websocket.cpp
79-
src/websocket_session.cpp
112+
src/websocket_stream_buffer.cpp
113+
src/websocket_stream_buffer_multiplexer.cpp
80114
src/logging.cpp
81115
)
82116
add_library(slick::net ALIAS slick-net)
@@ -88,7 +122,17 @@ target_include_directories(slick-net PUBLIC
88122
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
89123
$<INSTALL_INTERFACE:include>
90124
)
91-
target_link_libraries(slick-net PUBLIC slick::queue slick::dynamic_buffer Boost::asio Boost::beast Boost::context OpenSSL::SSL OpenSSL::Crypto)
125+
target_link_libraries(slick-net PUBLIC
126+
slick::queue
127+
slick::stream_buffer
128+
slick::stream_buffer_multiplexer
129+
slick::dynamic_buffer
130+
Boost::asio
131+
Boost::beast
132+
Boost::context
133+
OpenSSL::SSL
134+
OpenSSL::Crypto
135+
)
92136
set_target_properties(slick-net PROPERTIES EXPORT_NAME net)
93137

94138

@@ -109,7 +153,6 @@ else()
109153
endif()
110154
endif()
111155

112-
option(ENABLE_ASAN "Enable AddressSanitizer" OFF)
113156
if(ENABLE_ASAN)
114157
if(MSVC)
115158
# MSVC AddressSanitizer (requires Visual Studio 2022 17.7+)
@@ -133,7 +176,6 @@ if(ENABLE_ASAN)
133176
endif()
134177
endif()
135178

136-
option(BUILD_SLICK_NET_TESTS "Build tests" ${PROJECT_IS_TOP_LEVEL})
137179
if (BUILD_SLICK_NET_TESTS)
138180
message(STATUS "Building slick-net tests")
139181
enable_testing()
@@ -142,7 +184,6 @@ else()
142184
message(STATUS "Skipping slick-net tests")
143185
endif()
144186

145-
option(BUILD_SLICK_NET_EXAMPLES "Build examples" ${PROJECT_IS_TOP_LEVEL})
146187
if(BUILD_SLICK_NET_EXAMPLES)
147188
message(STATUS "Building slick::net examples")
148189
add_subdirectory(examples)

0 commit comments

Comments
 (0)