diff --git a/.github/workflows/reusable/cached-install/action.yml b/.github/workflows/reusable/cached-install/action.yml index 1a7d69fa..70f1bac8 100644 --- a/.github/workflows/reusable/cached-install/action.yml +++ b/.github/workflows/reusable/cached-install/action.yml @@ -63,4 +63,14 @@ runs: key: ${{ runner.arch }}-${{ runner.os }}-cache-vcpkg-installed1-${{ hashFiles('./vcpkg.json') }} path: | ./build/vcpkg_installed + #- name: Commit compiled binaries + # run: | + # git config --global user.name 'github-actions[bot]' + # git config --global user.email 'github-actions[bot]@users.noreply.github.com' + # git add packages/streamr-libstreamrproxyclient/dist + # git add packages/streamr-libstreamrproxyclient/wrappers/go + # git commit -m "Automatically compiled binaries" + # git pull --rebase --no-edit + # git push --no-verify + # shell: bash diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 3f1223c7..ff3ad657 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -27,6 +27,8 @@ jobs: with: ref: ${{ github.event.pull_request.head.ref }} fetch-depth: 0 + submodules: true + token: ${{ secrets.GITHUB_TOKEN }} - name: install uses: ./.github/workflows/reusable/cached-install - name: lint diff --git a/.gitmodules b/.gitmodules index 01c11c72..a0411790 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,3 +9,6 @@ [submodule "packages/streamr-trackerless-network/test/integration/ts-integration"] path = packages/streamr-trackerless-network/test/integration/ts-integration url = https://github.com/streamr-dev/native-ts-integration.git +[submodule "packages/streamr-libstreamrproxyclient/wrappers/go"] + path = packages/streamr-libstreamrproxyclient/wrappers/go + url = git@github.com:streamr-dev/goproxyclient.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b2dde86..537a35d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,3 +21,4 @@ message(STATUS "Root project VCPKG_TARGET_TRIPLET: ${VCPKG_TARGET_TRIPLET}") foreach(package ${MonorepoPackages}) add_subdirectory(packages/${package}) endforeach() + diff --git a/overlayports/folly/fix-cursor.patch b/overlayports/folly/fix-cursor.patch new file mode 100644 index 00000000..64724f2a --- /dev/null +++ b/overlayports/folly/fix-cursor.patch @@ -0,0 +1,13 @@ +diff --git a/folly/io/Cursor.h b/folly/io/Cursor.h +index 7a0abc9..710ba3e 100644 +--- a/folly/io/Cursor.h ++++ b/folly/io/Cursor.h +@@ -683,7 +683,7 @@ class CursorBase { + * + * @methodset Accessors + */ +- std::basic_string_view peekView() { ++ std::basic_string_view peekView() { + auto bytes = peekBytes(); + return {bytes.data(), bytes.size()}; + } diff --git a/overlayports/folly/fix-range.patch b/overlayports/folly/fix-range.patch new file mode 100644 index 00000000..328b5b51 --- /dev/null +++ b/overlayports/folly/fix-range.patch @@ -0,0 +1,13 @@ +diff --git a/folly/Range.h b/folly/Range.h +index 42cd92d69..d87914a99 100644 +--- a/folly/Range.h ++++ b/folly/Range.h +@@ -638,7 +638,7 @@ class Range { + template + struct StringViewType // + : std::conditional< +- std::is_trivial::value, ++ detail::range_is_char_type_v_, + std::basic_string_view, + NotStringView> {}; + diff --git a/overlayports/folly/portfile.cmake b/overlayports/folly/portfile.cmake index 9210ac3e..73b07fb3 100644 --- a/overlayports/folly/portfile.cmake +++ b/overlayports/folly/portfile.cmake @@ -21,6 +21,8 @@ vcpkg_from_github( disable-groupvarint.patch disable-cxa-init-primary-exception.patch fix-android-remainder.patch + fix-range.patch + fix-cursor.patch ) file(REMOVE "${SOURCE_PATH}/CMake/FindFmt.cmake") diff --git a/overlayports/libdatachannel/dependencies.diff b/overlayports/libdatachannel/dependencies.diff new file mode 100644 index 00000000..01ea420c --- /dev/null +++ b/overlayports/libdatachannel/dependencies.diff @@ -0,0 +1,63 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 8a61757..b35e4b1 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -234,7 +234,7 @@ set(THREADS_PREFER_PTHREAD_FLAG TRUE) + find_package(Threads REQUIRED) + + if(USE_SYSTEM_PLOG) +- find_package(plog REQUIRED) ++ find_package(plog CONFIG REQUIRED) + else() + set(CMAKE_POLICY_DEFAULT_CMP0048 NEW) + add_subdirectory(deps/plog EXCLUDE_FROM_ALL) +@@ -245,7 +245,8 @@ if(SCTP_DEBUG) + endif() + + if(USE_SYSTEM_USRSCTP) +- find_package(Usrsctp REQUIRED) ++ find_package(unofficial-usrsctp CONFIG REQUIRED) ++ add_library(Usrsctp::Usrsctp ALIAS unofficial::usrsctp::usrsctp) + else() + option(sctp_build_shared_lib OFF) + option(sctp_build_programs OFF) +@@ -331,7 +332,7 @@ else() + target_compile_definitions(datachannel PUBLIC RTC_ENABLE_MEDIA=1) + target_compile_definitions(datachannel-static PUBLIC RTC_ENABLE_MEDIA=1) + if(USE_SYSTEM_SRTP) +- find_package(libSRTP REQUIRED) ++ find_package(libSRTP CONFIG REQUIRED) + if(NOT TARGET libSRTP::srtp2) + add_library(libSRTP::srtp2 UNKNOWN IMPORTED) + set_target_properties(libSRTP::srtp2 PROPERTIES +@@ -475,8 +476,9 @@ install( + ) + + # Export config ++configure_file(cmake/LibDataChannelConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/cmake/LibDataChannelConfig.cmake @ONLY) + install( +- FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/LibDataChannelConfig.cmake ++ FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/LibDataChannelConfig.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/LibDataChannel + ) + +diff --git a/cmake/LibDataChannelConfig.cmake b/cmake/LibDataChannelConfig.cmake +index cb2b884..d0b77ca 100644 +--- a/cmake/LibDataChannelConfig.cmake ++++ b/cmake/LibDataChannelConfig.cmake +@@ -1,2 +1,15 @@ ++if(NOT "@BUILD_SHARED_LIBS@") ++ include(CMakeFindDependencyMacro) ++ set(THREADS_PREFER_PTHREAD_FLAG ON) ++ find_dependency(Threads) ++ find_dependency(plog CONFIG) ++ find_dependency(unofficial-usrsctp CONFIG) ++ if(NOT "@NO_MEDIA@") ++ find_dependency(libSRTP CONFIG) ++ endif() ++ find_dependency(OpenSSL) ++ find_dependency(LibJuice) ++endif() ++ + include("${CMAKE_CURRENT_LIST_DIR}/LibDataChannelTargets.cmake") + diff --git a/overlayports/libdatachannel/fix-cmakelists.patch b/overlayports/libdatachannel/fix-cmakelists.patch new file mode 100644 index 00000000..d275b199 --- /dev/null +++ b/overlayports/libdatachannel/fix-cmakelists.patch @@ -0,0 +1,28 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 38e069e..0ada768 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -260,10 +260,20 @@ else() + add_library(Usrsctp::Usrsctp ALIAS usrsctp) + endif() + +-configure_file ( +- ${PROJECT_SOURCE_DIR}/cmake/version.h.in +- ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/version.h ++if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/version.h") ++ file(REMOVE "${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/version.h") ++endif() ++ ++file(COPY ++ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.h.in ++ DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc + ) ++file(RENAME ++ ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/version.h.in ++ ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/version.h ++) ++ ++ + + add_library(datachannel SHARED + ${LIBDATACHANNEL_SOURCES} diff --git a/overlayports/libdatachannel/library-linkage.diff b/overlayports/libdatachannel/library-linkage.diff new file mode 100644 index 00000000..655c0320 --- /dev/null +++ b/overlayports/libdatachannel/library-linkage.diff @@ -0,0 +1,30 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index b35e4b1..b052d02 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -48,7 +48,6 @@ endif() + + list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules) + set(CMAKE_POSITION_INDEPENDENT_CODE ON) +-set(BUILD_SHARED_LIBS OFF) # to force usrsctp to be built static + + if(WIN32) + add_definitions(-DWIN32_LEAN_AND_MEAN) +@@ -457,11 +456,17 @@ if(WARNINGS_AS_ERRORS) + endif() + endif() + ++if(BUILD_SHARED_LIBS) + install(TARGETS datachannel EXPORT LibDataChannelTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) ++else() ++ set_target_properties(datachannel PROPERTIES EXCLUDE_FROM_ALL 1) ++ set_target_properties(datachannel-static PROPERTIES EXCLUDE_FROM_ALL 0) ++ install(TARGETS datachannel-static EXPORT LibDataChannelTargets) ++endif() + + install(FILES ${LIBDATACHANNEL_HEADERS} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/rtc diff --git a/overlayports/libdatachannel/portfile.cmake b/overlayports/libdatachannel/portfile.cmake new file mode 100644 index 00000000..5967b715 --- /dev/null +++ b/overlayports/libdatachannel/portfile.cmake @@ -0,0 +1,42 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO paullouisageneau/libdatachannel + REF "v${VERSION}" + SHA512 fd0d66bb932e29abc01e9f1a8b16ccb79012a7e3901e2e0f882f56ab2f090260945e1556c85ad07ef897b8c70fcdd44cdeead9955a9bca7afe1dda8900c473cc + HEAD_REF master + PATCHES + dependencies.diff + library-linkage.diff + uwp-warnings.patch + fix-cmakelists.patch +) + +vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS + FEATURES + stdcall CAPI_STDCALL + INVERTED_FEATURES + ws NO_WEBSOCKET + srtp NO_MEDIA +) + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" + OPTIONS + ${FEATURE_OPTIONS} + -DPREFER_SYSTEM_LIB=ON + -DNO_EXAMPLES=ON + -DNO_TESTS=ON +) + +vcpkg_cmake_install() +vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/LibDataChannel) +vcpkg_fixup_pkgconfig() + +if(VCPKG_LIBRARY_LINKAGE STREQUAL "static") + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/rtc/common.hpp" "#ifdef RTC_STATIC" "#if 1") + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/rtc/rtc.h" "#ifdef RTC_STATIC" "#if 1") +endif() + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include" "${CURRENT_PACKAGES_DIR}/debug/share") + +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") diff --git a/overlayports/libdatachannel/uwp-warnings.patch b/overlayports/libdatachannel/uwp-warnings.patch new file mode 100644 index 00000000..23d23dd3 --- /dev/null +++ b/overlayports/libdatachannel/uwp-warnings.patch @@ -0,0 +1,15 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 1b5190b..763b49e 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -315,6 +315,10 @@ target_link_libraries(datachannel-static PRIVATE Usrsctp::Usrsctp plog::plog) + if(WIN32) + target_link_libraries(datachannel PUBLIC ws2_32) # winsock2 + target_link_libraries(datachannel-static PUBLIC ws2_32) # winsock2 ++ if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") ++ target_compile_options(datachannel PRIVATE /wd4996) ++ target_compile_options(datachannel-static PRIVATE /wd4996) ++ endif() + endif() + + if (NO_WEBSOCKET) diff --git a/overlayports/libdatachannel/vcpkg.json b/overlayports/libdatachannel/vcpkg.json new file mode 100644 index 00000000..71d55e0f --- /dev/null +++ b/overlayports/libdatachannel/vcpkg.json @@ -0,0 +1,41 @@ +{ + "name": "libdatachannel", + "version-semver": "0.21.2", + "port-version": 1, + "description": "libdatachannel is a standalone implementation of WebRTC Data Channels, WebRTC Media Transport, and WebSockets in C++17 with C bindings for POSIX platforms (including GNU/Linux, Android, and Apple macOS) and Microsoft Windows.", + "homepage": "https://github.com/paullouisageneau/libdatachannel", + "license": "MPL-2.0", + "supports": "!xbox", + "dependencies": [ + "libjuice", + "nlohmann-json", + "openssl", + "plog", + "usrsctp", + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ], + "default-features": [ + "ws" + ], + "features": { + "srtp": { + "description": "Use Cisco's libSRTP for media transport.", + "dependencies": [ + "libsrtp" + ] + }, + "stdcall": { + "description": "Use stdcall convention in callbacks" + }, + "ws": { + "description": "Web Socket support" + } + } +} diff --git a/packages/streamr-dht/CMakeLists.txt b/packages/streamr-dht/CMakeLists.txt index 577a8f7a..2880d0dd 100644 --- a/packages/streamr-dht/CMakeLists.txt +++ b/packages/streamr-dht/CMakeLists.txt @@ -101,43 +101,43 @@ if(NOT IOS) ) add_executable(streamr-dht-test-unit - test/unit/AddressToolsTest.cpp + test/unit/WebsocketClientConnectionTest.cpp + test/unit/WebsocketClientConnectorRpcLocalTest.cpp test/unit/CertificateHelperTest.cpp - test/unit/ConnectedEndpointStateTest.cpp - test/unit/ConnectingEndpointStateTest.cpp - test/unit/ConnectionLockRpcLocalTest.cpp - test/unit/ConnectionLockRpcRemoteTest.cpp - test/unit/ConnectionLockStatesTest.cpp - test/unit/ConnectionLockerTest.cpp test/unit/ConnectionManagerTest.cpp - test/unit/ConnectionsViewTest.cpp - test/unit/ConnectivityTest.cpp + test/unit/WebsocketClientConnectorRpcRemoteTest.cpp + test/unit/IdentifiersTest.cpp + test/unit/ConnectionLockRpcRemoteTest.cpp test/unit/ConnectorFacadeTest.cpp + test/unit/ConnectionsViewTest.cpp + test/unit/WebsocketServerConnectorTest.cpp + test/unit/OffererTest.cpp test/unit/DhtCallContextTest.cpp - test/unit/DisconnectedEndpointStateTest.cpp - test/unit/DuplicateDetectorTest.cpp - test/unit/EndpointStateInterfaceTest.cpp - test/unit/EndpointStateTest.cpp + test/unit/PendingConnectionTest.cpp + test/unit/ConnectionLockRpcLocalTest.cpp test/unit/EndpointTest.cpp - test/unit/FakeTransportTest.cpp - test/unit/HandshakerTest.cpp - test/unit/IPendingConnectionTest.cpp - test/unit/IdentifiersTest.cpp - test/unit/IncomingHandshakerTest.cpp + test/unit/ConnectingEndpointStateTest.cpp + test/unit/ConnectedEndpointStateTest.cpp + test/unit/DisconnectedEndpointStateTest.cpp test/unit/InitialEndpointStateTest.cpp - test/unit/OffererTest.cpp + test/unit/FakeTransportTest.cpp + test/unit/EndpointStateTest.cpp test/unit/OutgoingHandshakerTest.cpp - test/unit/PendingConnectionTest.cpp - test/unit/RoutingRpcCommunicatorTest.cpp + test/unit/IncomingHandshakerTest.cpp + test/unit/EndpointStateInterfaceTest.cpp + test/unit/WebsocketConnectionTest.cpp test/unit/TransportTest.cpp + test/unit/HandshakerTest.cpp + test/unit/RoutingRpcCommunicatorTest.cpp + test/unit/ConnectionLockerTest.cpp + test/unit/AddressToolsTest.cpp + test/unit/DuplicateDetectorTest.cpp + test/unit/ConnectionLockStatesTest.cpp + test/unit/ConnectivityTest.cpp + test/unit/IPendingConnectionTest.cpp test/unit/VersionTest.cpp - test/unit/WebsocketClientConnectionTest.cpp - test/unit/WebsocketClientConnectorRpcLocalTest.cpp - test/unit/WebsocketClientConnectorRpcRemoteTest.cpp test/unit/WebsocketClientConnectorTest.cpp - test/unit/WebsocketConnectionTest.cpp test/unit/WebsocketServerConnectionTest.cpp - test/unit/WebsocketServerConnectorTest.cpp test/unit/WebsocketServerTest.cpp test/unit/ListeningRpcCommunicatorTest.cpp ) diff --git a/packages/streamr-libstreamrproxyclient/.gitignore b/packages/streamr-libstreamrproxyclient/.gitignore index 6c3ca2fc..514be16a 100644 --- a/packages/streamr-libstreamrproxyclient/.gitignore +++ b/packages/streamr-libstreamrproxyclient/.gitignore @@ -4,7 +4,16 @@ **/*.pyo **/*.pyd **/.pytest_cache/ +wrappers/python/dist +wrappers/python/src/streamrproxyclient/libstreamrproxyclient.dylib +wrappers/python/src/streamrproxyclient/libstreamrproxyclient.so +dist/* +**/**.dylib +**/**.so **/wheelhouse/ *.tgz *.so.* **/libstreamrproxyclient.[0-9].[0-9].[0-9].dylib +dist/ +dist/** +wrappers/python/src/streamrproxyclient/libstreamrproxyclient.dylib \ No newline at end of file diff --git a/packages/streamr-libstreamrproxyclient/CMakeLists.txt b/packages/streamr-libstreamrproxyclient/CMakeLists.txt index 7b649b92..d34ff073 100644 --- a/packages/streamr-libstreamrproxyclient/CMakeLists.txt +++ b/packages/streamr-libstreamrproxyclient/CMakeLists.txt @@ -14,15 +14,16 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/monorepoPackage.cmake) set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake") -set (SHAREDLIB_VERSION 1.0.0) -set (SHAREDLIB_SOVERSION 1) -set (IOS_SWIFT_PACKAGE_VERSION 1.0.0) -set (ANDROID_LIBRARY_VERSION 1.0.0) +include(${CMAKE_CURRENT_SOURCE_DIR}/VERSION.cmake) +set (SHAREDLIB_VERSION ${STREAMRPROXYCLIENT_VERSION}) +set (SHAREDLIB_SOVERSION ${STREAMRPROXYCLIENT_SOVERSION}) + +set (IOS_SWIFT_PACKAGE_VERSION ${STREAMRPROXYCLIENT_VERSION}) +set (ANDROID_LIBRARY_VERSION ${STREAMRPROXYCLIENT_VERSION}) project(streamr-streamrproxyclient CXX) add_library(streamrproxyclient SHARED src/streamrproxyclient.cpp - include/streamrproxyclient.h include/StreamrProxyClient.hpp ) set_target_properties(streamrproxyclient PROPERTIES VERSION ${SHAREDLIB_VERSION} SOVERSION ${SHAREDLIB_SOVERSION}) @@ -74,7 +75,7 @@ if (NOT IOS) find_package(GTest CONFIG REQUIRED) find_package(folly CONFIG REQUIRED) - add_executable(streamr-streamrproxyclient-test-integration test/integration/StreamrProxyClientTest.cpp test/integration/StreamrProxyClientCppTest.cpp) + add_executable(streamr-streamrproxyclient-test-integration test/integration/StreamrProxyClientTest.cpp) target_link_directories(streamr-streamrproxyclient-test-integration PUBLIC ${SHAREDLIB_OUTPUT_DIRECTORY}) target_include_directories(streamr-streamrproxyclient-test-integration PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) @@ -86,7 +87,7 @@ if (NOT IOS) PRIVATE GTest::gtest_main ) - add_executable(streamr-streamrproxyclient-test-end-to-end test/end-to-end/PublishToTsServerTest.cpp test/end-to-end/PublishToTsServerCppTest.cpp) + add_executable(streamr-streamrproxyclient-test-end-to-end test/end-to-end/PublishToTsServerTest.cpp) target_link_directories(streamr-streamrproxyclient-test-end-to-end PUBLIC ${CMAKE_CURRENT_LIST_DIR}/build) target_include_directories(streamr-streamrproxyclient-test-end-to-end PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) @@ -97,7 +98,7 @@ if (NOT IOS) PRIVATE GTest::gtest_main ) - add_executable(streamrproxyclient-cpp-wrapper-test ${CMAKE_CURRENT_LIST_DIR}/wrappers/cpp/test/StreamrProxyClientTest.cpp) + add_executable(streamrproxyclient-cpp-wrapper-test ${CMAKE_CURRENT_LIST_DIR}/wrappers/cpp/test/StreamrProxyClientCppWrapperTest.cpp) target_link_directories(streamrproxyclient-cpp-wrapper-test PUBLIC ${CMAKE_CURRENT_LIST_DIR}/build) target_include_directories(streamrproxyclient-cpp-wrapper-test PUBLIC ${CMAKE_CURRENT_LIST_DIR}/wrappers/cpp/include) @@ -123,29 +124,11 @@ if (NOT IOS) COMMAND "${CMAKE_CURRENT_LIST_DIR}/run-ts-multiple-messages-test.sh" WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" ) - - add_test( - NAME ts-end-to-end-cpp-test - COMMAND "${CMAKE_CURRENT_LIST_DIR}/run-ts-end-to-end-cpp-tests.sh" - WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" - ) - - add_test( - NAME ts-multiple-messages-cpp-test - COMMAND "${CMAKE_CURRENT_LIST_DIR}/run-ts-multiple-messages-cpp-test.sh" - WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" - ) - - endif() # Install header to dist/target-triplet install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/streamrproxyclient.h DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/dist/${VCPKG_TARGET_TRIPLET}/include) - # Install CPP header to dist/target-triplet - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/StreamrProxyClient.hpp - DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/dist/${VCPKG_TARGET_TRIPLET}/include) - # Install library to dist/target-triplet install(TARGETS streamrproxyclient DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/dist/${VCPKG_TARGET_TRIPLET}/lib/${CMAKE_BUILD_TYPE}) @@ -200,11 +183,13 @@ if (NOT IOS) # If not ios or android, and build type is Release, copy the .so or .dylib file to the wrappers/go/dist/target-triplet/lib/Release/ directory if (NOT (${VCPKG_TARGET_TRIPLET} MATCHES "android") AND ${CMAKE_BUILD_TYPE} STREQUAL "Release") install(CODE "execute_process(COMMAND ${CMAKE_CURRENT_LIST_DIR}/copyfilesforgowrapper.sh ${CMAKE_CURRENT_SOURCE_DIR}/dist/${VCPKG_TARGET_TRIPLET}/lib/${CMAKE_BUILD_TYPE} ${VCPKG_TARGET_TRIPLET} ${CMAKE_CURRENT_LIST_DIR})") - + # Also install header to wrappers/go install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/streamrproxyclient.h DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/wrappers/go) + + # Also create a python package and upload it to PyPi + install(CODE "execute_process(COMMAND ${CMAKE_CURRENT_LIST_DIR}/createpythonpackage.sh ${CMAKE_CURRENT_SOURCE_DIR}/dist/${VCPKG_TARGET_TRIPLET}/lib/${CMAKE_BUILD_TYPE} ${VCPKG_TARGET_TRIPLET} ${CMAKE_CURRENT_LIST_DIR} ${STREAMRPROXYCLIENT_VERSION})") endif() - endif() diff --git a/packages/streamr-libstreamrproxyclient/VERSION.cmake b/packages/streamr-libstreamrproxyclient/VERSION.cmake new file mode 100644 index 00000000..1d01dc02 --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/VERSION.cmake @@ -0,0 +1,6 @@ +set(STREAMRPROXYCLIENT_VERSION +2.0.5 +) +set(STREAMRPROXYCLIENT_SOVERSION +2 +) diff --git a/packages/streamr-libstreamrproxyclient/copyfilesforgowrapper.sh b/packages/streamr-libstreamrproxyclient/copyfilesforgowrapper.sh index 3606b996..279beb72 100755 --- a/packages/streamr-libstreamrproxyclient/copyfilesforgowrapper.sh +++ b/packages/streamr-libstreamrproxyclient/copyfilesforgowrapper.sh @@ -2,6 +2,16 @@ # Print out whole command line echo "Copying files for go wrapper: $0 $@" +# Check if all required arguments are provided +if [ "$#" -ne 3 ]; then + echo "Usage: $0 SOURCE_DIR VCPKG_TARGET_TRIPLET CURRENT_LIST_DIR" + echo " SOURCE_DIR: Directory containing the .so or .dylib file" + echo " VCPKG_TARGET_TRIPLET: Target triplet (e.g. x64-linux)" + echo " CURRENT_LIST_DIR: Current list directory" + exit 1 +fi + + # Take the source directory containing the .so or .dylib file as an argument SOURCE_DIR=$1 # Take the target triplet as an argument @@ -10,10 +20,38 @@ VCPKG_TARGET_TRIPLET=$2 CURRENT_LIST_DIR=$3 #find out if the file is a .so or .dylib file by checking the file extension of the files in the source directory -FILE_TYPE=$(ls $SOURCE_DIR | grep -o '\.so\|\.dylib') +FILE_TYPE=$(ls $SOURCE_DIR | grep -o '\.so\|\.dylib' | head -n 1) # create the destination directory if it doesn't exist mkdir -p $CURRENT_LIST_DIR/wrappers/go/dist/$VCPKG_TARGET_TRIPLET/lib/Release/ +SOURCE_FILE=$SOURCE_DIR/libstreamrproxyclient$FILE_TYPE +DEST_FILE=$CURRENT_LIST_DIR/wrappers/go/dist/$VCPKG_TARGET_TRIPLET/lib/Release/libstreamrproxyclient$FILE_TYPE # Copy the .so or .dylib file to the dist directory -cp -L $SOURCE_DIR/libstreamrproxyclient$FILE_TYPE $CURRENT_LIST_DIR/wrappers/go/dist/$VCPKG_TARGET_TRIPLET/lib/Release/ 2>/dev/null || : +cp -L $SOURCE_FILE $DEST_FILE 2>/dev/null || : + +cd $CURRENT_LIST_DIR/wrappers/go/ + +# Install git-filter-repo +#pip install git-filter-repo + +# Remove git history of the DEST_FILE +#git filter-repo --strip-blobs-bigger-than 100M --refs $DEST_FILE + +# Add the DEST_FILE to the submodule git repository +echo "Adding library file to git..." +git add $DEST_FILE 2>/dev/null || : + +echo "Committing library file changes..." +git commit -m "Add latest version of $DEST_FILE" 2>/dev/null || : + +echo "Force pushing library changes to submodule repository..." +git push origin --force 2>/dev/null || : + +cd - + +echo "Updating main repository with new submodule version..." +git add $CURRENT_LIST_DIR/wrappers/go 2>/dev/null || : +git commit -m "Update gowrapper submodule to latest version" 2>/dev/null || : +git push --no-verify origin master 2>/dev/null || : + diff --git a/packages/streamr-libstreamrproxyclient/createpythonpackage.sh b/packages/streamr-libstreamrproxyclient/createpythonpackage.sh new file mode 100755 index 00000000..49838a61 --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/createpythonpackage.sh @@ -0,0 +1,65 @@ +#! /bin/bash + +# Print out whole command line +echo "Copying files for python wrapper: $0 $@" + +# Check if all required arguments are provided +if [ "$#" -ne 4 ]; then + echo "Usage: $0 SOURCE_DIR VCPKG_TARGET_TRIPLET CURRENT_LIST_DIR" + echo " SOURCE_DIR: Directory containing the .so or .dylib file" + echo " VCPKG_TARGET_TRIPLET: Target triplet (e.g. x64-linux)" + echo " CURRENT_LIST_DIR: Current list directory" + echo " STREAMRPROXYCLIENT_VERSION: StreamrProxyClient version" + exit 1 +fi + + +# Take the source directory containing the .so or .dylib file as an argument +SOURCE_DIR=$1 +# Take the target triplet as an argument +VCPKG_TARGET_TRIPLET=$2 +# Take the current list directory as an argument +CURRENT_LIST_DIR=$3 +# Take the StreamrProxyClient version as an argument +STREAMRPROXYCLIENT_VERSION=$4 + +#find out if the file is a .so or .dylib file by checking the file extension of the files in the source directory +FILE_TYPE=$(ls $SOURCE_DIR | grep -o '\.so\|\.dylib' | head -n 1) + +SOURCE_FILE=$SOURCE_DIR/libstreamrproxyclient$FILE_TYPE +DEST_FILE=$CURRENT_LIST_DIR/wrappers/python/src/streamrproxyclient/libstreamrproxyclient$FILE_TYPE +echo "Copying $SOURCE_FILE to $DEST_FILE" +# Copy the .so or .dylib file to the dist directory +cp -L $SOURCE_FILE $DEST_FILE 2>/dev/null || : + +# Install needed python packages + +python -m pip install pip +python -m pip install hatch hatchling pip twine build + +# Copy the dylib to the package + +cd $CURRENT_LIST_DIR/wrappers/python/ + +# Replace the version in the pyproject.toml file +pip install toml + +python -c " +import toml +import sys + +config = toml.load('pyproject.toml') +config['project']['version'] = '$STREAMRPROXYCLIENT_VERSION' +with open('pyproject.toml', 'w') as f: + toml.dump(config, f) +" +rm -rf dist +python -m build + +# Upload the package to test.pypi.org + +python -m twine upload --verbose dist/* || : + +#remove the dylib from the package + +rm -f $DEST_FILE diff --git a/packages/streamr-libstreamrproxyclient/dist/arm64-osx/include/streamrproxyclient.h b/packages/streamr-libstreamrproxyclient/dist/arm64-osx/include/streamrproxyclient.h deleted file mode 100644 index b28c146c..00000000 --- a/packages/streamr-libstreamrproxyclient/dist/arm64-osx/include/streamrproxyclient.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef LIBSTREAMRPROXYCLIENT_H -#define LIBSTREAMRPROXYCLIENT_H - -// NOLINTNEXTLINE -#include - -#if defined(__clang__) || defined(__GNUC__) -#define SHARED_EXPORT __attribute__((visibility("default"))) -#define SHARED_LOCAL __attribute__((visibility("hidden"))) -#else -#define SHARED_EXPORT -#define SHARED_LOCAL -#endif - -#ifdef __cplusplus -#define EXTERN_C extern "C" -#else -#define EXTERN_C -#endif - -#define ERROR_INVALID_ETHEREUM_ADDRESS "INVALID_ETHEREUM_ADDRESS" -#define ERROR_INVALID_STREAM_PART_ID "INVALID_STREAM_PART_ID" -#define ERROR_PROXY_CLIENT_NOT_FOUND "PROXY_CLIENT_NOT_FOUND" -#define ERROR_INVALID_PROXY_URL "INVALID_PROXY_URL" -#define ERROR_NO_PROXIES_DEFINED "NO_PROXIES_DEFINED" -#define ERROR_PROXY_CONNECTION_FAILED "PROXY_CONNECTION_FAILED" -#define ERROR_PROXY_BROADCAST_FAILED "PROXY_BROADCAST_FAILED" - -EXTERN_C SHARED_EXPORT const char* testRpc(void); - -// NOLINTNEXTLINE -SHARED_EXPORT static void __attribute__((constructor)) initialize(void); - - -/** - * @brief Initialize the library. This function is called automatically when the library is loaded, - * but can be called explicitly to force a re-initialization (e.g. after proxyClientCleanupLibrary() has been called). - */ - -// NOLINTNEXTLINE -EXTERN_C SHARED_EXPORT void proxyClientInitLibrary(void); - -/** - * @brief Cleanup the library. This function MUST be called before the program exits. - * Can be safely called multiple times. This is needed because the standard dynamic library - * destructor (__attribute__((destructor))) is called after static variables have already been destroyed, - * which makes it impossible to clean up the other objects that depend on the static variables. - */ -// NOLINTNEXTLINE -EXTERN_C SHARED_EXPORT void proxyClientCleanupLibrary(void); -// NOLINTNEXTLINE -typedef struct Proxy { - const char* websocketUrl; - const char* ethereumAddress; -} Proxy; - -// NOLINTNEXTLINE -typedef struct Error { - const char* message; - const char* code; - const struct Proxy* proxy; -} Error; - -// NOLINTNEXTLINE -typedef struct ProxyResult { - Error* errors; - uint64_t numErrors; - Proxy* successful; - uint64_t numSuccessful; -} ProxyResult; - -/** - * @brief Delete a ProxyResult. This method must be called after every call that - * returns a ProxyResult. - * @param proxyResult The ProxyResult to delete. - */ - -EXTERN_C SHARED_EXPORT void proxyClientResultDelete(const ProxyResult* proxyResult); - -/** - * @brief Create a new proxy client. - * - * @param proxyResult Pointer in which ProxyResult will be stored. You MUST call - * proxyClientResultDelete() on this after the call returns. The resulting ProxyResult - * may only contain "errors" - the "successful" and "numSuccessful" fields are - * unused. - * @param ownEthereumAddress The Ethereum address of the client in format - * 0x1234567890123456789012345678901234567890. - * @param streamPartId The stream part id in format - * 0xa000000000000000000000000000000000000000#01. - * @return The handle of the created client. - */ - -EXTERN_C SHARED_EXPORT uint64_t proxyClientNew( - const ProxyResult** proxyResult, - const char* ownEthereumAddress, - const char* streamPartId); - -/** - * @brief Delete a proxy client. - * - * @param proxyResult Pointer in which ProxyResult will be stored. You MUST call - * proxyClientResultDelete() on this after the call returns. The resulting ProxyResult - * may only contain "errors" - the "successful" and "numSuccessful" fields are - * unused. - * @param clientHandle The client handle of the client to delete. - */ - -EXTERN_C SHARED_EXPORT void proxyClientDelete( - const ProxyResult** proxyResult, uint64_t clientHandle); - -/** - * @brief Connect a proxy client to a list of proxies. - * - * @param proxyResult Pointer in which ProxyResult will be stored. You MUST call - * proxyClientResultDelete() on this after the call returns. - * @param clientHandle The client handle of the client to connect. - * @param proxies The array of proxies. - * @param numProxies The number of proxies. - * @return The number of proxies connected to. - */ - -EXTERN_C SHARED_EXPORT uint64_t proxyClientConnect( - const ProxyResult** proxyResult, - uint64_t clientHandle, - const Proxy* proxies, - uint64_t numProxies); - -/** - * @brief Disconnect a proxy client from all proxies. - * - * @param proxyResult Pointer in which ProxyResult will be stored. You MUST call - * proxyClientResultDelete() on this after the call returns. The resulting ProxyResult - * may only contain "errors" - the "successful" and "numSuccessful" fields are - * unused. - * @param clientHandle The client handle of the client to disconnect. - -EXTERN_C SHARED_EXPORT void proxyClientDisconnect( - const ProxyResult** proxyResult, uint64_t clientHandle); -*/ - -/** - * @brief Publish a message to the stream. - * - * @param proxyResult Pointer in which ProxyResult will be stored. You MUST call - * proxyClientResultDelete() on this after the call returns. - * @param clientHandle The client handle of the client to publish. - * @param content The content to publish. - * @param contentLength The length of the content. - * @param ethereumPrivateKey as hex without 0x prefix (64 characters) or NULL if - * message should not be signed. - * @return The number of proxies to which the message was published to. - */ - -EXTERN_C SHARED_EXPORT uint64_t proxyClientPublish( - const ProxyResult** proxyResult, - uint64_t clientHandle, - const char* content, - uint64_t contentLength, - const char* ethereumPrivateKey); - -#endif /* LIBSTREAMRPROXYCLIENT_H */ diff --git a/packages/streamr-libstreamrproxyclient/dist/arm64-osx/lib/Debug/libstreamrproxyclient.dylib b/packages/streamr-libstreamrproxyclient/dist/arm64-osx/lib/Debug/libstreamrproxyclient.dylib deleted file mode 120000 index 0ec27660..00000000 --- a/packages/streamr-libstreamrproxyclient/dist/arm64-osx/lib/Debug/libstreamrproxyclient.dylib +++ /dev/null @@ -1 +0,0 @@ -libstreamrproxyclient.1.dylib \ No newline at end of file diff --git a/packages/streamr-libstreamrproxyclient/dist/arm64-osx/lib/Release/libstreamrproxyclient.dylib b/packages/streamr-libstreamrproxyclient/dist/arm64-osx/lib/Release/libstreamrproxyclient.dylib deleted file mode 120000 index 0ec27660..00000000 --- a/packages/streamr-libstreamrproxyclient/dist/arm64-osx/lib/Release/libstreamrproxyclient.dylib +++ /dev/null @@ -1 +0,0 @@ -libstreamrproxyclient.1.dylib \ No newline at end of file diff --git a/packages/streamr-libstreamrproxyclient/examples/go/go.mod b/packages/streamr-libstreamrproxyclient/examples/go/go.mod index 20d2b45a..28934360 100644 --- a/packages/streamr-libstreamrproxyclient/examples/go/go.mod +++ b/packages/streamr-libstreamrproxyclient/examples/go/go.mod @@ -1,3 +1,5 @@ -module publisherexample +module example/proxypublisher go 1.23.2 + +require github.com/streamr-dev/goproxyclient v0.0.0-20241128110816-2e50ac3088da // indirect diff --git a/packages/streamr-libstreamrproxyclient/examples/go/go.sum b/packages/streamr-libstreamrproxyclient/examples/go/go.sum new file mode 100644 index 00000000..a6389cde --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/examples/go/go.sum @@ -0,0 +1,4 @@ +github.com/streamr-dev/goproxyclient v0.0.0-20241128103014-190db546a3bf h1:OMGnwVCFrKtqPjRxIfESubOYsmoT8ErkcjN/seGvqI8= +github.com/streamr-dev/goproxyclient v0.0.0-20241128103014-190db546a3bf/go.mod h1:QjfDePiUjNMT7nRvrTrR/ITgnojp7oTKqXKSIRU3J2I= +github.com/streamr-dev/goproxyclient v0.0.0-20241128110816-2e50ac3088da h1:mZHsuAJkA8fIZsX/uSQoOMmIOCPITyJmga80k20wMaQ= +github.com/streamr-dev/goproxyclient v0.0.0-20241128110816-2e50ac3088da/go.mod h1:QjfDePiUjNMT7nRvrTrR/ITgnojp7oTKqXKSIRU3J2I= diff --git a/packages/streamr-libstreamrproxyclient/examples/go/main.go b/packages/streamr-libstreamrproxyclient/examples/go/main.go deleted file mode 100644 index 8ab16d3f..00000000 --- a/packages/streamr-libstreamrproxyclient/examples/go/main.go +++ /dev/null @@ -1,91 +0,0 @@ -package main - -/* -#cgo LDFLAGS: -lstreamrproxyclient -#include "streamrproxyclient.h" -#include -*/ -import "C" -import ( - "fmt" - "os" - "time" - "unsafe" -) - -func generateRandomEthereumAddress() string { - const hexChars = "0123456789abcdef" - address := make([]byte, 42) - address[0] = '0' - address[1] = 'x' - for i := 2; i < 42; i++ { - address[i] = hexChars[C.rand()%16] - } - return string(address) -} - -func main() { - if len(os.Args) != 4 { - fmt.Fprintf(os.Stderr, "Usage: %s \n", os.Args[0]) - os.Exit(1) - } - proxyUrl := os.Args[1] - proxyServerEthereumAddress := os.Args[2] - streamPartId := os.Args[3] - - ownEthereumAddress := C.CString("0xa5374e3c19f15e1847881979dd0c6c9ffe846bd5") - ethereumPrivateKey := C.CString("23bead9b499af21c4c16e4511b3b6b08c3e22e76e0591f5ab5ba8d4c3a5b1820") - defer C.free(unsafe.Pointer(ownEthereumAddress)) - defer C.free(unsafe.Pointer(ethereumPrivateKey)) - - var errors *C.Error - var numErrors C.uint64_t - - clientHandle := C.proxyClientNew(&errors, &numErrors, ownEthereumAddress, C.CString(streamPartId)) - if numErrors != 0 || errors != nil { - fmt.Fprintf(os.Stderr, "Error creating proxy client\n") - os.Exit(1) - } - - proxy := C.Proxy{ - websocketUrl: C.CString(proxyUrl), - ethereumAddress: C.CString(proxyServerEthereumAddress), - } - defer C.free(unsafe.Pointer(proxy.websocketUrl)) - defer C.free(unsafe.Pointer(proxy.ethereumAddress)) - - C.proxyClientConnect(&errors, &numErrors, clientHandle, &proxy, 1) - if numErrors != 0 || errors != nil { - fmt.Fprintf(os.Stderr, "Error connecting to proxy\n") - os.Exit(1) - } - - message := "Hello from libstreamrproxyclient!" - - for { - fmt.Println("Publishing message") - numProxiesPublishedTo := C.proxyClientPublish( - &errors, - &numErrors, - clientHandle, - C.CString(message), - C.uint64_t(len(message)), - ethereumPrivateKey) - - if numErrors != 0 || errors != nil { - fmt.Fprintf(os.Stderr, "Error publishing message\n") - os.Exit(1) - } - - fmt.Printf("%s published message \"%s\" to %d proxies\n", C.GoString(ownEthereumAddress), message, numProxiesPublishedTo) - fmt.Println("Sleeping for 15 seconds") - time.Sleep(15 * time.Second) - fmt.Println("Sleeping done") - } - - C.proxyClientDelete(&errors, &numErrors, clientHandle) - if numErrors != 0 || errors != nil { - fmt.Fprintf(os.Stderr, "Error deleting proxy client\n") - os.Exit(1) - } -} diff --git a/packages/streamr-libstreamrproxyclient/examples/go/proxypublisher.go b/packages/streamr-libstreamrproxyclient/examples/go/proxypublisher.go new file mode 100644 index 00000000..6c92cfbd --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/examples/go/proxypublisher.go @@ -0,0 +1,60 @@ +package main + +import ( + "log" + + streamrproxyclient "github.com/streamr-dev/goproxyclient" +) + +func main() { + // This is a widely-used test account + ownEthereumAddress := + "0xa5374e3c19f15e1847881979dd0c6c9ffe846bd5"; + ethereumPrivateKey := + "23bead9b499af21c4c16e4511b3b6b08c3e22e76e0591f5ab5ba8d4c3a5b1820"; + + // A Proxy server run by Streamr + proxyUrl := "ws://95.216.15.80:44211" + proxyEthereumAddress := "0xd0d14b38d1f6b59d3772a63d84ece0a79e6e1c1f" + + // The stream to publish to + streamPartId := "0xd2078dc2d780029473a39ce873fc182587be69db/low-level-client#0" + + // Create a new library instance + lib := streamrproxyclient.NewLibStreamrProxyClient() + defer lib.Close() + + + // Create a new ProxyClient instance + client, err := streamrproxyclient.NewProxyClient(ownEthereumAddress, streamPartId) + if err != nil { + log.Fatalf("Error creating ProxyClient: %v", err) + } + defer client.Close() + + // Create definition of the proxy server to connect to + proxies := []streamrproxyclient.Proxy{ + *streamrproxyclient.NewProxy(proxyUrl, proxyEthereumAddress), + } + + // Connect to the proxy server + result := client.Connect(proxies) + if len(result.Errors) != 0 { + log.Fatalf("Errors during connection: %v", result.Errors) + } + if len(result.Successful) != 1 { + log.Fatalf("Unexpected number of successful connections: %d", len(result.Successful)) + } + + // Publish a message to the test stream + // You should see the result in the Streamr HUB web UI at + // https://streamr.network/hub/streams/0xd2078dc2d780029473a39ce873fc182587be69db%2Flow-level-client/live-data + data := []byte("Hello from Go!") + result = client.Publish(data, ethereumPrivateKey) + if len(result.Errors) != 0 { + log.Fatalf("Errors during publish: %v", result.Errors) + } + if len(result.Successful) != 1 { + log.Fatalf("Unexpected number of successful publishes: %d", len(result.Successful)) + } +} \ No newline at end of file diff --git a/packages/streamr-libstreamrproxyclient/examples/go/run.sh b/packages/streamr-libstreamrproxyclient/examples/go/run.sh index 6ef1916e..e066cf59 100755 --- a/packages/streamr-libstreamrproxyclient/examples/go/run.sh +++ b/packages/streamr-libstreamrproxyclient/examples/go/run.sh @@ -1,36 +1,3 @@ -#! /bin/bash +#!/bin/bash -BASE_DIR=$(pwd) - -if [[ "$OSTYPE" == "darwin"* ]] && [[ "$(uname -m)" == "arm64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/arm64-osx/lib/Debug) - export DYLD_LIBRARY_PATH=$LIB_PATH:$DYLD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi -if [[ "$OSTYPE" == "darwin"* ]] && [[ "$(uname -m)" == "x86_64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/x64-osx/lib/Debug) - export DYLD_LIBRARY_PATH=$LIB_PATH:$DYLD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi -if [[ "$OSTYPE" == "linux-gnu"* ]] && [[ "$(uname -m)" == "x86_64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/x64-linux/lib/Debug) - export LD_LIBRARY_PATH=$LIB_PATH:$LD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi -if [[ "$OSTYPE" == "linux-gnu"* ]] && [[ "$(uname -m)" == "aarch64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/arm64-linux/lib/Debug) - export LD_LIBRARY_PATH=$LIB_PATH:$LD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi - -set -e - -PROXY_URL="ws://95.216.15.80:44211" -PROXY_ETHEREUM_ADDRESS="0xd0d14b38d1f6b59d3772a63d84ece0a79e6e1c1f" - -STREAM_PART_ID="0xd2078dc2d780029473a39ce873fc182587be69db/low-level-client#0" - -echo "Running the publisher example with parameters: $PROXY_URL $PROXY_ETHEREUM_ADDRESS $STREAM_PART_ID" -# Run the publisher example with the proxy address - -go run . $PROXY_URL $PROXY_ETHEREUM_ADDRESS $STREAM_PART_ID +go run proxypublisher.go diff --git a/packages/streamr-libstreamrproxyclient/examples/go/streamrproxyclient.h b/packages/streamr-libstreamrproxyclient/examples/go/streamrproxyclient.h deleted file mode 120000 index eb517140..00000000 --- a/packages/streamr-libstreamrproxyclient/examples/go/streamrproxyclient.h +++ /dev/null @@ -1 +0,0 @@ -../../include/streamrproxyclient.h \ No newline at end of file diff --git a/packages/streamr-libstreamrproxyclient/examples/python/install.sh b/packages/streamr-libstreamrproxyclient/examples/python/install.sh new file mode 100755 index 00000000..42c81af7 --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/examples/python/install.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +python -m pip install -i https://test.pypi.org/project/simple/ libstreamrproxyclient --extra-index-url https://pypi.org/simple diff --git a/packages/streamr-libstreamrproxyclient/examples/python/proxypublisher.py b/packages/streamr-libstreamrproxyclient/examples/python/proxypublisher.py new file mode 100644 index 00000000..5b24611e --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/examples/python/proxypublisher.py @@ -0,0 +1,22 @@ +from streamrproxyclient.libstreamrproxyclient import ( + Proxy, + LibStreamrProxyClient, + ProxyClient +) + +proxy_ethereum_address = "0xd0d14b38d1f6b59d3772a63d84ece0a79e6e1c1f" +proxy_url = "ws://95.216.15.80:44211" +stream_part_id = "0xd2078dc2d780029473a39ce873fc182587be69db/low-level-client#0" +own_ethereum_address = "0xa5374e3c19f15e1847881979dd0c6c9ffe846bd5" +ethereum_private_key = "23bead9b499af21c4c16e4511b3b6b08c3e22e76e0591f5ab5ba8d4c3a5b1820" + + +with LibStreamrProxyClient() as lib: + with ProxyClient(lib, own_ethereum_address, stream_part_id) as client: + result = client.connect([Proxy(proxy_url, proxy_ethereum_address)]) + assert len(result.errors) == 0 + assert len(result.successful) == 1 + + result = client.publish(b"Hello from python!", ethereum_private_key) + assert len(result.errors) == 0 + assert len(result.successful) == 1 diff --git a/packages/streamr-libstreamrproxyclient/examples/python/publisherexample.py b/packages/streamr-libstreamrproxyclient/examples/python/publisherexample.py deleted file mode 100644 index 8cc75e74..00000000 --- a/packages/streamr-libstreamrproxyclient/examples/python/publisherexample.py +++ /dev/null @@ -1,71 +0,0 @@ -import ctypes -import time - -# Load the shared library -import platform - -if platform.system() == "Darwin": - lib = ctypes.CDLL('libstreamrproxyclient.dylib') -else: - lib = ctypes.CDLL('libstreamrproxyclient.so') - -# Define the necessary ctypes -class Error(ctypes.Structure): - pass - -class Proxy(ctypes.Structure): - _fields_ = [("websocketUrl", ctypes.c_char_p), - ("ethereumAddress", ctypes.c_char_p)] - -# Function prototypes -lib.proxyClientNew.restype = ctypes.c_uint64 -lib.proxyClientNew.argtypes = [ctypes.POINTER(ctypes.POINTER(Error)), ctypes.POINTER(ctypes.c_uint64), ctypes.c_char_p, ctypes.c_char_p] - -lib.proxyClientConnect.argtypes = [ctypes.POINTER(ctypes.POINTER(Error)), ctypes.POINTER(ctypes.c_uint64), ctypes.c_uint64, ctypes.POINTER(Proxy), ctypes.c_uint64] - -lib.proxyClientPublish.restype = ctypes.c_uint64 -lib.proxyClientPublish.argtypes = [ctypes.POINTER(ctypes.POINTER(Error)), ctypes.POINTER(ctypes.c_uint64), ctypes.c_uint64, ctypes.c_char_p, ctypes.c_size_t, ctypes.c_char_p] - -lib.proxyClientDelete.argtypes = [ctypes.POINTER(ctypes.POINTER(Error)), ctypes.POINTER(ctypes.c_uint64), ctypes.c_uint64] - -# Constants -proxyUrl = b"ws://95.216.15.80:44211" -proxyServerEthereumAddress = b"0xd0d14b38d1f6b59d3772a63d84ece0a79e6e1c1f" -streamPartId = b"0xd2078dc2d780029473a39ce873fc182587be69db/low-level-client#0" -ownEthereumAddress = b"0xa5374e3c19f15e1847881979dd0c6c9ffe846bd5" -ethereumPrivateKey = b"23bead9b499af21c4c16e4511b3b6b08c3e22e76e0591f5ab5ba8d4c3a5b1820" - -# Initialize error and numErrors -errors = ctypes.POINTER(Error)() -numErrors = ctypes.c_uint64(0) - -# Create client handle -clientHandle = lib.proxyClientNew(ctypes.byref(errors), ctypes.byref(numErrors), ownEthereumAddress, streamPartId) -assert numErrors.value == 0 -assert not errors - -# Create proxy -proxy = Proxy(websocketUrl=proxyUrl, ethereumAddress=proxyServerEthereumAddress) - -# Connect to proxy -lib.proxyClientConnect(ctypes.byref(errors), ctypes.byref(numErrors), clientHandle, ctypes.byref(proxy), 1) -assert numErrors.value == 0 -assert not errors - -message = b"Hello from libstreamrproxyclient!" - -while True: - print("Publishing message") - numProxiesPublishedTo = lib.proxyClientPublish(ctypes.byref(errors), ctypes.byref(numErrors), clientHandle, message, len(message), ethereumPrivateKey) - assert numErrors.value == 0 - assert not errors - - print(f"{ownEthereumAddress.decode()} published message \"{message.decode()}\" to {numProxiesPublishedTo} proxies") - print("Sleeping for 15 seconds") - time.sleep(15) - print("Sleeping done") - -# Delete client handle -lib.proxyClientDelete(ctypes.byref(errors), ctypes.byref(numErrors), clientHandle) -assert numErrors.value == 0 -assert not errors diff --git a/packages/streamr-libstreamrproxyclient/examples/python/run.sh b/packages/streamr-libstreamrproxyclient/examples/python/run.sh index a1ddfd1b..c4257ec5 100755 --- a/packages/streamr-libstreamrproxyclient/examples/python/run.sh +++ b/packages/streamr-libstreamrproxyclient/examples/python/run.sh @@ -1,32 +1,3 @@ #! /bin/bash -BASE_DIR=$(pwd) - -if [[ "$OSTYPE" == "darwin"* ]] && [[ "$(uname -m)" == "arm64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/arm64-osx/lib/Debug) - export DYLD_LIBRARY_PATH=$LIB_PATH:$DYLD_LIBRARY_PATH -fi -if [[ "$OSTYPE" == "darwin"* ]] && [[ "$(uname -m)" == "x86_64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/x64-osx/lib/Debug) - export DYLD_LIBRARY_PATH=$LIB_PATH:$DYLD_LIBRARY_PATH -fi -if [[ "$OSTYPE" == "linux-gnu"* ]] && [[ "$(uname -m)" == "x86_64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/x64-linux/lib/Debug) - export LD_LIBRARY_PATH=$LIB_PATH:$LD_LIBRARY_PATH -fi -if [[ "$OSTYPE" == "linux-gnu"* ]] && [[ "$(uname -m)" == "aarch64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/arm64-linux/lib/Debug) - export LD_LIBRARY_PATH=$LIB_PATH:$LD_LIBRARY_PATH -fi - -set -e - -PROXY_URL="ws://95.216.15.80:44211" -PROXY_ETHEREUM_ADDRESS="0xd0d14b38d1f6b59d3772a63d84ece0a79e6e1c1f" - -STREAM_PART_ID="0xd2078dc2d780029473a39ce873fc182587be69db/low-level-client#0" - -echo "Running the publisher example with parameters: $PROXY_URL $PROXY_ETHEREUM_ADDRESS $STREAM_PART_ID" -# Run the publisher example with the proxy address - -python3 publisherexample.py $PROXY_URL $PROXY_ETHEREUM_ADDRESS $STREAM_PART_ID +python proxypublisher.py \ No newline at end of file diff --git a/packages/streamr-libstreamrproxyclient/examples/unix/CMakeLists.txt b/packages/streamr-libstreamrproxyclient/examples/unix-c/CMakeLists.txt similarity index 82% rename from packages/streamr-libstreamrproxyclient/examples/unix/CMakeLists.txt rename to packages/streamr-libstreamrproxyclient/examples/unix-c/CMakeLists.txt index 6e4c8950..b210be26 100644 --- a/packages/streamr-libstreamrproxyclient/examples/unix/CMakeLists.txt +++ b/packages/streamr-libstreamrproxyclient/examples/unix-c/CMakeLists.txt @@ -1,9 +1,8 @@ cmake_minimum_required(VERSION 3.26) -project(streamrproxyclientexample CXX) +project(streamrproxyclientexample C) -set(CMAKE_BUILD_TYPE Debug) -set(CMAKE_CXX_STANDARD 26) +set(CMAKE_BUILD_TYPE Release) if(APPLE) if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") @@ -21,7 +20,7 @@ else() message(FATAL_ERROR "Unsupported platform") endif() -add_executable(publisherexample publisherexample.cpp) +add_executable(publisherexample publisherexample.c) target_include_directories(publisherexample PRIVATE ${CMAKE_SOURCE_DIR}/../../dist/${ARCH_DIR}/include) target_link_directories(publisherexample PRIVATE ${CMAKE_SOURCE_DIR}/../../dist/${ARCH_DIR}/lib/${CMAKE_BUILD_TYPE}) diff --git a/packages/streamr-libstreamrproxyclient/examples/unix-c/README.md b/packages/streamr-libstreamrproxyclient/examples/unix-c/README.md new file mode 100644 index 00000000..f8b36ee1 --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/examples/unix-c/README.md @@ -0,0 +1,27 @@ +# Libstreamrproxyclient C example app for Unix-like operating systems + +This is a simple example app that demonstrates how to use the libstreamrproxyclient shared library directly in the C language to publish messages to the Streamr network on Linux and macOS. The example app broadcasts a "Hello from libstreamrproxyclient!" message to a Streamr stream that can be viewed at https://streamr.network/hub/streams/0xd2078dc2d780029473a39ce873fc182587be69db%2Flow-level-client/live-data + +# Prerequisites + +- A recent version of CMake +- A recent C compiler (clang on macOS, gcc on Linux) + +# Building + +- Compile the native-sdk project to generate the libstreamrproxyclient shared library, or get the pre-compiled library from a Streamr Native SDK distribution bundle. By default, the CMakeLists.txt script will look for the library at '${CMAKE_SOURCE_DIR}/../../dist/${ARCH_DIR}/lib/${CMAKE_BUILD_TYPE})' + +```bash +./install.sh +``` + +# Running + +- To publish a message to the Streamr network, run the example app: + +```bash +./run.sh +```bash + +- You should be able to see the publised message in the Streamr Hub Web UI at https://streamr.network/hub/streams/0xd2078dc2d780029473a39ce873fc182587be69db%2Flow-level-client/live-data + diff --git a/packages/streamr-libstreamrproxyclient/examples/unix/build/.gitignore b/packages/streamr-libstreamrproxyclient/examples/unix-c/build/.gitignore similarity index 100% rename from packages/streamr-libstreamrproxyclient/examples/unix/build/.gitignore rename to packages/streamr-libstreamrproxyclient/examples/unix-c/build/.gitignore diff --git a/packages/streamr-libstreamrproxyclient/examples/unix/install.sh b/packages/streamr-libstreamrproxyclient/examples/unix-c/install.sh similarity index 100% rename from packages/streamr-libstreamrproxyclient/examples/unix/install.sh rename to packages/streamr-libstreamrproxyclient/examples/unix-c/install.sh diff --git a/packages/streamr-libstreamrproxyclient/examples/unix-c/publisherexample.c b/packages/streamr-libstreamrproxyclient/examples/unix-c/publisherexample.c new file mode 100644 index 00000000..8b3120f1 --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/examples/unix-c/publisherexample.c @@ -0,0 +1,66 @@ +// NOLINTBEGIN + +#include +#include +#include +#include +#include +#include +#include "streamrproxyclient.h" + +int main() { + + // This is a widely-used test account + const char* ownEthereumAddress = + "0xa5374e3c19f15e1847881979dd0c6c9ffe846bd5"; + const char* ethereumPrivateKey = + "23bead9b499af21c4c16e4511b3b6b08c3e22e76e0591f5ab5ba8d4c3a5b1820"; + + const char* proxyUrl = "ws://95.216.15.80:44211"; + const char* proxyServerEthereumAddress = "0xd0d14b38d1f6b59d3772a63d84ece0a79e6e1c1f"; + const char* streamPartId = "0xd2078dc2d780029473a39ce873fc182587be69db/low-level-client#0"; + + const ProxyResult* proxyResult = NULL; + + proxyClientInitLibrary(); + + uint64_t clientHandle = + proxyClientNew(&proxyResult, ownEthereumAddress, streamPartId); + + assert(proxyResult->numErrors == 0); + proxyClientResultDelete(proxyResult); + + Proxy proxy; + proxy.websocketUrl = proxyUrl; + proxy.ethereumAddress = proxyServerEthereumAddress; + + proxyClientConnect(&proxyResult, clientHandle, &proxy, 1); + + assert(proxyResult->numErrors == 0); + proxyClientResultDelete(proxyResult); + + const char* message = "Hello from libstreamrproxyclient!"; + + printf("Publishing message\n"); + uint64_t numProxiesPublishedTo = proxyClientPublish( + &proxyResult, + clientHandle, + message, + strlen(message), + ethereumPrivateKey); + + assert(proxyResult->numErrors == 0); + proxyClientResultDelete(proxyResult); + + printf("%s published message \"%s\" to %llu proxies\n", + ownEthereumAddress, message, numProxiesPublishedTo); + + proxyClientDelete(&proxyResult, clientHandle); + + assert(proxyResult->numErrors == 0); + proxyClientResultDelete(proxyResult); + + proxyClientCleanupLibrary(); + return 0; +} +// NOLINTEND \ No newline at end of file diff --git a/packages/streamr-libstreamrproxyclient/examples/unix-c/run.sh b/packages/streamr-libstreamrproxyclient/examples/unix-c/run.sh new file mode 100755 index 00000000..06496102 --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/examples/unix-c/run.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -e + +./build/publisherexample diff --git a/packages/streamr-libstreamrproxyclient/examples/unix-cpp/CMakeLists.txt b/packages/streamr-libstreamrproxyclient/examples/unix-cpp/CMakeLists.txt new file mode 100644 index 00000000..6ae0be4a --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/examples/unix-cpp/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.26) + +project(streamrproxyclientexample CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_BUILD_TYPE Release) + +if(APPLE) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + set(ARCH_DIR "arm64-osx") + else() + set(ARCH_DIR "x64-osx") + endif() +elseif(UNIX AND NOT APPLE) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") + set(ARCH_DIR "arm64-linux") + else() + set(ARCH_DIR "x64-linux") + endif() +else() + message(FATAL_ERROR "Unsupported platform") +endif() + +add_executable(publisherexample publisherexample.cpp) + +target_include_directories(publisherexample + PRIVATE ${CMAKE_SOURCE_DIR}/../../dist/${ARCH_DIR}/include + PRIVATE ${CMAKE_SOURCE_DIR}/../../wrappers/cpp/include) +target_link_directories(publisherexample PRIVATE ${CMAKE_SOURCE_DIR}/../../dist/${ARCH_DIR}/lib/${CMAKE_BUILD_TYPE}) +target_link_libraries(publisherexample streamrproxyclient) diff --git a/packages/streamr-libstreamrproxyclient/examples/unix-cpp/README.md b/packages/streamr-libstreamrproxyclient/examples/unix-cpp/README.md new file mode 100644 index 00000000..6c92f401 --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/examples/unix-cpp/README.md @@ -0,0 +1,27 @@ +# Libstreamrproxyclient C++ example app for Unix-like operating systems + +This is a simple example app that demonstrates how to use the libstreamrproxyclient shared library with the C++ wrapper to publish messages to the Streamr network on Linux and macOS. The example app broadcasts a "Hello from libstreamrproxyclient C++!" message to a Streamr stream that can be viewed at https://streamr.network/hub/streams/0xd2078dc2d780029473a39ce873fc182587be69db%2Flow-level-client/live-data + +# Prerequisites + +- A recent version of CMake +- A recent C++ compiler (clang++ on macOS, g++ on Linux) + +# Building + +- Compile the native-sdk project to generate the libstreamrproxyclient shared library, or get the pre-compiled library from a Streamr Native SDK distribution bundle. By default, the CMakeLists.txt script will look for the library at '${CMAKE_SOURCE_DIR}/../../dist/${ARCH_DIR}/lib/${CMAKE_BUILD_TYPE})' + +```bash +./install.sh +``` + +# Running + +- To publish a message to the Streamr network, run the example app: + +```bash +./run.sh +```bash + +- You should be able to see the publised message in the Streamr Hub Web UI at https://streamr.network/hub/streams/0xd2078dc2d780029473a39ce873fc182587be69db%2Flow-level-client/live-data + diff --git a/packages/streamr-libstreamrproxyclient/examples/unix-cpp/build/.gitignore b/packages/streamr-libstreamrproxyclient/examples/unix-cpp/build/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/examples/unix-cpp/build/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/packages/streamr-libstreamrproxyclient/examples/unix-cpp/install.sh b/packages/streamr-libstreamrproxyclient/examples/unix-cpp/install.sh new file mode 100755 index 00000000..abca0308 --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/examples/unix-cpp/install.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -e + +cd build && cmake .. && cmake --build . && cmake --install . && cd .. diff --git a/packages/streamr-libstreamrproxyclient/examples/unix-cpp/publisherexample.cpp b/packages/streamr-libstreamrproxyclient/examples/unix-cpp/publisherexample.cpp new file mode 100644 index 00000000..23fd58fe --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/examples/unix-cpp/publisherexample.cpp @@ -0,0 +1,43 @@ +#include +#include +#include +#include "StreamrProxyClient.hpp" + +int main() { + // This is a widely-used test account + const std::string ownEthereumAddress = + "0xa5374e3c19f15e1847881979dd0c6c9ffe846bd5"; + const std::string ethereumPrivateKey = + "23bead9b499af21c4c16e4511b3b6b08c3e22e76e0591f5ab5ba8d4c3a5b1820"; + const std::string streamPartId = + "0xd2078dc2d780029473a39ce873fc182587be69db/low-level-client#0"; + + try { + // Create client instance + streamrproxyclient::StreamrProxyClient client( + ownEthereumAddress, ethereumPrivateKey, streamPartId); + + // Connect to proxy + auto connectResult = client.connect( + {{.websocketUrl = "ws://95.216.15.80:44211", + .ethereumAddress = + "0xd0d14b38d1f6b59d3772a63d84ece0a79e6e1c1f"}}); + assert(connectResult.errors.empty()); + + // Publish message + const std::string message = "Hello from libstreamrproxyclient C++!"; + + auto publishResult = client.publish(message); + assert(publishResult.errors.empty()); + + std::cout << ownEthereumAddress << " published message \"" << message + << "\" to " << publishResult.successful.size() + << " proxies\n"; + + } catch (const streamrproxyclient::StreamrProxyError& e) { + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/packages/streamr-libstreamrproxyclient/examples/unix-cpp/run.sh b/packages/streamr-libstreamrproxyclient/examples/unix-cpp/run.sh new file mode 100755 index 00000000..06496102 --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/examples/unix-cpp/run.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -e + +./build/publisherexample diff --git a/packages/streamr-libstreamrproxyclient/examples/unix/README.md b/packages/streamr-libstreamrproxyclient/examples/unix/README.md deleted file mode 100644 index 521c452c..00000000 --- a/packages/streamr-libstreamrproxyclient/examples/unix/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Libstreamrproxyclient example app for Unix-like operating systems - -This is a simple example app that demonstrates how to use the libstreamrproxyclient library to publish messages to the Streamr network on Linux and macOS. The exaple app broadcasts a "Hello World" message to the local proxy server every 15 seconds. ***As the local proxy server uses a private entrypoint running in the cloud to join a private Streamr Network, you will not be able to see the messages in the Streamr production Network, but you can see the messages on other computers that have joined the same private network.*** - -# Prerequisites - -- A recent version of CMake -- A recent C++ compiler (clang++ on macOS, g++ on Linux) - -***Note: you do not need to build the Streamr Native SDK to build this example app. The pre-compiled libstreamrproxyclient library is included in the Streamr Native SDK distribution bundle.*** - -# Building - -```bash -./install.sh -``` - -The CMake build system will link the example app against the correct pre-compiled libstreamrproxyclient library for your target platform. - -# Running - -Open the directory `native-sdk/packages/streamr-trackerless-network/test/integration/ts-integration/` in another terminal window, install and run the streamr proxy server: - -```bash -./install.sh -./run.sh -```bash - -Run the example app and see the messages in the proxy server console. - -```bash -./run.sh -``` - -You can also run the proxy server on another computer at the same time to see the Streamr Network propagating the messages. diff --git a/packages/streamr-libstreamrproxyclient/examples/unix/publisherexample.cpp b/packages/streamr-libstreamrproxyclient/examples/unix/publisherexample.cpp deleted file mode 100644 index d96c1f1c..00000000 --- a/packages/streamr-libstreamrproxyclient/examples/unix/publisherexample.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "streamrproxyclient.h" - -std::string generateRandomEthereumAddress() { - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<> dis(0, 15); // NOLINT - - std::stringstream ss; - ss << "0x"; - for (int i = 0; i < 40; ++i) { // NOLINT - ss << std::hex << dis(gen); - } - return ss.str(); -} - -int main(int argc, char* argv[]) { - if (argc != 4) { - std::cerr << "Usage: " << argv[0] << " " - << " " - << " " - << "\n"; - return 1; - } - const char* proxyUrl = argv[1]; - const char* proxyServerEthereumAddress = argv[2]; - const char* streamPartId = argv[3]; - - // This is a widely-used test account - - const char* ownEthereumAddress = - "0xa5374e3c19f15e1847881979dd0c6c9ffe846bd5"; - const char* ehereumPrivateKey = - "23bead9b499af21c4c16e4511b3b6b08c3e22e76e0591f5ab5ba8d4c3a5b1820"; - - Error* errors = nullptr; - uint64_t numErrors = 0; - - uint64_t clientHandle = - proxyClientNew(&errors, &numErrors, ownEthereumAddress, streamPartId); - - assert(numErrors == 0); - assert(errors == nullptr); - - Proxy proxy{ - .websocketUrl = proxyUrl, - .ethereumAddress = proxyServerEthereumAddress}; - - proxyClientConnect(&errors, &numErrors, clientHandle, &proxy, 1); - - assert(numErrors == 0); - assert(errors == nullptr); - - std::string message = "Hello from libstreamrproxyclient!"; - - while (true) { - std::cout << "Publishing message" - << "\n"; - uint64_t numProxiesPublishedTo = proxyClientPublish( - &errors, - &numErrors, - clientHandle, - message.c_str(), - message.length(), - ehereumPrivateKey); - - assert(numErrors == 0); - assert(errors == nullptr); - - std::cout << ownEthereumAddress << " published message " - << "\"" << message << "\"" - << " to " << numProxiesPublishedTo << " proxies" - << "\n"; - std::cout << "Sleeping for 15 seconds" - << "\n"; - std::this_thread::sleep_for(std::chrono::seconds(15)); // NOLINT - std::cout << "Sleeping done" - << "\n"; - } - - proxyClientDelete(&errors, &numErrors, clientHandle); - - assert(numErrors == 0); - assert(errors == nullptr); - - return 0; -} diff --git a/packages/streamr-libstreamrproxyclient/examples/unix/run.sh b/packages/streamr-libstreamrproxyclient/examples/unix/run.sh deleted file mode 100755 index 1b094cbb..00000000 --- a/packages/streamr-libstreamrproxyclient/examples/unix/run.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -set -e - -PROXY_URL="ws://95.216.15.80:44211" -PROXY_ETHEREUM_ADDRESS="0xd0d14b38d1f6b59d3772a63d84ece0a79e6e1c1f" - -STREAM_PART_ID="0xd2078dc2d780029473a39ce873fc182587be69db/low-level-client#0" - -echo "Running the publisher example: ./build/publisherexample $PROXY_URL $PROXY_ETHEREUM_ADDRESS $STREAM_PART_ID" -# Run the publisher example with the proxy address -./build/publisherexample $PROXY_URL $PROXY_ETHEREUM_ADDRESS $STREAM_PART_ID diff --git a/packages/streamr-libstreamrproxyclient/include/StreamrProxyClient.hpp b/packages/streamr-libstreamrproxyclient/include/StreamrProxyClient.hpp deleted file mode 100644 index 59522bd8..00000000 --- a/packages/streamr-libstreamrproxyclient/include/StreamrProxyClient.hpp +++ /dev/null @@ -1,218 +0,0 @@ -#ifndef StreamrProxyClient_hpp -#define StreamrProxyClient_hpp - -#include -#include -#include -#include -#include "streamrproxyclient.h" - -namespace streamr::libstreamrproxyclient { - -enum class StreamrProxyErrorCode { - INVALID_ETHEREUM_ADDRESS, - INVALID_STREAM_PART_ID, - INVALID_PROXY_URL, - NO_PROXIES_DEFINED, - PROXY_CONNECTION_FAILED, - UNKNOWN_ERROR // Always good to have an unknown error state -}; - -class Err : public std::runtime_error { -public: - StreamrProxyErrorCode code; // NOLINT - std::string message; // NOLINT - - Err(StreamrProxyErrorCode code, std::string message) - : runtime_error(message), code(code), message(std::move(message)) {} -}; - -struct InvalidEthereumAddress : public Err { - explicit InvalidEthereumAddress(const std::string& message) - : Err(StreamrProxyErrorCode::INVALID_ETHEREUM_ADDRESS, message) {} -}; - -struct InvalidStreamPartId : public Err { - explicit InvalidStreamPartId(const std::string& message) - : Err(StreamrProxyErrorCode::INVALID_STREAM_PART_ID, message) {} -}; - -struct InvalidProxyUrl : public Err { - explicit InvalidProxyUrl(const std::string& message) - : Err(StreamrProxyErrorCode::INVALID_PROXY_URL, message) {} -}; - -struct NoProxiesDefined : public Err { - explicit NoProxiesDefined(const std::string& message) - : Err(StreamrProxyErrorCode::NO_PROXIES_DEFINED, message) {} -}; - -struct ProxyConnectionFailed : public Err { - explicit ProxyConnectionFailed(const std::string& message) - : Err(StreamrProxyErrorCode::PROXY_CONNECTION_FAILED, message) {} -}; - -struct StreamrProxyAddress { - std::string websocketUrl; - std::string ethereumAddress; -}; - -struct StreamrProxyError { - std::string message; - StreamrProxyErrorCode code; - StreamrProxyAddress proxy; -}; - -struct StreamrProxyResult { - uint64_t numConnected; // Number of successfully connected proxies - std::vector successful; - std::vector failed; -}; - -// Helper function to convert C error codes (strings) to C++ enum -inline StreamrProxyErrorCode convertErrorCode(const char* cErrorCode) { - static const std::unordered_map - ErrorMap = { - {ERROR_INVALID_ETHEREUM_ADDRESS, - StreamrProxyErrorCode::INVALID_ETHEREUM_ADDRESS}, - {ERROR_INVALID_STREAM_PART_ID, - StreamrProxyErrorCode::INVALID_STREAM_PART_ID}, - {ERROR_INVALID_PROXY_URL, StreamrProxyErrorCode::INVALID_PROXY_URL}, - {ERROR_NO_PROXIES_DEFINED, - StreamrProxyErrorCode::NO_PROXIES_DEFINED}, - {ERROR_PROXY_CONNECTION_FAILED, - StreamrProxyErrorCode::PROXY_CONNECTION_FAILED}}; - - if (cErrorCode == nullptr) { - return StreamrProxyErrorCode::UNKNOWN_ERROR; - } - - auto it = ErrorMap.find(cErrorCode); - return it != ErrorMap.end() ? it->second - : StreamrProxyErrorCode::UNKNOWN_ERROR; -} - -// Convert from C Proxy to C++ StreamrProxyAddress -inline StreamrProxyAddress convertProxyAddress(const Proxy& cProxy) { - return StreamrProxyAddress{ - std::string(cProxy.websocketUrl), std::string(cProxy.ethereumAddress)}; -} - -inline StreamrProxyError convertError(const Error& cError) { - return StreamrProxyError{ - std::string(cError.message), - convertErrorCode(cError.code), - convertProxyAddress(*cError.proxy)}; -} - -static StreamrProxyResult convertToStreamrResult( - const ProxyResult* proxyResult, uint64_t numSuccess) { - StreamrProxyResult streamrResult; - streamrResult.numConnected = numSuccess; - - if (proxyResult != nullptr) { - // Handle successful operations - for (size_t i = 0; i < proxyResult->numSuccessful; i++) { - streamrResult.successful.push_back( - convertProxyAddress(proxyResult->successful[i])); - } - - // Handle errors - for (size_t i = 0; i < proxyResult->numErrors; i++) { - streamrResult.failed.push_back( - convertError(proxyResult->errors[i])); - } - - proxyClientResultDelete(proxyResult); - } - - return streamrResult; -} - -class StreamrProxyClient { -private: - uint64_t clientHandle; - -public: - StreamrProxyClient( - const std::string& ownEthereumAddress, - const std::string& streamPartId) { - const ProxyResult* proxyResult = nullptr; - this->clientHandle = proxyClientNew( - &proxyResult, ownEthereumAddress.c_str(), streamPartId.c_str()); - - if (proxyResult != nullptr && proxyResult->numErrors > 0) { - std::string errorMessage = proxyResult->errors[0].message; - StreamrProxyErrorCode errorCode = - convertErrorCode(proxyResult->errors[0].code); - proxyClientResultDelete(proxyResult); - - // Throw appropriate exception based on error code - switch (errorCode) { - case StreamrProxyErrorCode::INVALID_ETHEREUM_ADDRESS: - throw InvalidEthereumAddress(errorMessage); - case StreamrProxyErrorCode::INVALID_STREAM_PART_ID: - throw InvalidStreamPartId(errorMessage); - default: - throw Err(errorCode, errorMessage); - } - } - - proxyClientResultDelete(proxyResult); - } - - ~StreamrProxyClient() noexcept { - const ProxyResult* proxyResult = nullptr; - proxyClientDelete(&proxyResult, this->clientHandle); - proxyClientResultDelete(proxyResult); - } - - [[nodiscard]] StreamrProxyResult connect( - const std::vector& proxies) const { - const ProxyResult* proxyResult = nullptr; - StreamrProxyResult streamrResult; - - // Handle empty proxy list case first - if (proxies.empty()) { - streamrResult.numConnected = 0; - streamrResult.failed.push_back(StreamrProxyError{ - "No proxies defined", - StreamrProxyErrorCode::NO_PROXIES_DEFINED, - StreamrProxyAddress{} // Empty proxy address - }); - return streamrResult; - } - // Convert C++ proxy addresses to C structure - std::vector cProxies; - cProxies.reserve(proxies.size()); - - for (const auto& proxy : proxies) { - cProxies.push_back(Proxy{ - proxy.websocketUrl.c_str(), proxy.ethereumAddress.c_str()}); - } - - uint64_t numConnected = proxyClientConnect( - &proxyResult, this->clientHandle, cProxies.data(), cProxies.size()); - - return convertToStreamrResult(proxyResult, numConnected); - } - - [[nodiscard]] StreamrProxyResult publish( - const std::string& content, - const std::string& ethereumPrivateKey) const { - const ProxyResult* proxyResult = nullptr; - - uint64_t numPublished = proxyClientPublish( - &proxyResult, - this->clientHandle, - content.c_str(), - content.length(), - ethereumPrivateKey.c_str()); - - return convertToStreamrResult(proxyResult, numPublished); - } -}; - -} // namespace streamr::libstreamrproxyclient - -#endif /* StreamrProxyClient_hpp */ diff --git a/packages/streamr-libstreamrproxyclient/include/streamrproxyclient.h b/packages/streamr-libstreamrproxyclient/include/streamrproxyclient.h index b28c146c..63bb408f 100644 --- a/packages/streamr-libstreamrproxyclient/include/streamrproxyclient.h +++ b/packages/streamr-libstreamrproxyclient/include/streamrproxyclient.h @@ -48,6 +48,8 @@ EXTERN_C SHARED_EXPORT void proxyClientInitLibrary(void); */ // NOLINTNEXTLINE EXTERN_C SHARED_EXPORT void proxyClientCleanupLibrary(void); + + // NOLINTNEXTLINE typedef struct Proxy { const char* websocketUrl; diff --git a/packages/streamr-libstreamrproxyclient/run-ts-end-to-end-cpp-tests.sh b/packages/streamr-libstreamrproxyclient/run-ts-end-to-end-cpp-tests.sh deleted file mode 100755 index 152fce0d..00000000 --- a/packages/streamr-libstreamrproxyclient/run-ts-end-to-end-cpp-tests.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -set -e - -#Install the server -cd ../streamr-trackerless-network/test/integration/ts-integration -./install.sh - - -#Run the server - -./run-server-for-tests.sh - -cd - - -#Run the tests -EXPECTED_OUTPUT="Received message: Hello from libstreamrproxyclient!" -LOG_LEVEL=trace ./build/streamr-streamrproxyclient-test-end-to-end --gtest_filter=PublishToTsServerCppTest.ProxyPublish - -# Check if the server log contains the desired output -if grep -q "$EXPECTED_OUTPUT" ../streamr-trackerless-network/test/integration/ts-integration/output.log; then - echo "Server received the expected message: $EXPECTED_OUTPUT" -else - echo "Error: Server did not output the expected message." - kill $(cat ../streamr-trackerless-network/test/integration/ts-integration/server.pid) - exit 1 -fi - -#Kill the server - -kill $(cat ../streamr-trackerless-network/test/integration/ts-integration/server.pid) -exit 0 diff --git a/packages/streamr-libstreamrproxyclient/run-ts-multiple-messages-cpp-test.sh b/packages/streamr-libstreamrproxyclient/run-ts-multiple-messages-cpp-test.sh deleted file mode 100755 index 0669c9c9..00000000 --- a/packages/streamr-libstreamrproxyclient/run-ts-multiple-messages-cpp-test.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash - -set -e - -#Install the server -cd ../streamr-trackerless-network/test/integration/ts-integration -./install.sh - - -#Run the server - -./run-server-for-tests.sh - -cd - - -#Run the tests -EXPECTED_OUTPUT="Received message: Hello from libstreamrproxyclient! m1" -EXPECTED_OUTPUT_2="Received message: Hello from libstreamrproxyclient! m2" -EXPECTED_OUTPUT_3="Received message: Hello from libstreamrproxyclient! m3" - -LOG_LEVEL=trace ./build/streamr-streamrproxyclient-test-end-to-end --gtest_filter=PublishToTsServerCppTest.ProxyPublishMultipleMessages - -# Check if the server log contains the desired outputs -if grep -q "$EXPECTED_OUTPUT" ../streamr-trackerless-network/test/integration/ts-integration/output.log && \ - grep -q "$EXPECTED_OUTPUT_2" ../streamr-trackerless-network/test/integration/ts-integration/output.log && \ - grep -q "$EXPECTED_OUTPUT_3" ../streamr-trackerless-network/test/integration/ts-integration/output.log; then - echo "Server received the expected messages: $EXPECTED_OUTPUT, $EXPECTED_OUTPUT_2, $EXPECTED_OUTPUT_3" -else - echo "Error: Server did not output the expected message." - kill $(cat ../streamr-trackerless-network/test/integration/ts-integration/server.pid) - exit 1 -fi - -#Kill the server - -kill $(cat ../streamr-trackerless-network/test/integration/ts-integration/server.pid) -exit 0 diff --git a/packages/streamr-libstreamrproxyclient/test/end-to-end/PublishToTsServerCppTest.cpp b/packages/streamr-libstreamrproxyclient/test/end-to-end/PublishToTsServerCppTest.cpp deleted file mode 100644 index bcc2f88b..00000000 --- a/packages/streamr-libstreamrproxyclient/test/end-to-end/PublishToTsServerCppTest.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include -#include "StreamrProxyClient.hpp" - -using streamr::libstreamrproxyclient::StreamrProxyAddress; -using streamr::libstreamrproxyclient::StreamrProxyClient; - -class PublishToTsServerCppTest : public ::testing::Test { -protected: - static constexpr const char* ownEthereumAddress = - "0x1234567890123456789012345678901234567890"; - - static constexpr const char* tsEthereumAddress = - "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - static constexpr const char* tsProxyUrl = "ws://127.0.0.1:44211"; - static constexpr const char* tsStreamPartId = - "0xa000000000000000000000000000000000000000#01"; -}; - -TEST_F(PublishToTsServerCppTest, ProxyPublish) noexcept(false) { - // Create client - StreamrProxyClient client(ownEthereumAddress, tsStreamPartId); - // Connect to proxy - std::vector proxies = { - StreamrProxyAddress{tsProxyUrl, tsEthereumAddress}}; - - auto connectResult = client.connect(proxies); - EXPECT_EQ(connectResult.failed.size(), 0); - EXPECT_EQ(connectResult.numConnected, 1); - - // Publish message - std::string message = "Hello from libstreamrproxyclient!"; - auto publishResult = client.publish(message, ""); - // Verify publish results - EXPECT_EQ(publishResult.failed.size(), 0); - EXPECT_EQ(publishResult.numConnected, 1); -} - -TEST_F(PublishToTsServerCppTest, ProxyPublishMultipleMessages) noexcept(false) { - // Create client - StreamrProxyClient client(ownEthereumAddress, tsStreamPartId); - - // Connect to proxy - std::vector proxies = { - StreamrProxyAddress{tsProxyUrl, tsEthereumAddress}}; - - auto connectResult = client.connect(proxies); - EXPECT_EQ(connectResult.failed.size(), 0); - EXPECT_GT(connectResult.numConnected, 0); - - // Publish multiple messages - std::vector messages = { - "Hello from libstreamrproxyclient! m1", - "Hello from libstreamrproxyclient! m2", - "Hello from libstreamrproxyclient! m3"}; - - // Publish each message and verify results - for (const auto& message : messages) { - auto publishResult = client.publish(message, ""); - - // Verify publish results - EXPECT_EQ(publishResult.failed.size(), 0) - << "Failed to publish message: " << message; - EXPECT_GT(publishResult.numConnected, 0) - << "No successful publish for message: " << message; - } -} diff --git a/packages/streamr-libstreamrproxyclient/test/integration/StreamrProxyClientCppTest.cpp b/packages/streamr-libstreamrproxyclient/test/integration/StreamrProxyClientCppTest.cpp deleted file mode 100644 index 84696a37..00000000 --- a/packages/streamr-libstreamrproxyclient/test/integration/StreamrProxyClientCppTest.cpp +++ /dev/null @@ -1,196 +0,0 @@ -#include -#include -#include "StreamrProxyClient.hpp" - -using streamr::libstreamrproxyclient::Err; -using streamr::libstreamrproxyclient::InvalidEthereumAddress; -using streamr::libstreamrproxyclient::InvalidStreamPartId; -using streamr::libstreamrproxyclient::StreamrProxyAddress; -using streamr::libstreamrproxyclient::StreamrProxyClient; -using streamr::libstreamrproxyclient::StreamrProxyErrorCode; -using streamr::libstreamrproxyclient::StreamrProxyResult; - -class StreamrProxyClientCppTest : public ::testing::Test { -protected: - static constexpr const char* proxyWebsocketUrl = "ws://95.216.15.80:44211"; - static constexpr const char* proxyEthereumAddress = - "0xd0d14b38d1f6b59d3772a63d84ece0a79e6e1c1f"; - static constexpr const char* validStreamPartId2 = - "0xd2078dc2d780029473a39ce873fc182587be69db/low-level-client#0"; - static constexpr const char* invalidEthereumAddress = - "INVALID_ETHEREUM_ADDRESS"; - static constexpr const char* goodEthereumAddress = - "0x123456789012345678901234567890123456789a"; - static constexpr const char* validEthereumAddress = - "0x1234567890123456789012345678901234567890"; - static constexpr const char* validEthereumAddress2 = - "0x1234567890123456789012345678901234567892"; - static constexpr const char* validEthereumAddress3 = - "0x1234567890123456789012345678901234567893"; - static constexpr const char* invalidStreamPartId = "INVALID_STREAM_PART_ID"; - static constexpr const char* validStreamPartId = - "0xa000000000000000000000000000000000000000#01"; - - static constexpr const char* invalidProxyUrl = "poiejrg039utg240"; - static constexpr const char* validProxyUrl = "ws://valid.com"; - - static constexpr const char* nonExistentProxyUrl0 = "ws://localhost:0"; - static constexpr const char* nonExistentProxyUrl1 = "ws://localhost:1"; - static constexpr const char* nonExistentProxyUrl2 = "ws://localhost:2"; - - static constexpr uint64_t invalidClientHandle = 0; - - static void verifyFailed( - const StreamrProxyResult& result, StreamrProxyErrorCode expectedError) { - // Basic result validation - EXPECT_EQ(result.numConnected, 0); - EXPECT_EQ(result.successful.size(), 0); - EXPECT_EQ(result.failed.size(), 1); - - // Error validation - const auto& error = result.failed[0]; - EXPECT_EQ(error.code, expectedError); - } - - static std::vector createProxyArrayFromProxy( - const std::string& websocketUrl, const std::string& ethereumAddress) { - return {StreamrProxyAddress{websocketUrl, ethereumAddress}}; - } - - static StreamrProxyResult createClientAndConnect( - StreamrProxyClient& client, - std::optional websocketUrl = std::nullopt, - std::optional ethereumAddress = std::nullopt) { - std::vector proxies; - if (websocketUrl && ethereumAddress) { - proxies = - createProxyArrayFromProxy(*websocketUrl, *ethereumAddress); - } - - return client.connect(proxies); - } - - static void createClientConnectAndVerify( - const std::string& websocketUrl, - const std::string& ethereumAddress, - StreamrProxyErrorCode expectedError) { - StreamrProxyClient client(validEthereumAddress, validStreamPartId); - StreamrProxyResult result = createClientAndConnect( - client, std::string(websocketUrl), std::string(ethereumAddress)); - - verifyFailed(result, expectedError); - } - - static void tryToCreateClientWhichFails( - const std::string& ownEthereumAddress, - const std::string& streamPartId, - StreamrProxyErrorCode expectedError) { - try { - StreamrProxyClient client(ownEthereumAddress, streamPartId); - FAIL() << "Expected exception with error code: " - << static_cast(expectedError); - } catch (const InvalidEthereumAddress& e) { - EXPECT_EQ(e.code, expectedError); - EXPECT_FALSE(e.message.empty()); - } catch (const InvalidStreamPartId& e) { - EXPECT_EQ(e.code, expectedError); - EXPECT_FALSE(e.message.empty()); - } catch (const Err& e) { - EXPECT_EQ(e.code, expectedError); - EXPECT_FALSE(e.message.empty()); - } - } -}; - -TEST_F(StreamrProxyClientCppTest, CanCreateAndDeleteProxyClient) { - StreamrProxyClient client(validEthereumAddress, validStreamPartId); -} - -TEST_F(StreamrProxyClientCppTest, InvalidEthereumAddress) { - tryToCreateClientWhichFails( - invalidEthereumAddress, - validStreamPartId, - StreamrProxyErrorCode::INVALID_ETHEREUM_ADDRESS); -} - -TEST_F(StreamrProxyClientCppTest, InvalidStreamPartId) { - tryToCreateClientWhichFails( - validEthereumAddress, - invalidStreamPartId, - StreamrProxyErrorCode::INVALID_STREAM_PART_ID); -} - -TEST_F(StreamrProxyClientCppTest, InvalidProxyUrl) { - createClientConnectAndVerify( - invalidProxyUrl, - validEthereumAddress, - StreamrProxyErrorCode::INVALID_PROXY_URL); -} - -TEST_F(StreamrProxyClientCppTest, NoProxiesDefined) { - StreamrProxyClient client(validEthereumAddress, validStreamPartId); - StreamrProxyResult result = createClientAndConnect(client); - verifyFailed(result, StreamrProxyErrorCode::NO_PROXIES_DEFINED); -} - -TEST_F(StreamrProxyClientCppTest, InvalidProxyEthereumAddress) { - createClientConnectAndVerify( - validProxyUrl, - invalidEthereumAddress, - StreamrProxyErrorCode::INVALID_ETHEREUM_ADDRESS); -} - -TEST_F(StreamrProxyClientCppTest, ProxyConnectionFailed) { - createClientConnectAndVerify( - nonExistentProxyUrl0, - validEthereumAddress, - StreamrProxyErrorCode::PROXY_CONNECTION_FAILED); -} - -TEST_F(StreamrProxyClientCppTest, ThreeProxyConnectionsFailed) { - StreamrProxyClient client(goodEthereumAddress, validStreamPartId); - - std::vector proxies = { - StreamrProxyAddress{nonExistentProxyUrl0, validEthereumAddress}, - StreamrProxyAddress{nonExistentProxyUrl1, validEthereumAddress2}, - StreamrProxyAddress{nonExistentProxyUrl2, validEthereumAddress3}}; - - StreamrProxyResult result = client.connect(proxies); - - EXPECT_EQ(result.numConnected, 0); - EXPECT_TRUE(result.successful.empty()); - EXPECT_EQ(result.failed.size(), 3); - - // Verify that errors match the original proxies - EXPECT_EQ(result.failed[0].proxy.websocketUrl, proxies[0].websocketUrl); - EXPECT_EQ(result.failed[1].proxy.websocketUrl, proxies[1].websocketUrl); - EXPECT_EQ(result.failed[2].proxy.websocketUrl, proxies[2].websocketUrl); - - for (const auto& error : result.failed) { - EXPECT_EQ(error.code, StreamrProxyErrorCode::PROXY_CONNECTION_FAILED); - EXPECT_FALSE(error.message.empty()); - } -} - -TEST_F(StreamrProxyClientCppTest, ConnectSuccessfully) { - StreamrProxyClient client(validEthereumAddress, validStreamPartId2); - - StreamrProxyResult result = createClientAndConnect( - client, - std::string(proxyWebsocketUrl), - std::string(proxyEthereumAddress)); - - EXPECT_EQ(result.numConnected, 1); - EXPECT_FALSE(result.successful.empty()); - EXPECT_EQ(result.failed.size(), 0); - - const auto& successfulProxy = result.successful[0]; - EXPECT_EQ(successfulProxy.websocketUrl, proxyWebsocketUrl); - EXPECT_EQ(successfulProxy.ethereumAddress, proxyEthereumAddress); -} - -TEST_F(StreamrProxyClientCppTest, ProxyPublishWithoutConnection) { - StreamrProxyClient client(validEthereumAddress, validStreamPartId2); - auto publishResult = client.publish("abc", ""); - EXPECT_EQ(publishResult.numConnected, 0); -} \ No newline at end of file diff --git a/packages/streamr-libstreamrproxyclient/test/integration/StreamrProxyClientTest.cpp b/packages/streamr-libstreamrproxyclient/test/integration/StreamrProxyClientTest.cpp index dc14dca0..82528441 100644 --- a/packages/streamr-libstreamrproxyclient/test/integration/StreamrProxyClientTest.cpp +++ b/packages/streamr-libstreamrproxyclient/test/integration/StreamrProxyClientTest.cpp @@ -216,6 +216,7 @@ TEST_F(StreamrProxyClientTest, ThreeProxyConnectionsFailed) { proxyClientNew(&result, ownEthereumAddress, streamPartId); proxyClientResultDelete(result); + // NOLINTNEXTLINE Proxy proxies[] = { {.websocketUrl = nonExistentProxyUrl0, diff --git a/packages/streamr-libstreamrproxyclient/wrappers/cpp/README.md b/packages/streamr-libstreamrproxyclient/wrappers/cpp/README.md new file mode 100644 index 00000000..d346f97a --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/wrappers/cpp/README.md @@ -0,0 +1,145 @@ +# Streamr Proxy Client C++ Wrapper + +This is a C++ wrapper for the Streamr Proxy Client library. + +## Installation and usage + +* Obtain the Streamr Proxy Client shared library by building the [native-sdk](https://github.com/streamr-dev/native-sdk) project or by downloading the pre-built library from the [Streamr Proxy Client Releases](https://github.com/streamr-dev/native-sdk/releases) page. + +* Open the shared library by linking it to your project or by loading it dynamically at runtime using `dlopen` + +* Include the StreamrProxyClient.hpp header file in your project. + +* See [../../examples/unix-cpp](../../examples/unix-cpp) for a complete example project. + +### Publishing a message +```cpp +#include +#include +#include +#include "StreamrProxyClient.hpp" + +int main() { + // This is a widely-used test account + const std::string ownEthereumAddress = + "0xa5374e3c19f15e1847881979dd0c6c9ffe846bd5"; + const std::string ethereumPrivateKey = + "23bead9b499af21c4c16e4511b3b6b08c3e22e76e0591f5ab5ba8d4c3a5b1820"; + const std::string streamPartId = + "0xd2078dc2d780029473a39ce873fc182587be69db/low-level-client#0"; + + try { + // Create client instance + streamrproxyclient::StreamrProxyClient client( + ownEthereumAddress, ethereumPrivateKey, streamPartId); + + // Connect to proxy + auto connectResult = client.connect( + {{.websocketUrl = "ws://95.216.15.80:44211", + .ethereumAddress = + "0xd0d14b38d1f6b59d3772a63d84ece0a79e6e1c1f"}}); + assert(connectResult.errors.empty()); + + // Publish message + const std::string message = "Hello from libstreamrproxyclient C++!"; + + auto publishResult = client.publish(message); + assert(publishResult.errors.empty()); + + std::cout << ownEthereumAddress << " published message \"" << message + << "\" to " << publishResult.successful.size() + << " proxies\n"; + + } catch (const streamrproxyclient::StreamrProxyError& e) { + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } + + return 0; +} +``` +## API Documentation + +### StreamrProxyClient Class + +Main client class for interacting with Streamr proxies. + +#### Constructor +```cpp +StreamrProxyClient( + const std::string& ownEthereumAddress, + const std::string& ethereumPrivateKey, + const std::string& streamPartId) +``` +Creates a new StreamrProxyClient instance. + +Parameters: +- `ownEthereumAddress` - Ethereum address of the client +- `ethereumPrivateKey` - Private key for the Ethereum address +- `streamPartId` - Stream part ID + +Throws: `StreamrProxyError` if client creation fails + +#### Methods + +##### connect() +```cpp +StreamrProxyResult connect(const std::vector& proxies) +``` +Connects to specified proxies. + +Parameters: +- `proxies` - Vector of proxy addresses to connect to + +Returns: Result containing the proxies that the operation was successful on and the errors that occurred during the operation + +##### publish() +```cpp +StreamrProxyResult publish(const std::string& message) +``` +Publishes a message through connected proxies. + +Parameters: +- `message` - Message to publish + +Returns: Result containing the proxies that the operation was successful on and the errors that occurred during the operation + +### StreamrProxyError : public std::runtime_error + +Represents an error that occurred during a proxy operation. + +Members: +- `StreamrProxyAddress proxy` - Proxy address where the error occurred +- `StreamrProxyErrorCode code` - Error code + +Methods: +- `std::string what()` - Returns the error message + +### StreamrProxyErrorCode variant type + +- `ErrorInvalidEthereumAddress` - Indicates an invalid Ethereum address +- `ErrorInvalidStreamPartId` - Indicates an invalid stream part ID +- `ErrorProxyClientNotFound` - Indicates proxy client was not found +- `ErrorInvalidProxyUrl` - Indicates an invalid proxy URL +- `ErrorNoProxiesDefined` - Indicates no proxies were defined +- `ErrorProxyConnectionFailed` - Indicates proxy connection failed +- `ErrorProxyBroadcastFailed` - Indicates proxy broadcast failed + +### Structures + +#### StreamrProxyAddress +Represents a Streamr proxy address. + +Members: +- `std::string websocketUrl` - WebSocket URL of the proxy +- `std::string ethereumAddress` - Ethereum address of the proxy + +#### StreamrProxyResult +Contains the results of a proxy operation. + +Members: +- `std::vector successful` - List of proxies that the operation was successful on +- `std::vector errors` - List of errors that occurred during the operation + + + diff --git a/packages/streamr-libstreamrproxyclient/wrappers/cpp/include/StreamrProxyClient.hpp b/packages/streamr-libstreamrproxyclient/wrappers/cpp/include/StreamrProxyClient.hpp index 675bc5c0..c3cd565e 100644 --- a/packages/streamr-libstreamrproxyclient/wrappers/cpp/include/StreamrProxyClient.hpp +++ b/packages/streamr-libstreamrproxyclient/wrappers/cpp/include/StreamrProxyClient.hpp @@ -2,42 +2,67 @@ #define STREAMR_PROXY_CLIENT_HPP #include +#include +#include #include #include -struct ProxyAddress { - std::string websocketUrl; - std::string ethereumAddress; -}; +#include + +namespace streamrproxyclient { +/** + * @brief Error indicating an invalid Ethereum address + */ struct ErrorInvalidEthereumAddress { - static constexpr std::string_view name = ERROR_INVALID_ETHEREUM_ADDRESS; + static constexpr const char* name = ERROR_INVALID_ETHEREUM_ADDRESS; }; +/** + * @brief Error indicating an invalid stream part ID + */ struct ErrorInvalidStreamPartId { - static constexpr std::string_view name = ERROR_INVALID_STREAM_PART_ID; + static constexpr const char* name = ERROR_INVALID_STREAM_PART_ID; }; +/** + * @brief Error indicating proxy client was not found + */ struct ErrorProxyClientNotFound { - static constexpr std::string_view name = ERROR_PROXY_CLIENT_NOT_FOUND; + static constexpr const char* name = ERROR_PROXY_CLIENT_NOT_FOUND; }; +/** + * @brief Error indicating an invalid proxy URL + */ struct ErrorInvalidProxyUrl { - static constexpr std::string_view name = ERROR_INVALID_PROXY_URL; + static constexpr const char* name = ERROR_INVALID_PROXY_URL; }; +/** + * @brief Error indicating no proxies were defined + */ struct ErrorNoProxiesDefined { - static constexpr std::string_view name = ERROR_NO_PROXIES_DEFINED; + static constexpr const char* name = ERROR_NO_PROXIES_DEFINED; }; +/** + * @brief Error indicating proxy connection failed + */ struct ErrorProxyConnectionFailed { - static constexpr std::string_view name = ERROR_PROXY_CONNECTION_FAILED; + static constexpr const char* name = ERROR_PROXY_CONNECTION_FAILED; }; +/** + * @brief Error indicating proxy broadcast failed + */ struct ErrorProxyBroadcastFailed { - static constexpr std::string_view name = ERROR_PROXY_BROADCAST_FAILED; + static constexpr const char* name = ERROR_PROXY_BROADCAST_FAILED; }; -using ProxyErrorCode = std::variant< +/** + * @brief Variant type containing all possible proxy error codes + */ +using StreamrProxyErrorCode = std::variant< ErrorInvalidEthereumAddress, ErrorInvalidStreamPartId, ErrorProxyClientNotFound, @@ -46,35 +71,172 @@ using ProxyErrorCode = std::variant< ErrorProxyConnectionFailed, ErrorProxyBroadcastFailed>; -struct ProxyError { - ProxyAddress proxy; - std::string message; - ProxyErrorCode code; +/** + * @brief Represents a Streamr proxy address + */ +struct StreamrProxyAddress { + std::string websocketUrl; /**< WebSocket URL of the proxy */ + std::string ethereumAddress; /**< Ethereum address of the proxy */ + + static StreamrProxyAddress fromCProxy(const Proxy* proxy) { + return StreamrProxyAddress{ + std::string(proxy->websocketUrl), + std::string(proxy->ethereumAddress)}; + } +}; + +/** + * @brief Custom exception class for Streamr proxy errors + */ +struct StreamrProxyError : public std::runtime_error { + StreamrProxyAddress proxy; /**< The proxy where the error occurred */ + StreamrProxyErrorCode code; /**< The error code */ + + // NOLINTNEXTLINE(google-explicit-constructor) + StreamrProxyError(const Error* error) + : std::runtime_error(error->message), code(getErrorCode(error->code)) { + if (error->proxy) { + proxy = StreamrProxyAddress::fromCProxy(error->proxy); + } + } + +private: + static StreamrProxyErrorCode getErrorCode(const char* code) { + if (strcmp(code, ERROR_INVALID_ETHEREUM_ADDRESS) == 0) { + return ErrorInvalidEthereumAddress{}; + } + if (strcmp(code, ERROR_INVALID_STREAM_PART_ID) == 0) { + return ErrorInvalidStreamPartId{}; + } + if (std::strcmp(code, ERROR_PROXY_CLIENT_NOT_FOUND) == 0) { + return ErrorProxyClientNotFound{}; + } + if (std::strcmp(code, ERROR_INVALID_PROXY_URL) == 0) { + return ErrorInvalidProxyUrl{}; + } + if (std::strcmp(code, ERROR_NO_PROXIES_DEFINED) == 0) { + return ErrorNoProxiesDefined{}; + } + if (std::strcmp(code, ERROR_PROXY_CONNECTION_FAILED) == 0) { + return ErrorProxyConnectionFailed{}; + } + if (std::strcmp(code, ERROR_PROXY_BROADCAST_FAILED) == 0) { + return ErrorProxyBroadcastFailed{}; + } + return ErrorInvalidProxyUrl{}; + } +}; + +/** + * @brief Contains results of proxy operations + */ +struct StreamrProxyResult { + std::vector + successful; /**< List of successful proxy operations */ + std::vector + errors; /**< List of failed proxy operations */ + + // NOLINTNEXTLINE(google-explicit-constructor) + StreamrProxyResult(const ProxyResult* result) { + this->successful.reserve(result->numSuccessful); + for (size_t i = 0; i < result->numSuccessful; i++) { + this->successful.push_back( + StreamrProxyAddress::fromCProxy(&result->successful[i])); + } + this->errors.reserve(result->numErrors); + for (size_t i = 0; i < result->numErrors; i++) { + this->errors.emplace_back(&result->errors[i]); + } + } }; -/* -struct ProxyResult { - std::vector successful; - std::vector failed; +class SharedLibraryWrapper { +public: + SharedLibraryWrapper() { proxyClientInitLibrary(); } + ~SharedLibraryWrapper() { proxyClientCleanupLibrary(); } }; +/** + * @brief Main client class for interacting with Streamr proxies + */ class StreamrProxyClient { - StreamrProxyClient() { - // call proxyClientNew - } - ~StreamrProxyClient() { - // call proxyClientDelete +private: + static SharedLibraryWrapper sharedLibraryWrapper; + uint64_t proxyClientHandle = 0; + std::string ethereumPrivateKey; + +public: + /** + * @brief Constructs a new StreamrProxyClient + * @param ownEthereumAddress Ethereum address of the client + * @param ethereumPrivateKey Private key for the Ethereum address + * @param streamPartId Stream part ID + * @throw StreamrProxyError if client creation fails + */ + + StreamrProxyClient( + const std::string& ownEthereumAddress, // NOLINT + const std::string& ethereumPrivateKey, // NOLINT + const std::string& streamPartId) + : ethereumPrivateKey(ethereumPrivateKey) { + const ProxyResult* result; + this->proxyClientHandle = proxyClientNew( + &result, ownEthereumAddress.c_str(), streamPartId.c_str()); + if (result->numErrors > 0) { + auto error = StreamrProxyError(&result->errors[0]); + proxyClientResultDelete(result); + throw error; // NOLINT + } + proxyClientResultDelete(result); } - ProxyResult connect(const std::vector proxies) { - // call proxyClientConnect + ~StreamrProxyClient() { + if (this->proxyClientHandle != 0) { + const ProxyResult* result; + proxyClientDelete(&result, this->proxyClientHandle); + proxyClientResultDelete(result); } + } - ProxyResult publish(const std::string message) { - // call proxyClientPublish + /** + * @brief Connects to specified proxies + * @param proxies Vector of proxy addresses to connect to + * @return Result containing successful connections and errors + */ + [[nodiscard]] StreamrProxyResult connect( + const std::vector& proxies) const { + const ProxyResult* result; + std::vector cProxies; + cProxies.reserve(proxies.size()); + for (const auto& proxy : proxies) { + cProxies.push_back( + {proxy.websocketUrl.c_str(), proxy.ethereumAddress.c_str()}); } + proxyClientConnect( + &result, this->proxyClientHandle, cProxies.data(), cProxies.size()); + StreamrProxyResult streamrProxyResult(result); + proxyClientResultDelete(result); + return streamrProxyResult; + } + /** + * @brief Publishes a message through connected proxies + * @param message Message to publish + * @return Result containing successful publications and errors + */ + [[nodiscard]] StreamrProxyResult publish(const std::string& message) const { + const ProxyResult* result; + proxyClientPublish( + &result, + this->proxyClientHandle, + message.data(), + message.size(), + this->ethereumPrivateKey.c_str()); + StreamrProxyResult streamrProxyResult(result); + proxyClientResultDelete(result); + return streamrProxyResult; + } }; -*/ +} // namespace streamrproxyclient #endif // STREAMR_PROXY_CLIENT_HPP diff --git a/packages/streamr-libstreamrproxyclient/wrappers/cpp/test/StreamrProxyClientCppWrapperTest.cpp b/packages/streamr-libstreamrproxyclient/wrappers/cpp/test/StreamrProxyClientCppWrapperTest.cpp new file mode 100644 index 00000000..053edc3e --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/wrappers/cpp/test/StreamrProxyClientCppWrapperTest.cpp @@ -0,0 +1,102 @@ +#include +#include "StreamrProxyClient.hpp" + +using streamrproxyclient::ErrorInvalidProxyUrl; +using streamrproxyclient::ErrorNoProxiesDefined; +using streamrproxyclient::ErrorProxyConnectionFailed; +using streamrproxyclient::StreamrProxyAddress; +using streamrproxyclient::StreamrProxyClient; +using streamrproxyclient::StreamrProxyError; +class StreamrProxyClientCppWrapperTest : public ::testing::Test { +protected: + static constexpr const char* invalidEthereumAddress = + "INVALID_ETHEREUM_ADDRESS"; + static constexpr const char* goodEthereumAddress = + "0x123456789012345678901234567890123456789a"; + static constexpr const char* validEthereumAddress = + "0x1234567890123456789012345678901234567890"; + static constexpr const char* validEthereumAddress2 = + "0x1234567890123456789012345678901234567892"; + static constexpr const char* validEthereumAddress3 = + "0x1234567890123456789012345678901234567893"; + static constexpr const char* invalidStreamPartId = "INVALID_STREAM_PART_ID"; + static constexpr const char* validStreamPartId = + "0xa000000000000000000000000000000000000000#01"; + static constexpr const char* validPrivateKey = + "0000000000000000000000000000000000000000000000000000000000000001"; + + static constexpr const char* invalidProxyUrl = "poiejrg039utg240"; + static constexpr const char* validProxyUrl = "ws://valid.com"; + static constexpr const char* nonExistentProxyUrl0 = "ws://localhost:0"; + static constexpr const char* nonExistentProxyUrl1 = "ws://localhost:1"; + static constexpr const char* nonExistentProxyUrl2 = "ws://localhost:2"; +}; + +TEST_F(StreamrProxyClientCppWrapperTest, InvalidEthereumAddressCpp) { + EXPECT_THROW( + { + StreamrProxyClient client( + invalidEthereumAddress, validPrivateKey, validStreamPartId); + }, + StreamrProxyError); +} + +TEST_F(StreamrProxyClientCppWrapperTest, InvalidStreamPartIdCpp) { + EXPECT_THROW( + { + StreamrProxyClient client( + validEthereumAddress, validPrivateKey, invalidStreamPartId); + }, + StreamrProxyError); +} + +TEST_F(StreamrProxyClientCppWrapperTest, InvalidProxyUrlCpp) { + StreamrProxyClient client( + validEthereumAddress, validPrivateKey, validStreamPartId); + + std::vector proxies = { + {invalidProxyUrl, validEthereumAddress}}; + + auto result = client.connect(proxies); + EXPECT_EQ(result.successful.size(), 0); + EXPECT_EQ(result.errors.size(), 1); + EXPECT_TRUE( + std::holds_alternative(result.errors[0].code)); +} + +TEST_F(StreamrProxyClientCppWrapperTest, NoProxiesDefinedCpp) { + StreamrProxyClient client( + validEthereumAddress, validPrivateKey, validStreamPartId); + + std::vector proxies; + auto result = client.connect(proxies); + + EXPECT_EQ(result.successful.size(), 0); + EXPECT_EQ(result.errors.size(), 1); + EXPECT_TRUE( + std::holds_alternative(result.errors[0].code)); +} + +TEST_F(StreamrProxyClientCppWrapperTest, ThreeProxyConnectionsFailedCpp) { + StreamrProxyClient client( + goodEthereumAddress, validPrivateKey, validStreamPartId); + + std::vector proxies = { + {nonExistentProxyUrl0, validEthereumAddress}, + {nonExistentProxyUrl1, validEthereumAddress2}, + {nonExistentProxyUrl2, validEthereumAddress3}}; + + auto result = client.connect(proxies); + + EXPECT_EQ(result.successful.size(), 0); + EXPECT_EQ(result.errors.size(), 3); + + for (const auto& error : result.errors) { + EXPECT_TRUE( + std::holds_alternative(error.code)); + } + + EXPECT_EQ(result.errors[0].proxy.websocketUrl, nonExistentProxyUrl0); + EXPECT_EQ(result.errors[1].proxy.websocketUrl, nonExistentProxyUrl1); + EXPECT_EQ(result.errors[2].proxy.websocketUrl, nonExistentProxyUrl2); +} diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go b/packages/streamr-libstreamrproxyclient/wrappers/go new file mode 160000 index 00000000..55f17ba3 --- /dev/null +++ b/packages/streamr-libstreamrproxyclient/wrappers/go @@ -0,0 +1 @@ +Subproject commit 55f17ba3850938aa7539bb0f22409b4abe1b15a4 diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/dist/arm64-linux/lib/Release/libstreamrproxyclient.so b/packages/streamr-libstreamrproxyclient/wrappers/go/dist/arm64-linux/lib/Release/libstreamrproxyclient.so deleted file mode 100644 index 52b0508e..00000000 Binary files a/packages/streamr-libstreamrproxyclient/wrappers/go/dist/arm64-linux/lib/Release/libstreamrproxyclient.so and /dev/null differ diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/dist/arm64-osx/lib/Release/libstreamrproxyclient.dylib b/packages/streamr-libstreamrproxyclient/wrappers/go/dist/arm64-osx/lib/Release/libstreamrproxyclient.dylib deleted file mode 100755 index 63c0b130..00000000 Binary files a/packages/streamr-libstreamrproxyclient/wrappers/go/dist/arm64-osx/lib/Release/libstreamrproxyclient.dylib and /dev/null differ diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/dist/x64-linux/lib/Release/libstreamrproxyclient.so b/packages/streamr-libstreamrproxyclient/wrappers/go/dist/x64-linux/lib/Release/libstreamrproxyclient.so deleted file mode 100644 index 31669a76..00000000 Binary files a/packages/streamr-libstreamrproxyclient/wrappers/go/dist/x64-linux/lib/Release/libstreamrproxyclient.so and /dev/null differ diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/dist/x64-osx/lib/Release/libstreamrproxyclient.dylib b/packages/streamr-libstreamrproxyclient/wrappers/go/dist/x64-osx/lib/Release/libstreamrproxyclient.dylib deleted file mode 100755 index ab7f4eb1..00000000 Binary files a/packages/streamr-libstreamrproxyclient/wrappers/go/dist/x64-osx/lib/Release/libstreamrproxyclient.dylib and /dev/null differ diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/embeddedlib_darwin_amd64.go b/packages/streamr-libstreamrproxyclient/wrappers/go/embeddedlib_darwin_amd64.go deleted file mode 100644 index 3d35ee86..00000000 --- a/packages/streamr-libstreamrproxyclient/wrappers/go/embeddedlib_darwin_amd64.go +++ /dev/null @@ -1,32 +0,0 @@ -package streamrproxyclient - -import ( - "embed" - "os" - "path/filepath" -) - -//go:embed dist/x64-osx/lib/Release/libstreamrproxyclient.dylib -var libFileFs embed.FS - -const libFullPath = "dist/x64-osx/lib/Release/libstreamrproxyclient.dylib" -const libName = "libstreamrproxyclient.dylib" - -func SaveLibToTempFile() (string, error) { - dirName, err := os.MkdirTemp("", "*") - if err != nil { - return "", err - } - - libPath := filepath.Join(dirName, libName) - libFileBytes, err := libFileFs.ReadFile(libFullPath) - if err != nil { - return "", err - } - - err = os.WriteFile(libPath, libFileBytes, 0o600) - if err != nil { - return "", err - } - return libPath, nil -} diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/embeddedlib_darwin_arm64.go b/packages/streamr-libstreamrproxyclient/wrappers/go/embeddedlib_darwin_arm64.go deleted file mode 100644 index 9c1d9e65..00000000 --- a/packages/streamr-libstreamrproxyclient/wrappers/go/embeddedlib_darwin_arm64.go +++ /dev/null @@ -1,32 +0,0 @@ -package streamrproxyclient - -import ( - "embed" - "os" - "path/filepath" -) - -//go:embed dist/arm64-osx/lib/Release/libstreamrproxyclient.dylib -var libFileFs embed.FS - -const libFullPath = "dist/arm64-osx/lib/Release/libstreamrproxyclient.dylib" -const libName = "libstreamrproxyclient.dylib" - -func SaveLibToTempFile() (string, error) { - dirName, err := os.MkdirTemp("", "*") - if err != nil { - return "", err - } - - libPath := filepath.Join(dirName, libName) - libFileBytes, err := libFileFs.ReadFile(libFullPath) - if err != nil { - return "", err - } - - err = os.WriteFile(libPath, libFileBytes, 0o600) - if err != nil { - return "", err - } - return libPath, nil -} diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/embeddedlib_linux_amd64.go b/packages/streamr-libstreamrproxyclient/wrappers/go/embeddedlib_linux_amd64.go deleted file mode 100644 index a54d0e38..00000000 --- a/packages/streamr-libstreamrproxyclient/wrappers/go/embeddedlib_linux_amd64.go +++ /dev/null @@ -1,32 +0,0 @@ -package streamrproxyclient - -import ( - "embed" - "os" - "path/filepath" -) - -//go:embed dist/x64-linux/lib/Release/libstreamrproxyclient.so -var libFileFs embed.FS - -const libFullPath = "dist/x64-linux/lib/Release/libstreamrproxyclient.so" -const libName = "libstreamrproxyclient.so" - -func SaveLibToTempFile() (string, error) { - dirName, err := os.MkdirTemp("", "*") - if err != nil { - return "", err - } - - libPath := filepath.Join(dirName, libName) - libFileBytes, err := libFileFs.ReadFile(libFullPath) - if err != nil { - return "", err - } - - err = os.WriteFile(libPath, libFileBytes, 0o600) - if err != nil { - return "", err - } - return libPath, nil -} diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/embeddedlib_linux_arm64.go b/packages/streamr-libstreamrproxyclient/wrappers/go/embeddedlib_linux_arm64.go deleted file mode 100644 index b1d9ef1f..00000000 --- a/packages/streamr-libstreamrproxyclient/wrappers/go/embeddedlib_linux_arm64.go +++ /dev/null @@ -1,32 +0,0 @@ -package streamrproxyclient - -import ( - "embed" - "os" - "path/filepath" -) - -//go:embed dist/arm64-linux/lib/Release/libstreamrproxyclient.so -var libFileFs embed.FS - -const libFullPath = "dist/arm64-linux/lib/Release/libstreamrproxyclient.so" -const libName = "libstreamrproxyclient.so" - -func SaveLibToTempFile() (string, error) { - dirName, err := os.MkdirTemp("", "*") - if err != nil { - return "", err - } - - libPath := filepath.Join(dirName, libName) - libFileBytes, err := libFileFs.ReadFile(libFullPath) - if err != nil { - return "", err - } - - err = os.WriteFile(libPath, libFileBytes, 0o600) - if err != nil { - return "", err - } - return libPath, nil -} diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/go.mod b/packages/streamr-libstreamrproxyclient/wrappers/go/go.mod deleted file mode 100644 index d35de0f7..00000000 --- a/packages/streamr-libstreamrproxyclient/wrappers/go/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module streamrproxyclient - -go 1.23.2 diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/install.sh b/packages/streamr-libstreamrproxyclient/wrappers/go/install.sh deleted file mode 100755 index 8e5bf9ba..00000000 --- a/packages/streamr-libstreamrproxyclient/wrappers/go/install.sh +++ /dev/null @@ -1,26 +0,0 @@ -#! /bin/bash - -BASE_DIR=$(pwd) - -if [[ "$OSTYPE" == "darwin"* ]] && [[ "$(uname -m)" == "arm64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/arm64-osx/lib/Debug) - export DYLD_LIBRARY_PATH=$LIB_PATH:$DYLD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi -if [[ "$OSTYPE" == "darwin"* ]] && [[ "$(uname -m)" == "x86_64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/x64-osx/lib/Debug) - export DYLD_LIBRARY_PATH=$LIB_PATH:$DYLD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi -if [[ "$OSTYPE" == "linux-gnu"* ]] && [[ "$(uname -m)" == "x86_64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/x64-linux/lib/Debug) - export LD_LIBRARY_PATH=$LIB_PATH:$LD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi -if [[ "$OSTYPE" == "linux-gnu"* ]] && [[ "$(uname -m)" == "aarch64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/arm64-linux/lib/Debug) - export LD_LIBRARY_PATH=$LIB_PATH:$LD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi - -go build . \ No newline at end of file diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/publishtoserver.sh b/packages/streamr-libstreamrproxyclient/wrappers/go/publishtoserver.sh deleted file mode 100755 index 80770d76..00000000 --- a/packages/streamr-libstreamrproxyclient/wrappers/go/publishtoserver.sh +++ /dev/null @@ -1,26 +0,0 @@ -#! /bin/bash - -BASE_DIR=$(pwd) - -if [[ "$OSTYPE" == "darwin"* ]] && [[ "$(uname -m)" == "arm64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/arm64-osx/lib/Debug) - export DYLD_LIBRARY_PATH=$LIB_PATH:$DYLD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi -if [[ "$OSTYPE" == "darwin"* ]] && [[ "$(uname -m)" == "x86_64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/x64-osx/lib/Debug) - export DYLD_LIBRARY_PATH=$LIB_PATH:$DYLD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi -if [[ "$OSTYPE" == "linux-gnu"* ]] && [[ "$(uname -m)" == "x86_64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/x64-linux/lib/Debug) - export LD_LIBRARY_PATH=$LIB_PATH:$LD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi -if [[ "$OSTYPE" == "linux-gnu"* ]] && [[ "$(uname -m)" == "aarch64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/arm64-linux/lib/Debug) - export LD_LIBRARY_PATH=$LIB_PATH:$LD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi - -go test -test.run TestPublishToServer \ No newline at end of file diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/publishtoserver_test.go b/packages/streamr-libstreamrproxyclient/wrappers/go/publishtoserver_test.go deleted file mode 100644 index 22d2a17f..00000000 --- a/packages/streamr-libstreamrproxyclient/wrappers/go/publishtoserver_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package streamrproxyclient - -import ( - "testing" -) - -func TestPublishToServer(t *testing.T) { - tsEthereumAddress := "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - tsProxyUrl := "ws://127.0.0.1:44211" - tsStreamPartId := "0xa000000000000000000000000000000000000000#01" - ownEthereumAddress := "0xa5374e3c19f15e1847881979dd0c6c9ffe846bd5" - ethereumPrivateKey := "23bead9b499af21c4c16e4511b3b6b08c3e22e76e0591f5ab5ba8d4c3a5b1820" - - lib := NewLibStreamrProxyClient() - defer lib.Close() - - client, err := NewProxyClient(ownEthereumAddress, tsStreamPartId) - if err != nil { - t.Fatalf("Error creating ProxyClient: %v", err) - } - defer client.Close() - - proxies := []Proxy{ - *NewProxy(tsProxyUrl, tsEthereumAddress), - } - - result := client.Connect(proxies) - if len(result.errors) != 0 { - t.Fatalf("Errors during connection: %v", result.errors) - } - if len(result.successful) != 1 { - t.Fatalf("Unexpected number of successful connections: %d", len(result.successful)) - } - - data := []byte("Hello from Go!") - result = client.Publish(data, ethereumPrivateKey) - if len(result.errors) != 0 { - t.Fatalf("Errors during publish: %v", result.errors) - } - if len(result.successful) != 1 { - t.Fatalf("Unexpected number of successful publishes: %d", len(result.successful)) - } -} \ No newline at end of file diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/shim.c b/packages/streamr-libstreamrproxyclient/wrappers/go/shim.c deleted file mode 100644 index eeb7cb5f..00000000 --- a/packages/streamr-libstreamrproxyclient/wrappers/go/shim.c +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include "shim.h" - -void (*proxyClientInitLibraryPtr)(void); // NOLINT -void (*proxyClientCleanupLibraryPtr)(void); // NOLINT -void (*proxyClientResultDeletePtr)(const ProxyResult*); -uint64_t (*proxyClientNewPtr)(const ProxyResult**, const char*, const char*); -void (*proxyClientDeletePtr)(const ProxyResult**, uint64_t); -uint64_t (*proxyClientConnectPtr)(const ProxyResult**, uint64_t, const Proxy*, uint64_t); -void (*proxyClientDisconnectPtr)(const ProxyResult**, uint64_t); -uint64_t (*proxyClientPublishPtr)(const ProxyResult**, uint64_t, const char*, uint64_t, const char*); -void* proxyClientLibrary; - -void loadSharedLibrary(const char* libFilePath) { - proxyClientLibrary = dlopen(libFilePath, RTLD_LAZY); - proxyClientInitLibraryPtr = (void (*)(void))dlsym(proxyClientLibrary, "proxyClientInitLibrary"); // NOLINT - proxyClientCleanupLibraryPtr = (void (*)(void))dlsym(proxyClientLibrary, "proxyClientCleanupLibrary"); // NOLINT - proxyClientResultDeletePtr = (void (*)(const ProxyResult*))dlsym(proxyClientLibrary, "proxyClientResultDelete"); - proxyClientNewPtr = (uint64_t (*)(const ProxyResult**, const char*, const char*))dlsym(proxyClientLibrary, "proxyClientNew"); - proxyClientDeletePtr = (void (*)(const ProxyResult**, uint64_t))dlsym(proxyClientLibrary, "proxyClientDelete"); - proxyClientConnectPtr = (uint64_t (*)(const ProxyResult**, uint64_t, const Proxy*, uint64_t))dlsym(proxyClientLibrary, "proxyClientConnect"); - proxyClientDisconnectPtr = (void (*)(const ProxyResult**, uint64_t))dlsym(proxyClientLibrary, "proxyClientDisconnect"); - proxyClientPublishPtr = (uint64_t (*)(const ProxyResult**, uint64_t, const char*, uint64_t, const char*))dlsym(proxyClientLibrary, "proxyClientPublish"); -} - -void closeSharedLibrary() { - dlclose(proxyClientLibrary); -} - -void proxyClientInitLibraryWrapper(void) { // NOLINT - proxyClientInitLibraryPtr(); -} - -void proxyClientCleanupLibraryWrapper(void) { // NOLINT - proxyClientCleanupLibraryPtr(); -} - -void proxyClientResultDeleteWrapper(const ProxyResult* result) { - proxyClientResultDeletePtr(result); -} - -uint64_t proxyClientNewWrapper(const ProxyResult** result, const char* streamId, const char* topic) { - return proxyClientNewPtr(result, streamId, topic); -} - -void proxyClientDeleteWrapper(const ProxyResult** result, uint64_t id) { - proxyClientDeletePtr(result, id); -} - -uint64_t proxyClientConnectWrapper(const ProxyResult** result, uint64_t id, const Proxy* proxy, uint64_t proxyId) { - return proxyClientConnectPtr(result, id, proxy, proxyId); -} - -void proxyClientDisconnectWrapper(const ProxyResult** result, uint64_t id) { - proxyClientDisconnectPtr(result, id); -} - -uint64_t proxyClientPublishWrapper(const ProxyResult** result, uint64_t id, const char* content, uint64_t contentLength, const char* ethereumPrivateKey) { - return proxyClientPublishPtr(result, id, content, contentLength, ethereumPrivateKey); -} diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/shim.h b/packages/streamr-libstreamrproxyclient/wrappers/go/shim.h deleted file mode 100644 index 5e742f9f..00000000 --- a/packages/streamr-libstreamrproxyclient/wrappers/go/shim.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef SHIM_H -#define SHIM_H - -#include "streamrproxyclient.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void loadSharedLibrary(const char* libFilePath); -void closeSharedLibrary(); - -void proxyClientInitLibraryWrapper(void); // NOLINT -void proxyClientCleanupLibraryWrapper(void); // NOLINT -void proxyClientResultDeleteWrapper(const ProxyResult* result); -uint64_t proxyClientNewWrapper(const ProxyResult** result, const char* streamId, const char* topic); -void proxyClientDeleteWrapper(const ProxyResult** result, uint64_t id); -uint64_t proxyClientConnectWrapper(const ProxyResult** result, uint64_t id, const Proxy* proxy, uint64_t proxyId); -void proxyClientDisconnectWrapper(const ProxyResult** result, uint64_t id); -uint64_t proxyClientPublishWrapper(const ProxyResult** result, uint64_t id, const char* content, uint64_t contentLength, const char* ethereumPrivateKey); - -#ifdef __cplusplus -} -#endif - -#endif // SHIM_H diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/streamrproxyclient.go b/packages/streamr-libstreamrproxyclient/wrappers/go/streamrproxyclient.go deleted file mode 100644 index 40b46f23..00000000 --- a/packages/streamr-libstreamrproxyclient/wrappers/go/streamrproxyclient.go +++ /dev/null @@ -1,267 +0,0 @@ -package streamrproxyclient - -// #include -// #include "shim.h" -// #include "streamrproxyclient.h" -import "C" -import ( - "fmt" - "unsafe" -) - -func openLibrary() (error) { - fileName, err := SaveLibToTempFile() - if err != nil { - return err - } - C.loadSharedLibrary(C.CString(fileName)) - return nil -} - -func closeLibrary() { - C.closeSharedLibrary() -} - -/* -func openEmbeddedLib(embedFS embed.FS, libName, funcName string) (unsafe.Pointer, error) { - - log.Println("creating temp dir to host .so") - dirName, err := os.MkdirTemp("", "*") - if err != nil { - return nil, err - } - - log.Println("opening a .so from embed") - f, err := greet.LibFS.Open(libName) - if err != nil { - return nil, err - } - - log.Println("read .so content into memory buffer") - b := make([]byte, 1_000_000) - _, err = f.Read(b) - if err != nil { - return nil, err - } - - fPath := filepath.Join(dirName, libName) - - log.Println("writing embedded .so in:", fPath) - err = ioutil.WriteFile(fPath, b, 0o600) - if err != nil { - return nil, err - } - - fileName, err := SaveLibToTempFile() - if err != nil { - return nil, err - } - log.Println("dlopen the lib apps from temp file") - lName := C.CString(fileName) - handle := C.dlopen(lName, C.RTLD_LAZY) - if handle == nil { - return nil, errors.New("dlopen: fail") - } - - log.Println("dlsym the func from the lib") - symbol := C.CString(funcName) - greetFn := C.dlsym(handle, symbol) - if greetFn == nil { - return nil, errors.New("dlsym: fail") - } - return greetFn, err -} -*/ - -// Error codes from the C library. -const ( - ERROR_INVALID_ETHEREUM_ADDRESS = "INVALID_ETHEREUM_ADDRESS" - ERROR_INVALID_STREAM_PART_ID = "INVALID_STREAM_PART_ID" - ERROR_PROXY_CLIENT_NOT_FOUND = "PROXY_CLIENT_NOT_FOUND" - ERROR_INVALID_PROXY_URL = "INVALID_PROXY_URL" - ERROR_NO_PROXIES_DEFINED = "NO_PROXIES_DEFINED" - ERROR_PROXY_CONNECTION_FAILED = "PROXY_CONNECTION_FAILED" - ERROR_PROXY_BROADCAST_FAILED = "PROXY_BROADCAST_FAILED" -) - -// Proxy struct represents a proxy with a websocket URL and an Ethereum address. -type Proxy struct { - websocketUrl string - ethereumAddress string -} - -// NewProxy creates a new Proxy instance. -func NewProxy(websocketUrl, ethereumAddress string) *Proxy { - return &Proxy{ - websocketUrl: websocketUrl, - ethereumAddress: ethereumAddress, - } -} - -// FromCProxy converts a C Proxy to a Go Proxy. -func (p *Proxy) FromCProxy(cProxy *C.Proxy) *Proxy { - return &Proxy{ - websocketUrl: C.GoString(cProxy.websocketUrl), - ethereumAddress: C.GoString(cProxy.ethereumAddress), - } -} - -// String returns a string representation of the Proxy. -func (p *Proxy) String() string { - return fmt.Sprintf("Proxy(websocketUrl=%s, ethereumAddress=%s)", p.websocketUrl, p.ethereumAddress) -} - -// Equals checks if two Proxy instances are equal. -func (p *Proxy) Equals(other *Proxy) bool { - return p.websocketUrl == other.websocketUrl && p.ethereumAddress == other.ethereumAddress -} - -// ProxyClientError struct represents an error in the ProxyClient. -type ProxyClientError struct { - message string - code string - proxy *Proxy -} - -// Error implements the error interface for ProxyClientError. -func (e *ProxyClientError) Error() string { - return e.String() -} - -// NewProxyClientError creates a new ProxyClientError from a C Error. -func NewProxyClientError(cError *C.Error) *ProxyClientError { - var proxy *Proxy - if cError.proxy != nil { - proxy = NewProxy(C.GoString(cError.proxy.websocketUrl), C.GoString(cError.proxy.ethereumAddress)) - } - return &ProxyClientError{ - message: C.GoString(cError.message), - code: C.GoString(cError.code), - proxy: proxy, - } -} - -// String returns a string representation of the ProxyClientError. -func (e *ProxyClientError) String() string { - return fmt.Sprintf("Error(message=%s, code=%s, proxy=%v)", e.message, e.code, e.proxy) -} - -// ProxyClientResult struct represents the result of a ProxyClient operation. -type ProxyClientResult struct { - errors []*ProxyClientError - successful []*Proxy -} - -// NewProxyClientResult creates a new ProxyClientResult from a C ProxyResult. -func NewProxyClientResult(proxyResultPtr *C.ProxyResult) *ProxyClientResult { - result := &ProxyClientResult{ - errors: make([]*ProxyClientError, proxyResultPtr.numErrors), - successful: make([]*Proxy, proxyResultPtr.numSuccessful), - } - - for i := 0; i < int(proxyResultPtr.numErrors); i++ { - cError := (*C.Error)(unsafe.Pointer(uintptr(unsafe.Pointer(proxyResultPtr.errors)) + uintptr(i)*unsafe.Sizeof(*proxyResultPtr.errors))) - result.errors[i] = NewProxyClientError(cError) - } - - for i := 0; i < int(proxyResultPtr.numSuccessful); i++ { - cProxy := (*C.Proxy)(unsafe.Pointer(uintptr(unsafe.Pointer(proxyResultPtr.successful)) + uintptr(i)*unsafe.Sizeof(*proxyResultPtr.successful))) - result.successful[i] = NewProxy(C.GoString(cProxy.websocketUrl), C.GoString(cProxy.ethereumAddress)) - } - - return result -} - -// LibStreamrProxyClient struct represents the Streamr Proxy Client library. -type LibStreamrProxyClient struct { -} - -// NewLibStreamrProxyClient creates a new LibStreamrProxyClient instance. -func NewLibStreamrProxyClient() *LibStreamrProxyClient { - err := openLibrary() - if err != nil { - panic(err) - } - lib := &LibStreamrProxyClient{} - C.proxyClientInitLibraryWrapper() - return lib -} - -// Close cleans up the Streamr Proxy Client library. -func (l *LibStreamrProxyClient) Close() { - C.proxyClientCleanupLibraryWrapper() - closeLibrary() -} - -// ProxyClient struct represents a client that connects to proxies. -type ProxyClient struct { - ownEthereumAddress string - streamPartId string - clientHandle C.uint64_t -} - -// NewProxyClient creates a new ProxyClient instance. -func NewProxyClient(ownEthereumAddress, streamPartId string) (*ProxyClient, *ProxyClientError) { - client := &ProxyClient{ - ownEthereumAddress: ownEthereumAddress, - streamPartId: streamPartId, - } - var result *C.ProxyResult - client.clientHandle = C.proxyClientNewWrapper(&result, C.CString(client.ownEthereumAddress), C.CString(client.streamPartId)) - if result.numErrors > 0 { - firstError := (*C.Error)(unsafe.Pointer(uintptr(unsafe.Pointer(result.errors)) + uintptr(0)*unsafe.Sizeof(*result.errors))) - return nil, NewProxyClientError(firstError) - } - C.proxyClientResultDeleteWrapper(result) - return client, nil -} - -// Close deletes the ProxyClient instance. -func (p *ProxyClient) Close() *ProxyClientError { - var result *C.ProxyResult - C.proxyClientDeleteWrapper(&result, p.clientHandle) - if result.numErrors > 0 { - firstError := (*C.Error)(unsafe.Pointer(uintptr(unsafe.Pointer(result.errors)) + uintptr(0)*unsafe.Sizeof(*result.errors))) - return NewProxyClientError(firstError) - } - C.proxyClientResultDeleteWrapper(result) - return nil -} - -// Connect connects the ProxyClient to the given proxies. -func (p *ProxyClient) Connect(proxies []Proxy) *ProxyClientResult { - numProxies := C.uint64_t(len(proxies)) - var proxyArray []C.Proxy - if numProxies > 0 { - proxyArray = make([]C.Proxy, numProxies) - for i, proxy := range proxies { - proxyArray[i] = C.Proxy{ - websocketUrl: C.CString(proxy.websocketUrl), - ethereumAddress: C.CString(proxy.ethereumAddress), - } - } - } - var result *C.ProxyResult - - if numProxies > 0 { - C.proxyClientConnectWrapper(&result, p.clientHandle, &proxyArray[0], numProxies) - } else { - C.proxyClientConnectWrapper(&result, p.clientHandle, nil, numProxies) - } - res := NewProxyClientResult(result) - C.proxyClientResultDeleteWrapper(result) - return res -} - -// Publish publishes data using the ProxyClient. -func (p *ProxyClient) Publish(data []byte, ethereumPrivateKey string) *ProxyClientResult { - var result *C.ProxyResult - if ethereumPrivateKey != "" { - C.proxyClientPublishWrapper(&result, p.clientHandle, (*C.char)(unsafe.Pointer(&data[0])), C.uint64_t(len(data)), C.CString(ethereumPrivateKey)) - } else { - C.proxyClientPublishWrapper(&result, p.clientHandle, (*C.char)(unsafe.Pointer(&data[0])), C.uint64_t(len(data)), nil) - } - res := NewProxyClientResult(result) - C.proxyClientResultDeleteWrapper(result) - return res -} diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/streamrproxyclient.h b/packages/streamr-libstreamrproxyclient/wrappers/go/streamrproxyclient.h deleted file mode 100644 index b28c146c..00000000 --- a/packages/streamr-libstreamrproxyclient/wrappers/go/streamrproxyclient.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef LIBSTREAMRPROXYCLIENT_H -#define LIBSTREAMRPROXYCLIENT_H - -// NOLINTNEXTLINE -#include - -#if defined(__clang__) || defined(__GNUC__) -#define SHARED_EXPORT __attribute__((visibility("default"))) -#define SHARED_LOCAL __attribute__((visibility("hidden"))) -#else -#define SHARED_EXPORT -#define SHARED_LOCAL -#endif - -#ifdef __cplusplus -#define EXTERN_C extern "C" -#else -#define EXTERN_C -#endif - -#define ERROR_INVALID_ETHEREUM_ADDRESS "INVALID_ETHEREUM_ADDRESS" -#define ERROR_INVALID_STREAM_PART_ID "INVALID_STREAM_PART_ID" -#define ERROR_PROXY_CLIENT_NOT_FOUND "PROXY_CLIENT_NOT_FOUND" -#define ERROR_INVALID_PROXY_URL "INVALID_PROXY_URL" -#define ERROR_NO_PROXIES_DEFINED "NO_PROXIES_DEFINED" -#define ERROR_PROXY_CONNECTION_FAILED "PROXY_CONNECTION_FAILED" -#define ERROR_PROXY_BROADCAST_FAILED "PROXY_BROADCAST_FAILED" - -EXTERN_C SHARED_EXPORT const char* testRpc(void); - -// NOLINTNEXTLINE -SHARED_EXPORT static void __attribute__((constructor)) initialize(void); - - -/** - * @brief Initialize the library. This function is called automatically when the library is loaded, - * but can be called explicitly to force a re-initialization (e.g. after proxyClientCleanupLibrary() has been called). - */ - -// NOLINTNEXTLINE -EXTERN_C SHARED_EXPORT void proxyClientInitLibrary(void); - -/** - * @brief Cleanup the library. This function MUST be called before the program exits. - * Can be safely called multiple times. This is needed because the standard dynamic library - * destructor (__attribute__((destructor))) is called after static variables have already been destroyed, - * which makes it impossible to clean up the other objects that depend on the static variables. - */ -// NOLINTNEXTLINE -EXTERN_C SHARED_EXPORT void proxyClientCleanupLibrary(void); -// NOLINTNEXTLINE -typedef struct Proxy { - const char* websocketUrl; - const char* ethereumAddress; -} Proxy; - -// NOLINTNEXTLINE -typedef struct Error { - const char* message; - const char* code; - const struct Proxy* proxy; -} Error; - -// NOLINTNEXTLINE -typedef struct ProxyResult { - Error* errors; - uint64_t numErrors; - Proxy* successful; - uint64_t numSuccessful; -} ProxyResult; - -/** - * @brief Delete a ProxyResult. This method must be called after every call that - * returns a ProxyResult. - * @param proxyResult The ProxyResult to delete. - */ - -EXTERN_C SHARED_EXPORT void proxyClientResultDelete(const ProxyResult* proxyResult); - -/** - * @brief Create a new proxy client. - * - * @param proxyResult Pointer in which ProxyResult will be stored. You MUST call - * proxyClientResultDelete() on this after the call returns. The resulting ProxyResult - * may only contain "errors" - the "successful" and "numSuccessful" fields are - * unused. - * @param ownEthereumAddress The Ethereum address of the client in format - * 0x1234567890123456789012345678901234567890. - * @param streamPartId The stream part id in format - * 0xa000000000000000000000000000000000000000#01. - * @return The handle of the created client. - */ - -EXTERN_C SHARED_EXPORT uint64_t proxyClientNew( - const ProxyResult** proxyResult, - const char* ownEthereumAddress, - const char* streamPartId); - -/** - * @brief Delete a proxy client. - * - * @param proxyResult Pointer in which ProxyResult will be stored. You MUST call - * proxyClientResultDelete() on this after the call returns. The resulting ProxyResult - * may only contain "errors" - the "successful" and "numSuccessful" fields are - * unused. - * @param clientHandle The client handle of the client to delete. - */ - -EXTERN_C SHARED_EXPORT void proxyClientDelete( - const ProxyResult** proxyResult, uint64_t clientHandle); - -/** - * @brief Connect a proxy client to a list of proxies. - * - * @param proxyResult Pointer in which ProxyResult will be stored. You MUST call - * proxyClientResultDelete() on this after the call returns. - * @param clientHandle The client handle of the client to connect. - * @param proxies The array of proxies. - * @param numProxies The number of proxies. - * @return The number of proxies connected to. - */ - -EXTERN_C SHARED_EXPORT uint64_t proxyClientConnect( - const ProxyResult** proxyResult, - uint64_t clientHandle, - const Proxy* proxies, - uint64_t numProxies); - -/** - * @brief Disconnect a proxy client from all proxies. - * - * @param proxyResult Pointer in which ProxyResult will be stored. You MUST call - * proxyClientResultDelete() on this after the call returns. The resulting ProxyResult - * may only contain "errors" - the "successful" and "numSuccessful" fields are - * unused. - * @param clientHandle The client handle of the client to disconnect. - -EXTERN_C SHARED_EXPORT void proxyClientDisconnect( - const ProxyResult** proxyResult, uint64_t clientHandle); -*/ - -/** - * @brief Publish a message to the stream. - * - * @param proxyResult Pointer in which ProxyResult will be stored. You MUST call - * proxyClientResultDelete() on this after the call returns. - * @param clientHandle The client handle of the client to publish. - * @param content The content to publish. - * @param contentLength The length of the content. - * @param ethereumPrivateKey as hex without 0x prefix (64 characters) or NULL if - * message should not be signed. - * @return The number of proxies to which the message was published to. - */ - -EXTERN_C SHARED_EXPORT uint64_t proxyClientPublish( - const ProxyResult** proxyResult, - uint64_t clientHandle, - const char* content, - uint64_t contentLength, - const char* ethereumPrivateKey); - -#endif /* LIBSTREAMRPROXYCLIENT_H */ diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/streamrproxyclient_test.go b/packages/streamr-libstreamrproxyclient/wrappers/go/streamrproxyclient_test.go deleted file mode 100644 index 6488e776..00000000 --- a/packages/streamr-libstreamrproxyclient/wrappers/go/streamrproxyclient_test.go +++ /dev/null @@ -1,200 +0,0 @@ -package streamrproxyclient - -import ( - "fmt" - "testing" -) - -const ( - invalidEthereumAddress = "INVALID_ETHEREUM_ADDRESS" - goodEthereumAddress = "0x123456789012345678901234567890123456789a" - validEthereumAddress = "0x1234567890123456789012345678901234567890" - validEthereumAddress2 = "0x1234567890123456789012345678901234567892" - validEthereumAddress3 = "0x1234567890123456789012345678901234567893" - invalidStreamPartId = "INVALID_STREAM_PART_ID" - validStreamPartId = "0xa000000000000000000000000000000000000000#01" - ownEthereumAddress = "0x1234567890123456789012345678901234567890" - streamPartId = "0xd2078dc2d780029473a39ce873fc182587be69db/low-level-client#0" - invalidProxyUrl = "poiejrg039utg240" - validProxyUrl = "ws://valid.com" - nonExistentProxyUrl0 = "ws://localhost:0" - nonExistentProxyUrl1 = "ws://localhost:1" - nonExistentProxyUrl2 = "ws://localhost:2" - invalidClientHandle uint64 = 0 -) -func TestLibStreamrProxyClientCreation(t *testing.T) { - lib := NewLibStreamrProxyClient() - if lib == nil { - t.Fatalf("Failed to create LibStreamrProxyClient") - } - defer lib.Close() - client, err := NewProxyClient(ownEthereumAddress, streamPartId) - if err != nil { - t.Fatalf("Failed to create ProxyClient: %v", err) - } - defer client.Close() -} - -func TestInvalidEthereumAddress(t *testing.T) { - lib := NewLibStreamrProxyClient() - defer lib.Close() - client, err := NewProxyClient(invalidEthereumAddress, validStreamPartId) - if err == nil { - t.Fatalf("Expected error for invalid Ethereum address") - } else if err.code != ERROR_INVALID_ETHEREUM_ADDRESS { - t.Fatalf("Expected error code %s, got %s", ERROR_INVALID_ETHEREUM_ADDRESS, err.code) - } - if client != nil { - defer client.Close() - t.Fatalf("Expected nil client for invalid Ethereum address") - } -} - -func TestInvalidStreamPartId(t *testing.T) { - lib := NewLibStreamrProxyClient() - defer lib.Close() - client, err := NewProxyClient(validEthereumAddress, invalidStreamPartId) - if err == nil { - t.Fatalf("Expected error for invalid stream part id") - } else if err.code != ERROR_INVALID_STREAM_PART_ID { - t.Fatalf("Expected error code %s, got %s", ERROR_INVALID_STREAM_PART_ID, err.code) - } - if client != nil { - defer client.Close() - t.Fatalf("Expected nil client for invalid stream part id") - } -} - -func TestNoProxiesDefined(t *testing.T) { - lib := NewLibStreamrProxyClient() - defer lib.Close() - client, err := NewProxyClient(validEthereumAddress, validStreamPartId) - if err != nil { - t.Fatalf("Failed to create ProxyClient: %v", err) - } - defer client.Close() - result := client.Connect([]Proxy {}) - if result.errors == nil { - t.Fatalf("Expected error code %s, got nil", ERROR_NO_PROXIES_DEFINED) - } else if result.errors[0].code != ERROR_NO_PROXIES_DEFINED { - t.Fatalf("Expected error code %s, got %s", ERROR_NO_PROXIES_DEFINED, result.errors[0].code) - } - if len(result.successful) != 0 { - t.Fatalf("Expected nil successful proxies for no proxies defined") - } -} - -func TestInvalidProxyUrl(t *testing.T) { - lib := NewLibStreamrProxyClient() - defer lib.Close() - client, err := NewProxyClient(validEthereumAddress, validStreamPartId) - if err != nil { - t.Fatalf("Failed to create ProxyClient: %v", err) - } - defer client.Close() - proxies := []Proxy{ - Proxy{websocketUrl: invalidProxyUrl, ethereumAddress: validEthereumAddress}, - } - fmt.Println("calling connect") - result := client.Connect(proxies) - fmt.Println("Testing invalid proxy URL") - if len(result.errors) != 1 { - t.Fatalf("Expected 1 error for invalid proxy url, got %d", len(result.errors)) - } else if result.errors[0].code != ERROR_INVALID_PROXY_URL { - t.Fatalf("Expected error code %s, got %s", ERROR_INVALID_PROXY_URL, result.errors[0].code) - } - if len(result.successful) != 0 { - t.Fatalf("Expected nil successful proxies for invalid proxy url") - } -} - -func TestInvalidProxyEthereumAddress(t *testing.T) { - lib := NewLibStreamrProxyClient() - defer lib.Close() - client, err := NewProxyClient(validEthereumAddress, validStreamPartId) - if err != nil { - t.Fatalf("Failed to create ProxyClient: %v", err) - } - defer client.Close() - proxies := []Proxy{ - Proxy{websocketUrl: validProxyUrl, ethereumAddress: invalidEthereumAddress}, - } - result := client.Connect(proxies) - if len(result.errors) != 1 { - t.Fatalf("Expected 1 error for invalid proxy ethereum address, got %d", len(result.errors)) - } else if result.errors[0].code != ERROR_INVALID_ETHEREUM_ADDRESS { - t.Fatalf("Expected error code %s, got %s", ERROR_INVALID_ETHEREUM_ADDRESS, result.errors[0].code) - } - if len(result.successful) != 0 { - t.Fatalf("Expected nil successful proxies for invalid proxy ethereum address") - } -} - -func TestProxyConnectionFailed(t *testing.T) { - lib := NewLibStreamrProxyClient() - defer lib.Close() - client, err := NewProxyClient(validEthereumAddress, validStreamPartId) - if err != nil { - t.Fatalf("Failed to create ProxyClient: %v", err) - } - defer client.Close() - proxies := []Proxy{ - Proxy{websocketUrl: nonExistentProxyUrl0, ethereumAddress: validEthereumAddress}, - } - result := client.Connect(proxies) - if len(result.errors) != 1 { - t.Fatalf("Expected 1 error for proxy connection failed, got %d", len(result.errors)) - } else if result.errors[0].code != ERROR_PROXY_CONNECTION_FAILED { - t.Fatalf("Expected error code %s, got %s", ERROR_PROXY_CONNECTION_FAILED, result.errors[0].code) - } - if len(result.successful) != 0 { - t.Fatalf("Expected nil successful proxies for proxy connection failed") - } -} - -func TestThreeProxyConnectionsFailed(t *testing.T) { - lib := NewLibStreamrProxyClient() - defer lib.Close() - client, err := NewProxyClient(validEthereumAddress, validStreamPartId) - if err != nil { - t.Fatalf("Failed to create ProxyClient: %v", err) - } - defer client.Close() - proxies := []Proxy{ - Proxy{websocketUrl: nonExistentProxyUrl0, ethereumAddress: validEthereumAddress}, - Proxy{websocketUrl: nonExistentProxyUrl1, ethereumAddress: validEthereumAddress2}, - Proxy{websocketUrl: nonExistentProxyUrl2, ethereumAddress: validEthereumAddress3}, - } - result := client.Connect(proxies) - if len(result.errors) != 3 { - t.Fatalf("Expected 3 errors for three proxy connections failed, got %d", len(result.errors)) - } else { - for i, err := range result.errors { - if err.code != ERROR_PROXY_CONNECTION_FAILED { - t.Fatalf("Expected error code %s for error %d, got %s", ERROR_PROXY_CONNECTION_FAILED, i, err.code) - } - expectedWebsocketUrl := "" - expectedEthereumAddress := "" - switch i { - case 0: - expectedWebsocketUrl = nonExistentProxyUrl0 - expectedEthereumAddress = validEthereumAddress - case 1: - expectedWebsocketUrl = nonExistentProxyUrl1 - expectedEthereumAddress = validEthereumAddress2 - case 2: - expectedWebsocketUrl = nonExistentProxyUrl2 - expectedEthereumAddress = validEthereumAddress3 - } - if err.proxy.websocketUrl != expectedWebsocketUrl { - t.Fatalf("Expected websocket URL %s for error %d, got %s", expectedWebsocketUrl, i, err.proxy.websocketUrl) - } - if err.proxy.ethereumAddress != expectedEthereumAddress { - t.Fatalf("Expected ethereum address %s for error %d, got %s", expectedEthereumAddress, i, err.proxy.ethereumAddress) - } - } - } - if len(result.successful) != 0 { - t.Fatalf("Expected nil successful proxies for three proxy connections failed") - } -} \ No newline at end of file diff --git a/packages/streamr-libstreamrproxyclient/wrappers/go/test.sh b/packages/streamr-libstreamrproxyclient/wrappers/go/test.sh deleted file mode 100755 index 166b5e08..00000000 --- a/packages/streamr-libstreamrproxyclient/wrappers/go/test.sh +++ /dev/null @@ -1,26 +0,0 @@ -#! /bin/bash - -BASE_DIR=$(pwd) - -if [[ "$OSTYPE" == "darwin"* ]] && [[ "$(uname -m)" == "arm64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/arm64-osx/lib/Debug) - export DYLD_LIBRARY_PATH=$LIB_PATH:$DYLD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi -if [[ "$OSTYPE" == "darwin"* ]] && [[ "$(uname -m)" == "x86_64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/x64-osx/lib/Debug) - export DYLD_LIBRARY_PATH=$LIB_PATH:$DYLD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi -if [[ "$OSTYPE" == "linux-gnu"* ]] && [[ "$(uname -m)" == "x86_64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/x64-linux/lib/Debug) - export LD_LIBRARY_PATH=$LIB_PATH:$LD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi -if [[ "$OSTYPE" == "linux-gnu"* ]] && [[ "$(uname -m)" == "aarch64" ]]; then - LIB_PATH=$(realpath $BASE_DIR/../../dist/arm64-linux/lib/Debug) - export LD_LIBRARY_PATH=$LIB_PATH:$LD_LIBRARY_PATH - export CGO_LDFLAGS="-L$LIB_PATH" -fi - -go test -skip=TestPublishToServer \ No newline at end of file diff --git a/packages/streamr-libstreamrproxyclient/wrappers/python/README.md b/packages/streamr-libstreamrproxyclient/wrappers/python/README.md index e69de29b..f4935a30 100644 --- a/packages/streamr-libstreamrproxyclient/wrappers/python/README.md +++ b/packages/streamr-libstreamrproxyclient/wrappers/python/README.md @@ -0,0 +1,95 @@ +# Python wrapper for the StreamrProxyClient + +This is a Python wrapper for the StreamrProxyClient C++ library. It is used to publish data to the Streamr network. + +## Installation + +```bash +python -m pip install libstreamrproxyclient +``` +The package is distributed as a binary wheel and is available for MacOS (arm64 and x86_64) and Linux (arm64 and x86_64). + +## Usage example + +```python +from streamrproxyclient.libstreamrproxyclient import ( + Proxy, + LibStreamrProxyClient, + ProxyClient +) + +proxy_ethereum_address = "0xd0d14b38d1f6b59d3772a63d84ece0a79e6e1c1f" +proxy_url = "ws://95.216.15.80:44211" +stream_part_id = "0xd2078dc2d780029473a39ce873fc182587be69db/low-level-client#0" +own_ethereum_address = "0xa5374e3c19f15e1847881979dd0c6c9ffe846bd5" +ethereum_private_key = "23bead9b499af21c4c16e4511b3b6b08c3e22e76e0591f5ab5ba8d4c3a5b1820" + + +with LibStreamrProxyClient() as lib: + with ProxyClient(lib, own_ethereum_address, stream_part_id) as client: + result = client.connect([Proxy(proxy_url, proxy_ethereum_address)]) + assert len(result.errors) == 0 + assert len(result.successful) == 1 + + result = client.publish(b"Hello from python!", ethereum_private_key) + assert len(result.errors) == 0 + assert len(result.successful) == 1 +``` + +## API documentation + +### Classes + +#### Proxy +Contains information about a proxy node in the Streamr network. + +Methods: +- `__init__(websocket_url: str, ethereum_address: str)`: Initialize a Proxy instance with websocket URL and Ethereum address +- `from_c_proxy(c_proxy)`: Create Proxy instance from C struct (internal use) + +#### Error +Represents an error from the C library. + +Attributes: +- `message`: Error message string +- `code`: Error code string +- `proxy`: Associated Proxy instance if applicable + +#### ProxyClientException +Exception raised when C library operations fail. + +Attributes: +- `error`: The Error instance containing details + +#### ProxyClientResult +Result of proxy client operations. + +Attributes: +- `errors`: List of Error instances if operation had errors +- `successful`: List of successful Proxy instances + +#### LibStreamrProxyClient +Wrapper for the C library. Use as context manager. + +Methods: +- `__enter__()`: Load and initialize C library +- `__exit__()`: Cleanup C library + +#### ProxyClient +Main client for interacting with proxies. Use as context manager. + +Methods: +- `__init__(lib: LibStreamrProxyClient, ownEthereumAddress: str, streamPartId: str)`: Initialize with library instance, Ethereum address and stream ID +- `connect(proxies: list[Proxy]) -> ProxyClientResult`: Connect to list of proxies +- `publish(data: bytes, ethereumPrivateKey: str = None) -> ProxyClientResult`: Publish data to connected proxies + +### Error Codes + +- `ERROR_INVALID_ETHEREUM_ADDRESS`: Invalid Ethereum address format +- `ERROR_INVALID_STREAM_PART_ID`: Invalid stream part ID format +- `ERROR_PROXY_CLIENT_NOT_FOUND`: Proxy client instance not found +- `ERROR_INVALID_PROXY_URL`: Invalid proxy websocket URL +- `ERROR_NO_PROXIES_DEFINED`: No proxies provided +- `ERROR_PROXY_CONNECTION_FAILED`: Failed to connect to proxy +- `ERROR_PROXY_BROADCAST_FAILED`: Failed to broadcast message to proxy + diff --git a/packages/streamr-libstreamrproxyclient/wrappers/python/pyproject.toml b/packages/streamr-libstreamrproxyclient/wrappers/python/pyproject.toml index c46d18ab..8a340527 100644 --- a/packages/streamr-libstreamrproxyclient/wrappers/python/pyproject.toml +++ b/packages/streamr-libstreamrproxyclient/wrappers/python/pyproject.toml @@ -1,27 +1,26 @@ [build-system] -requires = ["hatchling"] +requires = [ "hatchling",] build-backend = "hatchling.build" [project] name = "libstreamrproxyclient" -version = "2.0.0" -dependencies = [ -] +version = "2.0.5" +dependencies = [] requires-python = ">=3.12" -authors = [ - {name = "Petri Savolainen", email = "petri.savolainen@streamr.network"} -] -maintainers = [ - {name = "Petri Savolainen", email = "petri.savolainen@streamr.network"} -] description = "Python bindings for libstreamrproxyclient" readme = "README.md" -license = {file = "LICENSE.txt"} -keywords = ["streamr", "proxy", "client"] -classifiers = [ - "Development Status :: 4 - Beta", - "Programming Language :: Python" -] +keywords = [ "streamr", "proxy", "client",] +classifiers = [ "Development Status :: 4 - Beta", "Programming Language :: Python",] +[[project.authors]] +name = "Petri Savolainen" +email = "petri.savolainen@streamr.network" + +[[project.maintainers]] +name = "Petri Savolainen" +email = "petri.savolainen@streamr.network" + +[project.license] +file = "LICENSE.txt" [project.urls] Homepage = "https://github.com/streamr-dev/native-sdk" @@ -29,6 +28,6 @@ Documentation = "https://github.com/streamr-dev/native-sdk/tree/main/wrappers/py Repository = "https://github.com/streamr-dev/native-sdk.git" [tool.hatch.build.targets.wheel] -packages = ["src/streamrproxyclient"] +packages = [ "src/streamrproxyclient",] -[tool.hatch.build.targets.wheel.hooks.custom] \ No newline at end of file +[tool.hatch.build.targets.wheel.hooks.custom] diff --git a/packages/streamr-libstreamrproxyclient/wrappers/python/src/streamrproxyclient/libstreamrproxyclient.dylib b/packages/streamr-libstreamrproxyclient/wrappers/python/src/streamrproxyclient/libstreamrproxyclient.dylib deleted file mode 120000 index 44b945ee..00000000 --- a/packages/streamr-libstreamrproxyclient/wrappers/python/src/streamrproxyclient/libstreamrproxyclient.dylib +++ /dev/null @@ -1 +0,0 @@ -../../../../dist/arm64-osx/lib/Debug/libstreamrproxyclient.dylib \ No newline at end of file