dashboard: get rid of oatpp - #419
Conversation
Signed-off-by: Marius Börschig <Marius.Boerschig@vector.com>
713ff9a to
8701f38
Compare
refactor and cleanups Signed-off-by: Marius Börschig <Marius.Boerschig@vector.com>
Signed-off-by: Marius Börschig <Marius.Boerschig@vector.com>
Signed-off-by: Marius Börschig <Marius.Boerschig@vector.com>
Signed-off-by: Marius Börschig <Marius.Boerschig@vector.com>
VDanielEdwards
left a comment
There was a problem hiding this comment.
Heres a mixed set of comments made by Claude and me.
|
|
||
| asio::io_context ioContext{1}; | ||
| std::optional<asio::ip::tcp::socket> socket; | ||
| asio::streambuf readBuffer; |
There was a problem hiding this comment.
Default max_size is SIZE_MAX, so ReadHead's async_read_until and ReadUntilClose's async_read never self-terminate — maxHeadSize/maxHttpBodySize are only checked once the data is already buffered. A server that streams headers without the blank line, or a response with neither Content-Length nor Transfer-Encoding, grows RSS for the whole 30s read window.
asio::streambuf readBuffer{maxHeadSize + maxHttpBodySize}; bounds both (async_read_until then completes with error::not_found). Content-Length and chunked framing are already bounded before reading.
| { | ||
| return asio::error::message_size; | ||
| } | ||
| const auto* data = asio::buffer_cast<const char*>(readBuffer.data()); |
There was a problem hiding this comment.
asio::buffer_cast is deprecated in asio 1.30 — compiles only while ASIO_NO_DEPRECATED is unset. static_cast<const char*>(readBuffer.data().data()) is the current spelling. Also lines 277, 298, 368 and in FakeHttpServer.hpp.
|
|
||
| TEST_F(Test_AsioHttpClient, Post_ReportsATransportErrorWhenNothingIsListening) | ||
| { | ||
| // Port 1 is reserved and never has a listener. The connect deadline is out of reach, so a |
There was a problem hiding this comment.
1h connect deadline + port 1 assumes the host refuses rather than drops. Where loopback port 1 is filtered this hangs to the CTest timeout. Same in service/Test_DashboardShutdown.cpp:79.
| // Parse eagerly so that a malformed --dashboard-uri is reported when the instance is created, | ||
| // rather than later on the registry's thread. The result is discarded; DashboardRestClient | ||
| // parses it again once it is built. | ||
| (void)SilKit::Core::Uri::Parse(dashboardUri); |
There was a problem hiding this comment.
Consider making sure that the URI scheme is http. The Uri::Parse function accepts any scheme.
| (void)SilKit::Core::Uri::Parse(dashboardUri); | |
| const auto uri = SilKit::Core::Uri::Parse(dashboardUri); | |
| if (uri.Scheme() != "http") | |
| { | |
| SilKit::SilKitError{"Dashboard URI must have the http scheme!"}; | |
| } |
Alternatively the check could be done in DashboardRestClient.
| # Every dashboard test links the same set, so register them from one list. | ||
| set(SILKIT_DASHBOARD_TEST_SOURCES | ||
| Test_DashboardEventQueueWorker.cpp | ||
| Test_DashboardSilKitEventQueue.cpp | ||
| client/Test_DashboardSystemServiceClient.cpp | ||
| http/Test_AsioHttpClient.cpp | ||
| http/Test_HttpResponseParser.cpp | ||
| http/Test_RetryingHttpClient.cpp | ||
| json/Test_DashboardJsonWriter.cpp | ||
| service/Test_DashboardDtoMapper.cpp | ||
| service/Test_DashboardRestClient.cpp | ||
| service/Test_DashboardShutdown.cpp | ||
| ) | ||
|
|
||
| add_silkit_test_to_executable(SilKitDashboardTests | ||
| SOURCES client/Test_DashboardSystemServiceClient.cpp | ||
| LIBS | ||
| S_SilKitImpl | ||
| O_SilKit_Dashboard | ||
| I_SilKit | ||
| oatpp | ||
| ) | ||
| target_sources(SilKitDashboardTests PRIVATE http/FakeHttpServer.hpp Mocks/MockRestClient.hpp) | ||
|
|
||
| foreach(testSource IN LISTS SILKIT_DASHBOARD_TEST_SOURCES) | ||
| add_silkit_test_to_executable(SilKitDashboardTests | ||
| SOURCES ${testSource} | ||
| LIBS | ||
| S_SilKitImpl | ||
| O_SilKit_Dashboard | ||
| I_SilKit | ||
| ) | ||
| endforeach() |
There was a problem hiding this comment.
Using target_sources is only valid when SILKIT_BUILD_TESTS=ON. Otherwise the target does not exist. All sources can be combined into a single call to add_silkit_test_to_executable. This does the check internally.
| # Every dashboard test links the same set, so register them from one list. | |
| set(SILKIT_DASHBOARD_TEST_SOURCES | |
| Test_DashboardEventQueueWorker.cpp | |
| Test_DashboardSilKitEventQueue.cpp | |
| client/Test_DashboardSystemServiceClient.cpp | |
| http/Test_AsioHttpClient.cpp | |
| http/Test_HttpResponseParser.cpp | |
| http/Test_RetryingHttpClient.cpp | |
| json/Test_DashboardJsonWriter.cpp | |
| service/Test_DashboardDtoMapper.cpp | |
| service/Test_DashboardRestClient.cpp | |
| service/Test_DashboardShutdown.cpp | |
| ) | |
| add_silkit_test_to_executable(SilKitDashboardTests | |
| SOURCES client/Test_DashboardSystemServiceClient.cpp | |
| LIBS | |
| S_SilKitImpl | |
| O_SilKit_Dashboard | |
| I_SilKit | |
| oatpp | |
| ) | |
| target_sources(SilKitDashboardTests PRIVATE http/FakeHttpServer.hpp Mocks/MockRestClient.hpp) | |
| foreach(testSource IN LISTS SILKIT_DASHBOARD_TEST_SOURCES) | |
| add_silkit_test_to_executable(SilKitDashboardTests | |
| SOURCES ${testSource} | |
| LIBS | |
| S_SilKitImpl | |
| O_SilKit_Dashboard | |
| I_SilKit | |
| ) | |
| endforeach() | |
| add_silkit_test_to_executable(SilKitDashboardTests | |
| SOURCES | |
| http/FakeHttpServer.hpp | |
| Mocks/MockRestClient.hpp | |
| Test_DashboardEventQueueWorker.cpp | |
| Test_DashboardSilKitEventQueue.cpp | |
| client/Test_DashboardSystemServiceClient.cpp | |
| http/Test_AsioHttpClient.cpp | |
| http/Test_HttpResponseParser.cpp | |
| http/Test_RetryingHttpClient.cpp | |
| json/Test_DashboardJsonWriter.cpp | |
| service/Test_DashboardDtoMapper.cpp | |
| service/Test_DashboardRestClient.cpp | |
| service/Test_DashboardShutdown.cpp | |
| LIBS | |
| S_SilKitImpl | |
| O_SilKit_Dashboard | |
| I_SilKit | |
| ) |
| char buffer[64]; | ||
| const int length = std::snprintf(buffer, sizeof buffer, "%.16g", value); | ||
| node << ryml::csubstr{buffer, static_cast<size_t>(length < 0 ? 0 : length)}; |
There was a problem hiding this comment.
Since snprintf(..., "%.16g", ...) can emit nan or inf (for which JSON has no represantation in any case) we should handle this case here. I'd just emit 0. We could also add a log message in this cae, but then we'd have to keep a logger pointer around.
| char buffer[64]; | |
| const int length = std::snprintf(buffer, sizeof buffer, "%.16g", value); | |
| node << ryml::csubstr{buffer, static_cast<size_t>(length < 0 ? 0 : length)}; | |
| if (std::isfinite(value)) | |
| { | |
| char buffer[64]; | |
| const int length = std::snprintf(buffer, sizeof buffer, "%.16g", value); | |
| node << ryml::csubstr{buffer, static_cast<size_t>(length < 0 ? 0 : length)}; | |
| } | |
| else | |
| { | |
| node << 0; | |
| } |
| * | ||
| * Implementations must never throw out of Post(): every failure is reported as | ||
| * HttpResult::transportError. Post() is expected to be called from a single thread; Abort() may be | ||
| * called concurrently from another. |
There was a problem hiding this comment.
Can Reset() also only be called from the same, singular thread as Post(...)?
| // asio types are kept out of this header so that the 22k-line asio headers are confined to the | ||
| // single translation unit that implements the client. | ||
| namespace asio { | ||
| class io_context; |
There was a problem hiding this comment.
Is this forward declare neccessary? AFAICT its not used in this header, and the implementation includes the asio headers themselves.
Drop oat++ from the SIL Kit Dashboard client
ThirdParty/oatppsubmodule, its CMake and license entriesdashboard/http/):, no\/, UTF-8 over\uXXXX; unescapable control chars become U+FFFDRegistryInstancedestroyed the dashboard before the registry pointing at itDashboardtopic and escaped topic filteringSILKIT_BUILD_DASHBOARD=OFFwith--dashboard-urinow reports the missing feature plainlyCollectFromRemoteis off, which silently yields no metrics or attributesSilKitEventtype erasure tostd::variant, worker split out; net −348 linesIRestClientmocked, batching had no coverage