hgraph-web 0.8.20__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. hgraph_web-0.8.20/.gitignore +7 -0
  2. hgraph_web-0.8.20/CHANGELOG.md +37 -0
  3. hgraph_web-0.8.20/CMakeLists.txt +396 -0
  4. hgraph_web-0.8.20/LICENSE +21 -0
  5. hgraph_web-0.8.20/PKG-INFO +100 -0
  6. hgraph_web-0.8.20/README.md +86 -0
  7. hgraph_web-0.8.20/cmake/hgraph-webConfig.cmake.in +38 -0
  8. hgraph_web-0.8.20/include/hgraph/web/export.h +16 -0
  9. hgraph_web-0.8.20/include/hgraph/web/service.h +146 -0
  10. hgraph_web-0.8.20/include/hgraph/web/testing/fake_transport.h +136 -0
  11. hgraph_web-0.8.20/include/hgraph/web/types.h +482 -0
  12. hgraph_web-0.8.20/include/hgraph/web/value_builders.h +260 -0
  13. hgraph_web-0.8.20/pyproject.toml +47 -0
  14. hgraph_web-0.8.20/python/hgraph_web/__init__.py +841 -0
  15. hgraph_web-0.8.20/python/hgraph_web/_endpoints.py +433 -0
  16. hgraph_web-0.8.20/python/hgraph_web/compat.py +1251 -0
  17. hgraph_web-0.8.20/python/tests/_loopback_harness.py +66 -0
  18. hgraph_web-0.8.20/python/tests/test_api.py +481 -0
  19. hgraph_web-0.8.20/python/tests/test_compat.py +548 -0
  20. hgraph_web-0.8.20/python/tests/test_endpoints.py +381 -0
  21. hgraph_web-0.8.20/python/tests/test_packaging.py +182 -0
  22. hgraph_web-0.8.20/python/tests/test_runtime.py +244 -0
  23. hgraph_web-0.8.20/src/asio_server.cpp +4945 -0
  24. hgraph_web-0.8.20/src/curl_client.cpp +2483 -0
  25. hgraph_web-0.8.20/src/detail/h2_engine.h +147 -0
  26. hgraph_web-0.8.20/src/detail/route_table.cpp +383 -0
  27. hgraph_web-0.8.20/src/detail/route_table.h +111 -0
  28. hgraph_web-0.8.20/src/detail/service_transport.h +1189 -0
  29. hgraph_web-0.8.20/src/detail/stream_model.h +121 -0
  30. hgraph_web-0.8.20/src/detail/web_bindings.h +186 -0
  31. hgraph_web-0.8.20/src/nghttp2_session.cpp +457 -0
  32. hgraph_web-0.8.20/src/python_module.cpp +171 -0
  33. hgraph_web-0.8.20/src/service.cpp +75 -0
  34. hgraph_web-0.8.20/src/testing/fake_transport.cpp +1246 -0
  35. hgraph_web-0.8.20/src/value_builders.cpp +938 -0
  36. hgraph_web-0.8.20/test_package/CMakeLists.txt +13 -0
  37. hgraph_web-0.8.20/test_package/main.cpp +34 -0
  38. hgraph_web-0.8.20/tests/CMakeLists.txt +112 -0
  39. hgraph_web-0.8.20/tests/h2spec_server.cpp +209 -0
  40. hgraph_web-0.8.20/tests/test_client_loopback.cpp +339 -0
  41. hgraph_web-0.8.20/tests/test_h2_engine.cpp +539 -0
  42. hgraph_web-0.8.20/tests/test_h2_loopback.cpp +864 -0
  43. hgraph_web-0.8.20/tests/test_loopback.cpp +754 -0
  44. hgraph_web-0.8.20/tests/test_route_table.cpp +354 -0
  45. hgraph_web-0.8.20/tests/test_service.cpp +1375 -0
  46. hgraph_web-0.8.20/tests/test_service_transport.cpp +210 -0
  47. hgraph_web-0.8.20/tests/test_types.cpp +169 -0
  48. hgraph_web-0.8.20/tests/transport_perf.cpp +412 -0
  49. hgraph_web-0.8.20/tools/audit_distribution.py +171 -0
  50. hgraph_web-0.8.20/tools/run_h2spec.py +112 -0
@@ -0,0 +1,7 @@
1
+ /build/
2
+ /build-*/
3
+ /cmake-build-*/
4
+ /dist/
5
+ /.venv/
6
+ __pycache__/
7
+ *.pyc
@@ -0,0 +1,37 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ - Retain the private request, response, WebSocket, delivery, and event
6
+ transport envelopes as immutable `Shared<T>` allocations across the
7
+ push-source and graph-buffering path. Public web service schemas remain
8
+ unchanged and receive one concrete projection at publication.
9
+ - Keep server timer handles immutable during shutdown so graph teardown cannot
10
+ race an Asio timer callback copying the same handle.
11
+ - Initial extension skeleton (RFC 0024).
12
+ - Service tier: one standard bounded burst push source per independently
13
+ ordered logical channel, avoiding cross-channel head-of-line blocking while
14
+ distributing distinct TSD keys together and preserving same-key/scalar FIFO;
15
+ graph-side stateless grouping followed by standard `collect`/mapped `emit`,
16
+ standard scalar `emit`, and command sinks; domain byte/reservation watermarks
17
+ released at graph handoff without a second value queue; the
18
+ eleven service interfaces wired through
19
+ `impl_input`/`impl_output`, wiring sugar, and the socketless
20
+ `FakeWebServer`/`FakeWebClient` transports. Graph-owned subscription
21
+ generations prevent queued HTTP or WebSocket ingress from crossing route/key
22
+ removal and re-addition boundaries (RFC 0024/0027).
23
+ - Python surface: the `hgraph_web` schemas/services/wiring helpers, the
24
+ `@http_endpoint`/`@ws_endpoint` decorators with JSON/text codec helpers
25
+ and route/server authenticators, and `hgraph_web.compat` — the released
26
+ tornado adaptor API re-implemented on the native transports with its
27
+ legacy behaviors reproduced only there (parity notes in the module).
28
+ Compatibility requests are keyed before route streams merge, preserving
29
+ concurrent requests matched by distinct routes in one burst cycle.
30
+ - Live transports: the Asio/Beast server (h1.1 + WebSocket, TLS with the
31
+ HTTP/2 ALPN seam, route trie, port-sharing listener registry, request
32
+ timeouts, watermark read-pausing, strict stop ordering) and the libcurl
33
+ client (h1 + h2, WebSocket over CONNECT_ONLY, response reservations,
34
+ pre-warmed value bindings), `register_server`/`register_client`, and
35
+ the loopback test tiers — an independent Beast oracle against the
36
+ server, and the extension's own client against its own server
37
+ (RFC 0024, implementation plan steps 3-4).
@@ -0,0 +1,396 @@
1
+ cmake_minimum_required(VERSION 3.25)
2
+
3
+ project(hgraph_web VERSION 0.8.0 LANGUAGES C CXX)
4
+
5
+ include(GNUInstallDirs)
6
+ include(CMakePackageConfigHelpers)
7
+ include(CTest)
8
+ include(FetchContent)
9
+
10
+ option(HGRAPH_WEB_FETCH_NGHTTP2
11
+ "Fetch the pinned nghttp2 release when a CMake package is unavailable"
12
+ ON)
13
+ option(HGRAPH_WEB_FETCH_CURL
14
+ "Fetch the pinned curl release when a CMake package is unavailable"
15
+ ON)
16
+ option(HGRAPH_WEB_FETCH_BOOST
17
+ "Fetch the pinned Boost release when a CMake package is unavailable"
18
+ ON)
19
+ option(HGRAPH_WEB_FORCE_FETCH_DEPENDENCIES
20
+ "Use the pinned third-party releases even when system packages are available"
21
+ OFF)
22
+ option(HGRAPH_WEB_BUILD_PYTHON "Build the optional Python authoring bridge" OFF)
23
+
24
+ # Load only the limited-API Python targets before the installed hgraph SDK.
25
+ # Linking an embedding target such as Python::Python would pin this ABI3
26
+ # extension to the interpreter used for the build.
27
+ if(HGRAPH_WEB_BUILD_PYTHON)
28
+ find_package(Python 3.12 COMPONENTS
29
+ Interpreter Development.Module Development.SABIModule REQUIRED)
30
+ endif()
31
+
32
+ if(NOT TARGET hgraph::core)
33
+ find_package(hgraph CONFIG REQUIRED)
34
+ endif()
35
+
36
+ if(HGRAPH_WEB_BUILD_PYTHON AND PROJECT_IS_TOP_LEVEL)
37
+ get_target_property(_hgraph_web_core_links hgraph::options INTERFACE_LINK_LIBRARIES)
38
+ if("Python::Python" IN_LIST _hgraph_web_core_links)
39
+ message(FATAL_ERROR
40
+ "The selected hgraph SDK embeds a specific Python interpreter and "
41
+ "cannot produce an ABI3 hgraph-web wheel; use the SDK installed "
42
+ "by an hgraph stable-ABI wheel")
43
+ endif()
44
+ endif()
45
+
46
+ # ---------------------------------------------------------------------------
47
+ # Third-party transport stack (RFC 0024, packaging): OpenSSL everywhere (one
48
+ # TLS surface, including Windows), then nghttp2 -> curl -> Boost in that
49
+ # order. curl links the same nghttp2 it uses for client HTTP/2, so the later
50
+ # server HTTP/2 activation adds only a translation unit, not a dependency.
51
+ # Everything fetched is built static and stays PRIVATE to this extension.
52
+
53
+ # A Python extension statically embeds its TLS stack. Keep OpenSSL inside the
54
+ # extension on wheel platforms where a package-local dynamic dependency would
55
+ # otherwise require loader-path repair. In particular, Python 3.8+ does not
56
+ # search the Windows process PATH for dependent DLLs.
57
+ if(HGRAPH_WEB_BUILD_PYTHON AND (APPLE OR WIN32))
58
+ set(OPENSSL_USE_STATIC_LIBS TRUE)
59
+ endif()
60
+ find_package(OpenSSL REQUIRED)
61
+
62
+ # Keep the fetched transport libraries static without disturbing how the
63
+ # extension itself (or any sibling target) honors BUILD_SHARED_LIBS, and keep
64
+ # their test suites out of this build.
65
+ set(_hgraph_web_saved_build_shared_libs ${BUILD_SHARED_LIBS})
66
+ set(_hgraph_web_saved_build_testing ${BUILD_TESTING})
67
+ set(BUILD_SHARED_LIBS OFF)
68
+ set(BUILD_STATIC_LIBS ON)
69
+ set(BUILD_TESTING OFF)
70
+ # The static transport archives link into a shared Python module on ELF
71
+ # wheels, so every fetched object must be position independent.
72
+ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
73
+
74
+ # Sibling dependencies (Arrow, the AWS SDK) import system curl and friends at
75
+ # the root scope, so a bare TARGET check would adopt whatever they found.
76
+ # Each dependency is adopted only when this extension's own versioned find
77
+ # succeeded; otherwise the pinned release is fetched.
78
+ set(HGRAPH_WEB_NGHTTP2_TARGET "")
79
+ if(NOT HGRAPH_WEB_FORCE_FETCH_DEPENDENCIES)
80
+ find_package(nghttp2 CONFIG QUIET)
81
+ if(nghttp2_FOUND AND TARGET nghttp2::nghttp2)
82
+ set(HGRAPH_WEB_NGHTTP2_TARGET nghttp2::nghttp2)
83
+ endif()
84
+ endif()
85
+ if(NOT HGRAPH_WEB_NGHTTP2_TARGET)
86
+ if(NOT HGRAPH_WEB_FETCH_NGHTTP2)
87
+ message(FATAL_ERROR
88
+ "nghttp2 was not found; install its CMake package or enable "
89
+ "HGRAPH_WEB_FETCH_NGHTTP2")
90
+ endif()
91
+ set(ENABLE_LIB_ONLY ON CACHE BOOL "" FORCE)
92
+ set(ENABLE_DOC OFF CACHE BOOL "" FORCE)
93
+ set(ENABLE_SHARED_LIB OFF CACHE BOOL "" FORCE)
94
+ set(ENABLE_STATIC_LIB ON CACHE BOOL "" FORCE)
95
+ FetchContent_Declare(nghttp2
96
+ GIT_REPOSITORY https://github.com/nghttp2/nghttp2.git
97
+ GIT_TAG v1.64.0
98
+ GIT_SHALLOW TRUE
99
+ )
100
+ FetchContent_MakeAvailable(nghttp2)
101
+ if(TARGET nghttp2_static)
102
+ set(HGRAPH_WEB_NGHTTP2_TARGET nghttp2_static)
103
+ elseif(TARGET nghttp2)
104
+ set(HGRAPH_WEB_NGHTTP2_TARGET nghttp2)
105
+ else()
106
+ message(FATAL_ERROR "nghttp2 did not provide its library target")
107
+ endif()
108
+ # Point curl's nghttp2 discovery at the fetched tree: the version header
109
+ # is generated into the binary include directory at configure time.
110
+ set(NGHTTP2_INCLUDE_DIR
111
+ "${nghttp2_SOURCE_DIR}/lib/includes;${nghttp2_BINARY_DIR}/lib/includes"
112
+ CACHE STRING "" FORCE)
113
+ set(NGHTTP2_LIBRARY ${HGRAPH_WEB_NGHTTP2_TARGET} CACHE STRING "" FORCE)
114
+ endif()
115
+
116
+ set(HGRAPH_WEB_CURL_TARGET "")
117
+ if(NOT HGRAPH_WEB_FORCE_FETCH_DEPENDENCIES)
118
+ # RFC 0024 pins curl >= 8.11: the WebSocket client API left its
119
+ # experimental phase there.
120
+ find_package(CURL 8.11 CONFIG QUIET)
121
+ if(CURL_FOUND AND TARGET CURL::libcurl)
122
+ set(HGRAPH_WEB_CURL_TARGET CURL::libcurl)
123
+ endif()
124
+ endif()
125
+ if(NOT HGRAPH_WEB_CURL_TARGET)
126
+ if(NOT HGRAPH_WEB_FETCH_CURL)
127
+ message(FATAL_ERROR
128
+ "curl >= 8.11 was not found; install its CMake package or enable "
129
+ "HGRAPH_WEB_FETCH_CURL")
130
+ endif()
131
+ set(BUILD_CURL_EXE OFF CACHE BOOL "" FORCE)
132
+ set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
133
+ # The fetched curl links the in-tree nghttp2 target, which cannot appear
134
+ # in curl's own CMake export set; the extension never consumes curl via
135
+ # its export anyway. Installation must be off entirely: a partial
136
+ # CURLConfig.cmake landing in the hgraph SDK prefix poisons every later
137
+ # find_package(CURL) in that prefix.
138
+ set(CURL_ENABLE_EXPORT_TARGET OFF CACHE BOOL "" FORCE)
139
+ set(CURL_DISABLE_INSTALL ON CACHE BOOL "" FORCE)
140
+ set(BUILD_LIBCURL_DOCS OFF CACHE BOOL "" FORCE)
141
+ set(BUILD_MISC_DOCS OFF CACHE BOOL "" FORCE)
142
+ set(ENABLE_CURL_MANUAL OFF CACHE BOOL "" FORCE)
143
+ # One TLS surface on every platform, including Windows (RFC 0024).
144
+ set(CURL_USE_OPENSSL ON CACHE BOOL "" FORCE)
145
+ set(CURL_USE_SCHANNEL OFF CACHE BOOL "" FORCE)
146
+ set(CURL_USE_SECTRANSP OFF CACHE BOOL "" FORCE)
147
+ set(USE_NGHTTP2 ON CACHE BOOL "" FORCE)
148
+ # The transport needs no auxiliary curl features; keeping them off keeps
149
+ # the wheel dependency-free beyond OpenSSL.
150
+ set(CURL_USE_LIBPSL OFF CACHE BOOL "" FORCE)
151
+ set(CURL_USE_LIBSSH2 OFF CACHE BOOL "" FORCE)
152
+ set(CURL_BROTLI OFF CACHE BOOL "" FORCE)
153
+ set(CURL_ZSTD OFF CACHE BOOL "" FORCE)
154
+ set(USE_LIBIDN2 OFF CACHE BOOL "" FORCE)
155
+ set(CURL_USE_GSSAPI OFF CACHE BOOL "" FORCE)
156
+ set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
157
+ FetchContent_Declare(curl
158
+ GIT_REPOSITORY https://github.com/curl/curl.git
159
+ GIT_TAG curl-8_11_1
160
+ GIT_SHALLOW TRUE
161
+ )
162
+ FetchContent_MakeAvailable(curl)
163
+ if(APPLE AND CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND
164
+ TARGET libcurl_static)
165
+ # curl 8.11.1 passes an intentionally zero-length transfer buffer that
166
+ # AppleClang 21 diagnoses as an uninitialized const pointer. Keep that
167
+ # dependency-owned warning out of otherwise clean hgraph builds.
168
+ target_compile_options(libcurl_static PRIVATE
169
+ -Wno-uninitialized-const-pointer)
170
+ elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND TARGET libcurl_static)
171
+ # GCC 14 diagnoses const conversions in curl 8.11.1's C compatibility
172
+ # surface. Keep that pinned-dependency warning off hgraph build logs.
173
+ target_compile_options(libcurl_static PRIVATE
174
+ -Wno-discarded-qualifiers)
175
+ endif()
176
+ # Adopt the concrete static target: the CURL::libcurl alias name may
177
+ # already be taken by a sibling's system-curl import.
178
+ if(TARGET libcurl_static)
179
+ set(HGRAPH_WEB_CURL_TARGET libcurl_static)
180
+ elseif(TARGET libcurl)
181
+ set(HGRAPH_WEB_CURL_TARGET libcurl)
182
+ else()
183
+ message(FATAL_ERROR "curl did not provide its static library target")
184
+ endif()
185
+ endif()
186
+
187
+ set(HGRAPH_WEB_BOOST_TARGETS "")
188
+ if(NOT HGRAPH_WEB_FORCE_FETCH_DEPENDENCIES)
189
+ find_package(Boost 1.85 CONFIG QUIET COMPONENTS system)
190
+ if(Boost_FOUND AND TARGET Boost::system)
191
+ set(HGRAPH_WEB_BOOST_TARGETS Boost::system)
192
+ if(TARGET Boost::beast)
193
+ list(APPEND HGRAPH_WEB_BOOST_TARGETS Boost::beast Boost::asio)
194
+ else()
195
+ list(APPEND HGRAPH_WEB_BOOST_TARGETS Boost::headers)
196
+ endif()
197
+ endif()
198
+ endif()
199
+ if(NOT HGRAPH_WEB_BOOST_TARGETS)
200
+ if(NOT HGRAPH_WEB_FETCH_BOOST)
201
+ message(FATAL_ERROR
202
+ "Boost >= 1.85 was not found; install its CMake package or enable "
203
+ "HGRAPH_WEB_FETCH_BOOST")
204
+ endif()
205
+ # The CMake-enabled release archive supports building only the needed
206
+ # subset; Beast and Asio are header-only, so this costs extraction, not
207
+ # compilation.
208
+ set(BOOST_INCLUDE_LIBRARIES beast asio system)
209
+ set(BOOST_ENABLE_CMAKE ON)
210
+ # Keep the fetched Boost out of the install tree; it is a build-time
211
+ # detail of this extension, never part of the hgraph SDK.
212
+ set(BOOST_SKIP_INSTALL_RULES ON)
213
+ FetchContent_Declare(boost
214
+ URL https://github.com/boostorg/boost/releases/download/boost-1.87.0/boost-1.87.0-cmake.tar.xz
215
+ DOWNLOAD_EXTRACT_TIMESTAMP TRUE
216
+ )
217
+ FetchContent_MakeAvailable(boost)
218
+ if(NOT TARGET Boost::beast)
219
+ message(FATAL_ERROR "Boost did not provide its Beast target")
220
+ endif()
221
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND TARGET boost_container)
222
+ # GCC 14 reports an unreachable size_t wraparound iteration in the
223
+ # pinned Boost.Container dlmalloc implementation after inlining.
224
+ target_compile_options(boost_container PRIVATE
225
+ -Wno-aggressive-loop-optimizations)
226
+ endif()
227
+ set(HGRAPH_WEB_BOOST_TARGETS Boost::beast Boost::asio Boost::system)
228
+ endif()
229
+
230
+ set(BUILD_SHARED_LIBS ${_hgraph_web_saved_build_shared_libs})
231
+ set(BUILD_TESTING ${_hgraph_web_saved_build_testing})
232
+ # A fetched dependency rewrites the shared BUILD_TESTING cache entry during
233
+ # its configure; restore the superbuild's value so a reconfigure does not
234
+ # silently drop every test target in the tree.
235
+ set(BUILD_TESTING ${_hgraph_web_saved_build_testing}
236
+ CACHE BOOL "Build the testing tree." FORCE)
237
+ unset(_hgraph_web_saved_build_shared_libs)
238
+ unset(_hgraph_web_saved_build_testing)
239
+
240
+ add_library(hgraph_web
241
+ src/asio_server.cpp
242
+ src/curl_client.cpp
243
+ src/nghttp2_session.cpp
244
+ src/detail/route_table.cpp
245
+ src/service.cpp
246
+ src/value_builders.cpp
247
+ src/testing/fake_transport.cpp
248
+ )
249
+ add_library(hgraph::web ALIAS hgraph_web)
250
+
251
+ get_target_property(HGRAPH_WEB_LIBRARY_TYPE hgraph_web TYPE)
252
+ if(HGRAPH_WEB_LIBRARY_TYPE STREQUAL "STATIC_LIBRARY")
253
+ target_compile_definitions(hgraph_web PUBLIC HGRAPH_WEB_STATIC_DEFINE)
254
+ endif()
255
+
256
+ target_compile_features(hgraph_web PUBLIC cxx_std_23)
257
+ # The transport targets join this link line with their translation units:
258
+ # ${HGRAPH_WEB_BOOST_TARGETS} with asio_server.cpp, ${HGRAPH_WEB_CURL_TARGET}
259
+ # with curl_client.cpp, and ${HGRAPH_WEB_NGHTTP2_TARGET} with the HTTP/2
260
+ # session (all PRIVATE; RFC 0024).
261
+ target_link_libraries(hgraph_web
262
+ PUBLIC hgraph::core
263
+ # The fetched transport libraries are build-tree targets outside this
264
+ # project's export set, so they must not leak into the installed
265
+ # interface. Beast/Asio are header-only (compiled into these objects); a
266
+ # SHARED hgraph_web links curl/nghttp2/OpenSSL in. A STATIC install
267
+ # instead needs system curl and OpenSSL at the consumer's final link —
268
+ # the package config records that (the CI SDK consumer uses the shared
269
+ # leg; wheels are always shared).
270
+ PRIVATE $<BUILD_INTERFACE:${HGRAPH_WEB_BOOST_TARGETS}>
271
+ $<BUILD_INTERFACE:${HGRAPH_WEB_CURL_TARGET}>
272
+ $<BUILD_INTERFACE:${HGRAPH_WEB_NGHTTP2_TARGET}>
273
+ OpenSSL::SSL OpenSSL::Crypto
274
+ )
275
+ target_include_directories(hgraph_web
276
+ PUBLIC
277
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
278
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
279
+ PRIVATE
280
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
281
+ )
282
+ set_target_properties(hgraph_web PROPERTIES
283
+ EXPORT_NAME web
284
+ POSITION_INDEPENDENT_CODE ON
285
+ )
286
+
287
+ if(MSVC)
288
+ # The transport implementation includes Windows headers. Keep their
289
+ # min/max macros from rewriting standard-library calls in this target.
290
+ # Its Asio transport requires Windows 10 APIs; publish that build-tree
291
+ # target to sibling tests so Boost does not silently assume Windows 7.
292
+ # Beast's template instantiation count in the server TU exceeds the
293
+ # default COFF section limit, hence /bigobj.
294
+ target_compile_definitions(hgraph_web PRIVATE NOMINMAX WIN32_LEAN_AND_MEAN)
295
+ target_compile_definitions(hgraph_web PUBLIC
296
+ $<BUILD_INTERFACE:_WIN32_WINNT=0x0A00>)
297
+ target_compile_options(hgraph_web PRIVATE /W4 /permissive- /bigobj)
298
+ else()
299
+ target_compile_options(hgraph_web PRIVATE -Wall -Wextra -Wpedantic)
300
+ endif()
301
+
302
+ if(HGRAPH_ENABLE_TSAN AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
303
+ # Boost.Asio uses atomic_thread_fence for its fenced block. GCC warns that
304
+ # TSan cannot model that standalone fence; keep the diagnostic visible but
305
+ # do not let warnings-as-errors prevent the sanitizer runtime from running.
306
+ target_compile_options(hgraph_web PRIVATE -Wno-error=tsan)
307
+ endif()
308
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
309
+ # GCC's -Wmaybe-uninitialized fires falsely on the std::optional-held
310
+ # scalar tuple the static-node machinery instantiates for the server
311
+ # runtime node; it is a middle-end diagnostic, so the suppression must
312
+ # be a compile flag — diagnostic pragmas do not reach it.
313
+ set_source_files_properties(src/asio_server.cpp PROPERTIES
314
+ COMPILE_OPTIONS "-Wno-maybe-uninitialized")
315
+ endif()
316
+
317
+ if(MSVC AND OPENSSL_USE_STATIC_LIBS)
318
+ # Windows TLS objects embed default-library directives for the OpenSSL
319
+ # import libraries. Ignore those names when CMake selected the statically
320
+ # linked archives for a self-contained consumer; otherwise MSVC still
321
+ # searches for the absent import libs.
322
+ target_link_options(hgraph_web INTERFACE
323
+ /NODEFAULTLIB:libcrypto.lib
324
+ /NODEFAULTLIB:libssl.lib
325
+ )
326
+ endif()
327
+
328
+ if(BUILD_TESTING)
329
+ add_subdirectory(tests)
330
+ endif()
331
+
332
+ if(HGRAPH_WEB_BUILD_PYTHON)
333
+ find_package(Python 3.12 COMPONENTS Interpreter Development.Module Development.SABIModule REQUIRED)
334
+ if(COMMAND hgraph_add_python_module AND TARGET hgraph::nanobind)
335
+ hgraph_add_python_module(_hgraph_web STABLE_ABI NOMINSIZE src/python_module.cpp)
336
+ elseif(NOT PROJECT_IS_TOP_LEVEL AND COMMAND nanobind_add_module)
337
+ if(HGRAPH_BUILD_SHARED)
338
+ set(_hgraph_web_nanobind_linkage NB_SHARED)
339
+ else()
340
+ set(_hgraph_web_nanobind_linkage NB_STATIC)
341
+ endif()
342
+ nanobind_add_module(_hgraph_web STABLE_ABI NOMINSIZE
343
+ ${_hgraph_web_nanobind_linkage} src/python_module.cpp)
344
+ unset(_hgraph_web_nanobind_linkage)
345
+ else()
346
+ message(FATAL_ERROR
347
+ "HGRAPH_WEB_BUILD_PYTHON requires a Python-enabled installed hgraph SDK")
348
+ endif()
349
+ target_link_libraries(_hgraph_web PRIVATE hgraph::web)
350
+ if(APPLE)
351
+ set_target_properties(_hgraph_web PROPERTIES
352
+ INSTALL_RPATH "@loader_path/../${CMAKE_INSTALL_LIBDIR}")
353
+ elseif(UNIX)
354
+ set_target_properties(_hgraph_web PROPERTIES
355
+ INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}")
356
+ endif()
357
+ install(TARGETS _hgraph_web
358
+ COMPONENT Python
359
+ LIBRARY DESTINATION hgraph_web
360
+ RUNTIME DESTINATION hgraph_web
361
+ )
362
+ endif()
363
+
364
+ install(TARGETS hgraph_web
365
+ EXPORT hgraphWebTargets
366
+ COMPONENT Development
367
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
368
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
369
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
370
+ )
371
+ install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
372
+ COMPONENT Development FILES_MATCHING PATTERN "*.h")
373
+
374
+ write_basic_package_version_file(
375
+ "${PROJECT_BINARY_DIR}/hgraph-webConfigVersion.cmake"
376
+ VERSION ${PROJECT_VERSION}
377
+ COMPATIBILITY SameMajorVersion
378
+ )
379
+ configure_package_config_file(
380
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/hgraph-webConfig.cmake.in"
381
+ "${PROJECT_BINARY_DIR}/hgraph-webConfig.cmake"
382
+ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/hgraph-web
383
+ )
384
+
385
+ install(EXPORT hgraphWebTargets
386
+ FILE hgraphWebTargets.cmake
387
+ NAMESPACE hgraph::
388
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/hgraph-web
389
+ COMPONENT Development
390
+ )
391
+ install(FILES
392
+ "${PROJECT_BINARY_DIR}/hgraph-webConfig.cmake"
393
+ "${PROJECT_BINARY_DIR}/hgraph-webConfigVersion.cmake"
394
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/hgraph-web
395
+ COMPONENT Development
396
+ )
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Howard Henson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,100 @@
1
+ Metadata-Version: 2.2
2
+ Name: hgraph-web
3
+ Version: 0.8.20
4
+ Summary: HTTP/S and WebSocket transport extension for hgraph
5
+ License: MIT
6
+ Project-URL: Homepage, https://github.com/hhenson/hgraph
7
+ Project-URL: Repository, https://github.com/hhenson/hgraph.git
8
+ Requires-Python: >=3.12
9
+ Requires-Dist: hgraph>=0.8.0
10
+ Requires-Dist: frozendict>=2
11
+ Provides-Extra: test
12
+ Requires-Dist: pytest>=8; extra == "test"
13
+ Description-Content-Type: text/markdown
14
+
15
+ # hgraph-web
16
+
17
+ C++-first HTTP/S and WebSocket transports for hgraph, implementing the contract
18
+ in hgraph RFC 0024. The extension covers all four transports — HTTP(S) server,
19
+ HTTP(S) client, WebSocket server, and WebSocket client — and exposes the same
20
+ service model to native C++ and Python graphs.
21
+
22
+ One path-bound, multi-interface `service_impl` owns the sockets, TLS contexts,
23
+ and worker threads for a configuration. Serving a route and connecting a
24
+ WebSocket are subscription services keyed by the immutable route or connection
25
+ key; responding, sending frames, and calling a remote endpoint are
26
+ request/reply services; events and statistics are reference services. Graph
27
+ output reaches the transport through the implementation's sink inputs, and
28
+ requests, frames, delivery reports, events, and stats re-enter the root graph
29
+ through bounded push sources. Listeners and clients are created on graph start
30
+ and stopped with the graph; there is no user-held server or client object.
31
+
32
+ Routing lives in the transport rather than the graph. The route key set arrives
33
+ as `TSS` deltas, is compiled into a native route table, and requests are
34
+ delivered already keyed by route. Duplicate and ordered headers, multi-value
35
+ query parameters, and binary bodies are preserved end to end.
36
+
37
+ The server speaks HTTP/1.1 and WebSocket over Asio/Beast; the client speaks
38
+ HTTP/1.1, HTTP/2, and WebSocket over libcurl. The server ships the complete
39
+ HTTP/2 seam — the ALPN callback, protocol dispatch, and configuration
40
+ placeholders — and rejects `h2` in server ALPN until the nghttp2 session lands
41
+ in a v1.x release. TLS termination, mTLS, SNI, and ALPN use OpenSSL on every
42
+ platform.
43
+
44
+ The core `hgraph` wheel owns a guarded compatibility shim at
45
+ `hgraph.adaptors.web` which delegates to this extension when it is installed.
46
+ The released `hgraph.adaptors.tornado` package is unchanged; whether it is
47
+ later re-pointed or deprecated is a separate migration decision. The extension
48
+ wheel installs only `hgraph_web`; it never contributes files to the core
49
+ `hgraph` package.
50
+
51
+ ## Status
52
+
53
+ This is the packaging and public-header skeleton. The authoring surface —
54
+ schemas, service interfaces, decorators, and codec helpers — lands with the
55
+ service implementation; see the implementation plan in RFC 0024.
56
+
57
+ ## Build and test
58
+
59
+ This is a first-party extension in the hgraph monorepo. It remains a separate
60
+ CMake package and Python distribution: the top-level core package does not link
61
+ curl, Boost, nghttp2, or OpenSSL, and does not install these modules.
62
+
63
+ For an in-tree native development build from the repository root:
64
+
65
+ ```sh
66
+ cmake -S . -B build-web \
67
+ -DHGRAPH_BUILD_WEB_EXTENSION=ON \
68
+ -DBUILD_TESTING=ON
69
+ cmake --build build-web --parallel
70
+ ctest --test-dir build-web --output-on-failure
71
+ ```
72
+
73
+ The extension can still be configured independently against an installed
74
+ hgraph SDK:
75
+
76
+ ```sh
77
+ cmake -S . -B build -DCMAKE_PREFIX_PATH=/path/to/hgraph/install
78
+ cmake --build build --parallel
79
+ ctest --test-dir build --output-on-failure
80
+ ```
81
+
82
+ Each third-party dependency arrives with the translation unit that links it,
83
+ resolved with `find_package(... CONFIG QUIET)` first and falling back to a
84
+ pinned static `FetchContent` build. The skeleton links only `hgraph::core`.
85
+
86
+ Build its separately deployable ABI3 wheel from the repository root after
87
+ making the matching hgraph SDK discoverable through `CMAKE_PREFIX_PATH`:
88
+
89
+ ```sh
90
+ CMAKE_PREFIX_PATH=/path/to/hgraph/sdk \
91
+ uv build --wheel --package hgraph-web --python 3.12
92
+ ```
93
+
94
+ The deterministic suite runs against the extension's fake transport, which
95
+ exercises routing, pacing, reservation, and lifecycle without sockets. A live
96
+ loopback subset acts as the transport oracle.
97
+
98
+ Wheel builds require the SDK installed by a stable-ABI hgraph wheel. The
99
+ extension rejects an SDK that links `Python::Python`, because that would pin
100
+ the nominal ABI3 module to the build interpreter.
@@ -0,0 +1,86 @@
1
+ # hgraph-web
2
+
3
+ C++-first HTTP/S and WebSocket transports for hgraph, implementing the contract
4
+ in hgraph RFC 0024. The extension covers all four transports — HTTP(S) server,
5
+ HTTP(S) client, WebSocket server, and WebSocket client — and exposes the same
6
+ service model to native C++ and Python graphs.
7
+
8
+ One path-bound, multi-interface `service_impl` owns the sockets, TLS contexts,
9
+ and worker threads for a configuration. Serving a route and connecting a
10
+ WebSocket are subscription services keyed by the immutable route or connection
11
+ key; responding, sending frames, and calling a remote endpoint are
12
+ request/reply services; events and statistics are reference services. Graph
13
+ output reaches the transport through the implementation's sink inputs, and
14
+ requests, frames, delivery reports, events, and stats re-enter the root graph
15
+ through bounded push sources. Listeners and clients are created on graph start
16
+ and stopped with the graph; there is no user-held server or client object.
17
+
18
+ Routing lives in the transport rather than the graph. The route key set arrives
19
+ as `TSS` deltas, is compiled into a native route table, and requests are
20
+ delivered already keyed by route. Duplicate and ordered headers, multi-value
21
+ query parameters, and binary bodies are preserved end to end.
22
+
23
+ The server speaks HTTP/1.1 and WebSocket over Asio/Beast; the client speaks
24
+ HTTP/1.1, HTTP/2, and WebSocket over libcurl. The server ships the complete
25
+ HTTP/2 seam — the ALPN callback, protocol dispatch, and configuration
26
+ placeholders — and rejects `h2` in server ALPN until the nghttp2 session lands
27
+ in a v1.x release. TLS termination, mTLS, SNI, and ALPN use OpenSSL on every
28
+ platform.
29
+
30
+ The core `hgraph` wheel owns a guarded compatibility shim at
31
+ `hgraph.adaptors.web` which delegates to this extension when it is installed.
32
+ The released `hgraph.adaptors.tornado` package is unchanged; whether it is
33
+ later re-pointed or deprecated is a separate migration decision. The extension
34
+ wheel installs only `hgraph_web`; it never contributes files to the core
35
+ `hgraph` package.
36
+
37
+ ## Status
38
+
39
+ This is the packaging and public-header skeleton. The authoring surface —
40
+ schemas, service interfaces, decorators, and codec helpers — lands with the
41
+ service implementation; see the implementation plan in RFC 0024.
42
+
43
+ ## Build and test
44
+
45
+ This is a first-party extension in the hgraph monorepo. It remains a separate
46
+ CMake package and Python distribution: the top-level core package does not link
47
+ curl, Boost, nghttp2, or OpenSSL, and does not install these modules.
48
+
49
+ For an in-tree native development build from the repository root:
50
+
51
+ ```sh
52
+ cmake -S . -B build-web \
53
+ -DHGRAPH_BUILD_WEB_EXTENSION=ON \
54
+ -DBUILD_TESTING=ON
55
+ cmake --build build-web --parallel
56
+ ctest --test-dir build-web --output-on-failure
57
+ ```
58
+
59
+ The extension can still be configured independently against an installed
60
+ hgraph SDK:
61
+
62
+ ```sh
63
+ cmake -S . -B build -DCMAKE_PREFIX_PATH=/path/to/hgraph/install
64
+ cmake --build build --parallel
65
+ ctest --test-dir build --output-on-failure
66
+ ```
67
+
68
+ Each third-party dependency arrives with the translation unit that links it,
69
+ resolved with `find_package(... CONFIG QUIET)` first and falling back to a
70
+ pinned static `FetchContent` build. The skeleton links only `hgraph::core`.
71
+
72
+ Build its separately deployable ABI3 wheel from the repository root after
73
+ making the matching hgraph SDK discoverable through `CMAKE_PREFIX_PATH`:
74
+
75
+ ```sh
76
+ CMAKE_PREFIX_PATH=/path/to/hgraph/sdk \
77
+ uv build --wheel --package hgraph-web --python 3.12
78
+ ```
79
+
80
+ The deterministic suite runs against the extension's fake transport, which
81
+ exercises routing, pacing, reservation, and lifecycle without sockets. A live
82
+ loopback subset acts as the transport oracle.
83
+
84
+ Wheel builds require the SDK installed by a stable-ABI hgraph wheel. The
85
+ extension rejects an SDK that links `Python::Python`, because that would pin
86
+ the nominal ABI3 module to the build interpreter.