diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..c8e65c60 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,26 @@ +name: CI + +on: + push: + pull_request: + schedule: + - cron: '0 0 * * 0' + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + fail-fast: false + steps: + - name: Checkout + uses: actions/checkout@v2.0.0 + + - name: Build project + uses: nicledomaS/cmake_build_action@v1.3 + with: + submodule_update: ON + run_tests: ON + unit_test_build: -DBUILD_UNIT_TESTS=ON + cmake_args: -DCMAKE_CXX_FLAGS=-std=c++11 diff --git a/.gitignore b/.gitignore index 989bd14a..ec9c2f5b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,10 @@ build/ -**/*.user \ No newline at end of file +**/*.user + +CMakeCache.txt +CMakeFiles/ +Makefile +cmake_install.cmake +install_manifest.txt +libsioclient.a +.DS_Store \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 2644de04..6c672230 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "lib/rapidjson"] path = lib/rapidjson url = https://github.com/miloyip/rapidjson.git +[submodule "lib/asio"] + path = lib/asio + url = https://github.com/chriskohlhoff/asio.git diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9c865bac..00000000 --- a/.travis.yml +++ /dev/null @@ -1,18 +0,0 @@ -language: cpp - -compiler: - - clang - -before_install: - - sudo apt-get install clang git libssl-dev - - sudo add-apt-repository -y ppa:boost-latest/ppa - - sudo add-apt-repository -y ppa:kubuntu-ppa/backports - - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test -y - - sudo apt-get update -yqq - - sudo apt-get install -y libboost1.55-dev libboost-system1.55-dev libboost-date-time1.55-dev libboost-random1.55-dev - - sudo apt-get install -y cmake g++-4.8 - - sed -i -e 's/cmake_minimum_required(VERSION 3.1.0/cmake_minimum_required(VERSION 2.8.12/' ./CMakeLists.txt -script: - - cmake -D CMAKE_CXX_FLAGS=-std=c++11 . - - make - - make install diff --git a/API.md b/API.md index 4cc16460..71da07b3 100644 --- a/API.md +++ b/API.md @@ -182,6 +182,19 @@ Set listener for reconnecting is in process. Set listener for reconnecting event, called once a delayed connecting is scheduled. +#### Logs +`void set_logs_default()` + +Configure logs to the default level (connect, disconnect, app) + +`void set_logs_quiet()` + +Configure logs to the quiet level + +`void set_logs_verbose()` + +Configure logs to the verbose level + #### Namespace `socket::ptr socket(std::string const& nsp)` diff --git a/BOOST.md b/BOOST.md deleted file mode 100644 index d9c46460..00000000 --- a/BOOST.md +++ /dev/null @@ -1,21 +0,0 @@ -## Boost setup - -1. Download boost from [boost.org](http://www.boost.org/). -1. Unpack boost to some place. -1. Run either .\bootstrap.bat (on Windows), or ./bootstrap.sh (on other operating systems) under boost folder. - -## Boost build (Build the necessary subset only) - -#### Windows (or other mainstream desktop platforms shall work too): -Run with following script will build the necessary subset: - -```bash -bjam install --prefix="" --with-system --with-date_time --with-random link=static runtime-link=shared threading=multi -``` -Optionally You can merge all output .lib files into a fat one,especially if you're not using cmake. - -In output folder, run: - -```bash -lib.exe /OUT:boost.lib * -``` diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..d1691679 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,40 @@ +# [2.1.0](https://github.com/socketio/socket.io-client-cpp/compare/2.0.0...2.1.0) (2021-10-12) + + +### Bug Fixes + +* fix ASIO_STANDALONE release build trying to use boost::random ([#301](https://github.com/socketio/socket.io-client-cpp/issues/301)) ([168ce9d](https://github.com/socketio/socket.io-client-cpp/commit/168ce9d10b4ac667c43fe16b4cf530f6a3749235)) +* fix LOG call syntax ([#301](https://github.com/socketio/socket.io-client-cpp/issues/301)) ([c09221f](https://github.com/socketio/socket.io-client-cpp/commit/c09221f357effe1a5a0fc0e7d7902eba1ab0484d)) + + +### Features + +* support TLSv1.2 and newer ([#321](https://github.com/socketio/socket.io-client-cpp/issues/321)) ([7c60ba9](https://github.com/socketio/socket.io-client-cpp/commit/7c60ba9d1e5e58de57f127025bcf69f4baecd2b4)) + + + +# [3.1.0](https://github.com/socketio/socket.io-client-cpp/compare/3.0.0...3.1.0) (2021-10-12) + + +### Bug Fixes + +* lower the minimum CMake supported version ([b196fa7](https://github.com/socketio/socket.io-client-cpp/commit/b196fa7537cd3f7bed626ead873a7b71d1293c0d)) +* handle closing sockets upon on_fail events ([d1c73b7](https://github.com/socketio/socket.io-client-cpp/commit/d1c73b73a8f536da3d353eac2a560af9791b13e3)) +* resolve client_impl::ping LOG call syntax in debug builds ([e7de4eb](https://github.com/socketio/socket.io-client-cpp/commit/e7de4ebf64f4f49e18594a2c093c07beb963579a)) + + +### Features + +* allow resource path to be set in connection URI ([#134](https://github.com/socketio/socket.io-client-cpp/issues/134)) ([36a8cd4](https://github.com/socketio/socket.io-client-cpp/commit/36a8cd45272aa51f0f6ef27aa4744dbc6e8421f7)) +* add support for logging configuration ([1b42ce7](https://github.com/socketio/socket.io-client-cpp/commit/1b42ce738f4c3e260f79bcb143bfe6efcdce5709)) +* support TLSv1.2 and newer ([#321](https://github.com/socketio/socket.io-client-cpp/issues/321)) ([82d39a9](https://github.com/socketio/socket.io-client-cpp/commit/82d39a90ef118500a0329d214eec331db983bd74)) + + + +# [3.0.0](https://github.com/socketio/socket.io-client-cpp/compare/2.0.0...3.0.0) (2021-01-09) + + +### Features + +* add support for Socket.IO v3 ([ec4d540](https://github.com/socketio/socket.io-client-cpp/commit/ec4d540ad54593604ac2091e67ffc2a6d9a00db6)) + diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c2fad3f..edaba3be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,84 +1,181 @@ -cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) -PROJECT(sioclient) +cmake_minimum_required(VERSION 3.4 FATAL_ERROR) + +PROJECT(sioclient + VERSION 3.1.0 +) option(BUILD_SHARED_LIBS "Build the shared library" OFF) -option(Boost_USE_STATIC_LIBS "Use Boost static version" ON) - -set(MAJOR 1) -set(MINOR 6) -set(PATCH 0) - -if(NOT CMAKE_BUILD_TYPE ) -MESSAGE(STATUS "not define build type, set to release" ) -set(CMAKE_BUILD_TYPE Release ) -elseif(NOT (${CMAKE_BUILD_TYPE} STREQUAL "Release" OR ${CMAKE_BUILD_TYPE} STREQUAL "Debug" )) -MESSAGE(SEND_ERROR "CMAKE_BUILD_TYPE must be either Release or Debug") -return() +option(BUILD_UNIT_TESTS "Builds unit tests target" OFF) +option(USE_SUBMODULES "Use source in local submodules instead of system libraries" ON) +option(DISABLE_LOGGING "Do not print logging messages" OFF) + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(DEFAULT_BUILD_TYPE "Release") + message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.") + set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE) + + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() -set(BOOST_VER "1.55.0" CACHE STRING "boost version" ) +# Only do these if this is the main project, and not if it is included through add_subdirectory +if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) + # Testing only available if this is the main app + # Note this needs to be done in the main CMakeLists + # since it calls enable_testing, which must be in the + # main CMakeLists. + include(CTest) +endif() -set(Boost_USE_MULTITHREADED ON) -set(Boost_USE_STATIC_RUNTIME OFF) -find_package(Boost ${BOOST_VER} REQUIRED COMPONENTS system date_time random) +add_definitions( + # These will force ASIO to compile without Boost + -DBOOST_DATE_TIME_NO_LIB + -DBOOST_REGEX_NO_LIB + -DASIO_STANDALONE + + # These will force sioclient to compile with C++11 + -D_WEBSOCKETPP_CPP11_STL_ + -D_WEBSOCKETPP_CPP11_FUNCTIONAL_ + -D_WEBSOCKETPP_CPP11_TYPE_TRAITS_ + -D_WEBSOCKETPP_CPP11_CHRONO_ +) + +if (MSVC) + # To solve error C1128: number of sections exceeded object file format limit: compile with /bigobj + add_compile_options(/bigobj) +endif() -aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src ALL_SRC) -aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src/internal ALL_SRC) -file(GLOB ALL_HEADERS ${CMAKE_CURRENT_LIST_DIR}/src/*.h ) -set(SIO_INCLUDEDIR ${CMAKE_CURRENT_LIST_DIR}) +if (DISABLE_LOGGING) + add_definitions(-DSIO_DISABLE_LOGGING) +endif() +set(ALL_SRC + "src/sio_client.cpp" + "src/sio_socket.cpp" + "src/internal/sio_client_impl.cpp" + "src/internal/sio_packet.cpp" +) add_library(sioclient ${ALL_SRC}) -target_include_directories(sioclient PRIVATE ${Boost_INCLUDE_DIRS} - ${CMAKE_CURRENT_LIST_DIR}/src - ${CMAKE_CURRENT_LIST_DIR}/lib/websocketpp - ${CMAKE_CURRENT_LIST_DIR}/lib/rapidjson/include + +if(USE_SUBMODULES) + set(MODULE_INCLUDE_DIRS + ${CMAKE_CURRENT_LIST_DIR}/lib/websocketpp + ${CMAKE_CURRENT_LIST_DIR}/lib/rapidjson/include + ${CMAKE_CURRENT_LIST_DIR}/lib/asio/asio/include + ) +else() + find_package(websocketpp CONFIG REQUIRED) + find_package(asio CONFIG REQUIRED) + find_package(RapidJSON CONFIG REQUIRED) + target_link_libraries(sioclient PRIVATE websocketpp::websocketpp asio asio::asio rapidjson) +endif() + +target_include_directories(sioclient + PUBLIC + $ + $ + PRIVATE + ${MODULE_INCLUDE_DIRS} ) set_property(TARGET sioclient PROPERTY CXX_STANDARD 11) set_property(TARGET sioclient PROPERTY CXX_STANDARD_REQUIRED ON) -target_link_libraries(sioclient PRIVATE ${Boost_LIBRARIES}) + if(BUILD_SHARED_LIBS) -set_target_properties(sioclient - PROPERTIES - SOVERSION ${MAJOR} - VERSION ${MAJOR}.${MINOR}.${PATCH} - ) + set_target_properties(sioclient + PROPERTIES + SOVERSION ${PROJECT_VERSION_MAJOR} + VERSION ${PROJECT_VERSION} + ) endif() + list(APPEND TARGET_LIBRARIES sioclient) find_package(OpenSSL) + if(OPENSSL_FOUND) -add_library(sioclient_tls ${ALL_SRC}) -target_include_directories(sioclient_tls PRIVATE ${Boost_INCLUDE_DIRS} - ${CMAKE_CURRENT_LIST_DIR}/src - ${CMAKE_CURRENT_LIST_DIR}/lib/websocketpp - ${CMAKE_CURRENT_LIST_DIR}/lib/rapidjson/include - ${OPENSSL_INCLUDE_DIR} -) + add_library(sioclient_tls ${ALL_SRC}) + target_include_directories(sioclient_tls PUBLIC + $ + $ + PRIVATE + ${MODULE_INCLUDE_DIRS} + ${OPENSSL_INCLUDE_DIR} + ) -set_property(TARGET sioclient_tls PROPERTY CXX_STANDARD 11) -set_property(TARGET sioclient_tls PROPERTY CXX_STANDARD_REQUIRED ON) -target_link_libraries(sioclient_tls PRIVATE ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ) -target_compile_definitions(sioclient_tls PRIVATE -DSIO_TLS) -if(BUILD_SHARED_LIBS) -set_target_properties(sioclient_tls - PROPERTIES - SOVERSION ${MAJOR} - VERSION ${MAJOR}.${MINOR}.${PATCH} - ) -endif() -list(APPEND TARGET_LIBRARIES sioclient_tls) + set_property(TARGET sioclient_tls PROPERTY CXX_STANDARD 11) + set_property(TARGET sioclient_tls PROPERTY CXX_STANDARD_REQUIRED ON) + + target_link_libraries(sioclient_tls PRIVATE OpenSSL::SSL OpenSSL::Crypto) + if (NOT USE_SUBMODULES) + target_link_libraries(sioclient_tls PRIVATE websocketpp::websocketpp asio asio::asio rapidjson) + endif() + + target_compile_definitions(sioclient_tls PRIVATE -DSIO_TLS) + + if(BUILD_SHARED_LIBS) + set_target_properties(sioclient_tls + PROPERTIES + SOVERSION ${PROJECT_VERSION_MAJOR} + VERSION ${PROJECT_VERSION} + ) + endif() + list(APPEND TARGET_LIBRARIES sioclient_tls) endif() -install(FILES ${ALL_HEADERS} - DESTINATION "${CMAKE_CURRENT_LIST_DIR}/build/include" +export(PACKAGE sioclient) + +include(GNUInstallDirs) + +file(GLOB ALL_HEADERS ${CMAKE_CURRENT_LIST_DIR}/src/*.h) +install(FILES ${ALL_HEADERS} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) -install(TARGETS ${TARGET_LIBRARIES} - DESTINATION "${CMAKE_CURRENT_LIST_DIR}/build/lib/${CMAKE_BUILD_TYPE}" +install(TARGETS ${TARGET_LIBRARIES} EXPORT sioclientTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) -install(FILES ${Boost_LIBRARIES} - DESTINATION "${CMAKE_CURRENT_LIST_DIR}/build/lib/${CMAKE_BUILD_TYPE}" +# === generate a CMake Config File === +include(CMakePackageConfigHelpers) +set(ConfigPackageLocation ${CMAKE_INSTALL_LIBDIR}/cmake/sioclient) +string(REGEX REPLACE "([^;]+)" "find_dependency(\\1)" _find_dependency_calls "${_package_dependencies}") +string(REPLACE ";" "\n" _find_dependency_calls "${_find_dependency_calls}") + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/sioclient/sioclientConfigVersion.cmake" + VERSION ${sioclient_VERSION} + COMPATIBILITY AnyNewerVersion ) + +export(EXPORT sioclientTargets + FILE "${CMAKE_CURRENT_BINARY_DIR}/sioclient/sioclientTargets.cmake" + NAMESPACE sioclient:: +) + +configure_package_config_file(sioclientConfig.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/sioclient/sioclientConfig.cmake" + INSTALL_DESTINATION "${ConfigPackageLocation}" +) + +install(EXPORT sioclientTargets + NAMESPACE + sioclient:: + DESTINATION + ${ConfigPackageLocation} +) +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/sioclient/sioclientConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/sioclient/sioclientConfigVersion.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/sioclient/sioclientTargets.cmake" + DESTINATION + ${ConfigPackageLocation} +) + +if((CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) OR BUILD_UNIT_TESTS) + add_subdirectory(test) +endif() diff --git a/INSTALL.md b/INSTALL.md index 614280df..77069709 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,48 +1,28 @@ ## Install ### With CMake -1. Install boost, see [Boost setup](#boost_setup) section. -2. Use `git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git` to clone your local repo. -3. Run `cmake -DBOOST_ROOT:STRING= -DBOOST_VER:STRING= ./` -4. Run `make install`(if makefile generated) or open generated project (if project file generated) to build. -5. Outputs is under `./build`, link with the all static libs under `./build/lib` and include headers under `./build/include` in your client code where you want to use it. - -* If you're using boost without install,you can specify `boost include dir` and `boost lib dir` separately by: -```bash -cmake --DBOOST_INCLUDEDIR= --DBOOST_LIBRARYDIR= --DBOOST_VER:STRING= -./ -``` -* CMake didn't allow merging static libraries,but they're all copied to `./build/lib`, you can DIY if you like. +1. Use `git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git` to clone your local repo. +2. Run `cmake ./` +3. Run `make install`(if makefile generated) or open generated project (if project file generated) to build. +4. Outputs is under `./build`, link with the all static libs under `./build/lib` and include headers under `./build/include` in your client code where you want to use it. ### Without CMake -1. Install boost, see [Boost setup](#boost_setup) section. -2. Use `git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git` to clone your local repo. -3. Add `/include`,`./lib/websocketpp` and `./lib/rapidjson/include` to headers search path. -4. Include all files under `./src` in your project, add `sio_client.cpp`,`sio_socket.cpp`,`internal/sio_client_impl.cpp`, `internal/sio_packet.cpp` to source list. -5. Add `/lib` to library search path, add `boost.lib`(Win32) or `-lboost`(Other) link option. -6. Include `sio_client.h` in your client code where you want to use it. - -## Boost setup +1. Use `git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git` to clone your local repo. +2. Add `./lib/asio/asio/include`, `./lib/websocketpp` and `./lib/rapidjson/include` to headers search path. +3. Include all files under `./src` in your project, add `sio_client.cpp`,`sio_socket.cpp`,`internal/sio_client_impl.cpp`, `internal/sio_packet.cpp` to source list. +4. Add `BOOST_DATE_TIME_NO_LIB`, `BOOST_REGEX_NO_LIB`, `ASIO_STANDALONE`, `_WEBSOCKETPP_CPP11_STL_` and `_WEBSOCKETPP_CPP11_FUNCTIONAL_` to the preprocessor definitions +5. Include `sio_client.h` in your client code where you want to use it. -1. Download boost from [boost.org](http://www.boost.org/). -1. Unpack boost to some place. -1. Run either .\bootstrap.bat (on Windows), or ./bootstrap.sh (on other operating systems) under boost folder. +### With vcpkg -## Boost build (Build the necessary subset only) -Windows (or other mainstream desktop platforms shall work too): - -The following script will build the necessary subset: +You can download and install the Socket.IO C++ client using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: ```bash -bjam install --prefix="" --with-system --with-date_time --with-random link=static runtime-link=shared threading=multi +git clone https://github.com/Microsoft/vcpkg.git +cd vcpkg +./bootstrap-vcpkg.sh +./vcpkg integrate install +vcpkg install socket-io-client ``` -Optionally You can merge all output .lib files into a fat one, especially if you're not using cmake. - -In output folder, run: -```bash -lib.exe /OUT:boost.lib * -``` +The Socket.IO client port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. diff --git a/INSTALL_IOS.md b/INSTALL_IOS.md index 881b2085..e154cf85 100644 --- a/INSTALL_IOS.md +++ b/INSTALL_IOS.md @@ -1,12 +1,6 @@ ## iOS -### Option 1: Cocoapods - -``` -pod 'SocketIO-Client-CPP' -``` - -### Option 2: Create a static library +### Option 1: Create a static library 1. Create a static library 1. Copy the header files into xcode @@ -26,7 +20,7 @@ libtool -static -o libUniversalDebug.a Debug-iphoneos/libsioclient.a Debug-iphon ``` -### Option 3: Manual integration +### Option 2: Manual integration Use this [shell](https://gist.github.com/melode11/a90114a2abf009ca22ea) to download and build boost completely automattically. It installs boost to `/prefix`. diff --git a/README.md b/README.md index b30c7d8f..63a78041 100755 --- a/README.md +++ b/README.md @@ -1,24 +1,50 @@ # Socket.IO C++ Client -[![Build Status](https://travis-ci.org/socketio/socket.io-client-cpp.svg)](https://travis-ci.org/socketio/socket.io-client-cpp) + +[![Build Status](https://github.com/socketio/socket.io-client-cpp/workflows/CI/badge.svg)](https://github.com/socketio/socket.io-client-cpp/actions) By virtue of being written in C++, this client works in several different platforms. The [examples](https://github.com/socketio/socket.io-client-cpp/tree/master/examples) folder contains an iPhone, QT and Console example chat client! It depends on [websocket++](https://github.com/zaphoyd/websocketpp) and is inspired by [socket.io-clientpp](https://github.com/ebshimizu/socket.io-clientpp). [![Clients with iPhone, QT, Console and web](https://cldup.com/ukvVVZmvYV.png)](https://github.com/socketio/socket.io-client-cpp/tree/master/examples) +## Compatibility table + + + + + + + + + + + + + + + + + + + + +
C++ Client versionSocket.IO server version
1.x / 2.x3.x / 4.x
2.x (2.x branch)YESYES, with allowEIO3: true
3.x (master branch)NOYES
+ ## Features - 100% written in modern C++11 -- Compatible with socket.io 1.0+ protocol - Binary support - Automatic JSON encoding - Multiplex support - Similar API to the Socket.IO JS client - Cross platform +Note: Only the WebSocket transport is currently implemented (no fallback to HTTP long-polling) + ## Installation alternatives * [With CMAKE](./INSTALL.md#with-cmake) * [Without CMAKE](./INSTALL.md#without-cmake) +* [With VCPKG](./INSTALL.md#with-vcpkg) * [iOS and OS X](./INSTALL_IOS.md) * Option 1: Cocoapods * Option 2: Create a static library diff --git a/examples/Console/main.cpp b/examples/Console/main.cpp index 846f46fa..9a95dfb2 100755 --- a/examples/Console/main.cpp +++ b/examples/Console/main.cpp @@ -69,7 +69,7 @@ int participants = -1; socket::ptr current_socket; -void bind_events(socket::ptr &socket) +void bind_events() { current_socket->on("new message", sio::socket::event_listener_aux([&](string const& name, message::ptr const& data, bool isAck,message::list &ack_resp) { @@ -141,7 +141,7 @@ MAIN_FUNC _cond.wait(_lock); } _lock.unlock(); - bind_events(current_socket); + bind_events(); HIGHLIGHT("Start to chat,commands:\n'$exit' : exit chat\n'$nsp ' : change namespace"); for (std::string line; std::getline(std::cin, line);) { @@ -166,7 +166,7 @@ MAIN_FUNC current_socket->close(); } current_socket = h.socket(new_nsp); - bind_events(current_socket); + bind_events(); //if change to default nsp, we do not need to login again (since it is not closed). if(current_socket->get_namespace() == "/") { diff --git a/examples/QT/README.md b/examples/QT/README.md index 03ccb8ec..a26610d1 100644 --- a/examples/QT/README.md +++ b/examples/QT/README.md @@ -2,7 +2,7 @@ In this tutorial we’ll learn how to create a QT chat application that communicates with a [Socket.IO Node.JS chat server](https://github.com/Automattic/socket.io/tree/master/examples/chat). -###Introduction +### Introduction To follow along, start by cloning the repository: [socket.io-client-cpp](https://github.com/socketio/socket.io-client-cpp). Using: @@ -39,7 +39,7 @@ SioChatDemo |__mainwindow.ui ``` -###Import SioClient and config compile options. +### Import SioClient and config compile options. Let's copy the SioClient into the QT project as a subfolder `sioclient`. Edit `SioChatDemo.pro` to config paths and compile options, simply add: @@ -65,24 +65,7 @@ CONFIG+=c++11 `no_keywords` is for preventing qmake treat some function's name `emit` as the keyword of signal-slot mechanism. `c++11` ask for C++11 support. -##Import boost -Suppose we now have our boost `headers` and a fat boost `static lib` named `libboost.a`(non-win32) or `boost.lib`(win32) ready. - -To import them we need to edit `SioChatDemo.pro` again,add header include: - -```bash -INCLUDEPATH += `our boost headers folder` -``` - -also linker options: - -```bash -win32:CONFIG(release, debug|release): LIBS += -L`our Win32 boost static lib folder` -lboost -else:win32:CONFIG(debug, debug|release): LIBS += -L`our Win32 boost static lib folder` -lboost -else:unix: LIBS += -L`our osx boost static lib folder` -lboost -``` - -###Make up mainwindow ui. +### Make up mainwindow ui. Make up a simple ui by drag and drop widget from `Widget box` in left side. We finally end up with this: @@ -101,7 +84,7 @@ It contains: * a `QPushButton` at the bottomright for sending message, named `sendBtn` -###Add Slots in mainwindow +### Add Slots in mainwindow Slots need to be added in `mainwindow` class to handle UI events.They are * click login button @@ -122,7 +105,7 @@ public Q_SLOTS: void OnMessageReturn(); ``` -###Connect UI event signal and slots together +### Connect UI event signal and slots together Open `mainwindow.ui` in Design mode. switch to `signals/slots` mode by check `Menu->Edit->Edit Signals/Slots` By press left mouse on widget and drag on to the window (cursor will become a sign of electrical ground), to open the connection editor. @@ -135,7 +118,7 @@ We finally end up with this: ![QT signals&slots](https://cldup.com/Vsb-UXG3FC.jpg) -###Adding UI refresh Signals/Slots +### Adding UI refresh Signals/Slots `sio::client`'s callbacks are not in UI thread. However, UI is required to be updated by those callbacks, so we need some `Signal` for non-UI thread to "request" `Slots` functions been called in UI thread. Say if we want to signal `QListWidgetItem` being added, add: ```C++ @@ -160,7 +143,7 @@ Then connect them in `MainWindow` constructor. connect(this,SIGNAL(RequestAddListItem(QListWidgetItem*)),this,SLOT(AddListItem(QListWidgetItem*))); ``` -###Init sio::client in MainWindow +### Init sio::client in MainWindow For single window applications, simply let `MainWindow` class holding the `sio::client` object: declare a `unique_ptr` member of `sio::client` and Several event handling functions in `mainwindow.h` @@ -214,7 +197,7 @@ MainWindow::MainWindow(QWidget *parent) : } ``` -###Managing connection state +### Managing connection state We have several connection listeners for connection events. First we want to send login message once we're connected, get the default `socket` from `client` to do that. @@ -256,7 +239,7 @@ MainWindow::~MainWindow() } ``` -###Handle socket.io events +### Handle socket.io events We'll need to handle socket.io events in our functions bind to socket.io events. For example, we need to show received messages to the `listView` @@ -278,7 +261,7 @@ void MainWindow::OnNewMessage(std::string const& name,message::ptr const& data,b } ``` -###Sending chat message +### Sending chat message When `sendBtn` is clicked, we need to send the text in `messageEdit` to chatroom. Add code to `SendBtnClicked()`: @@ -301,7 +284,7 @@ void MainWindow::SendBtnClicked() } ``` -###Further reading +### Further reading You can run [Demo project](https://github.com/socketio/socket.io-client-cpp/tree/master/examples/QT/SioChatDemo) to have a closer look. Before running, please follow the [instructions](../../README.md#with_cmake) to make the sioclient library. diff --git a/lib/asio b/lib/asio new file mode 160000 index 00000000..230c0d2a --- /dev/null +++ b/lib/asio @@ -0,0 +1 @@ +Subproject commit 230c0d2ae035c5ce1292233fcab03cea0d341264 diff --git a/lib/websocketpp b/lib/websocketpp index ac5d7ea5..56123c87 160000 --- a/lib/websocketpp +++ b/lib/websocketpp @@ -1 +1 @@ -Subproject commit ac5d7ea5af9734de965688b54a7860259887b537 +Subproject commit 56123c87598f8b1dd471be83ca841ceae07f95ba diff --git a/sioclientConfig.cmake.in b/sioclientConfig.cmake.in new file mode 100644 index 00000000..a28fad84 --- /dev/null +++ b/sioclientConfig.cmake.in @@ -0,0 +1,7 @@ + +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +@_find_dependency_calls@ + +include("${CMAKE_CURRENT_LIST_DIR}/sioclientTargets.cmake") \ No newline at end of file diff --git a/src/internal/sio_client_impl.cpp b/src/internal/sio_client_impl.cpp index 8da8b8c6..d78da46f 100644 --- a/src/internal/sio_client_impl.cpp +++ b/src/internal/sio_client_impl.cpp @@ -7,35 +7,56 @@ // #include "sio_client_impl.h" +#include #include -#include -#include +#include #include #include // Comment this out to disable handshake logging to stdout -#if DEBUG || _DEBUG +#if (DEBUG || _DEBUG) && !defined(SIO_DISABLE_LOGGING) #define LOG(x) std::cout << x #else #define LOG(x) #endif -using boost::posix_time::milliseconds; -using namespace std; +#if SIO_TLS +// If using Asio's SSL support, you will also need to add this #include. +// Source: http://think-async.com/Asio/asio-1.10.6/doc/asio/using.html +// #include +#endif + +using std::chrono::milliseconds; + +namespace { + bool iequals(const std::string& a, const std::string& b) + { + size_t sz = a.size(); + if (b.size() != sz) { + return false; + } + for (size_t i = 0; i < sz; ++i) { + if (std::tolower(a[i]) != std::tolower(b[i])) { + return false; + } + } + return true; + } +} namespace sio { /*************************public:*************************/ template - client_impl::client_impl(const string& uri) : - m_base_url(uri), - m_con_state(con_closed), + client_impl::client_impl(const client_options& options) : + m_base_url(options.uri), m_ping_interval(0), m_ping_timeout(0), m_network_thread(), - m_reconn_attempts(0xFFFFFFFF), - m_reconn_made(0), + m_con_state(con_closed), m_reconn_delay(5000), - m_reconn_delay_max(25000) + m_reconn_delay_max(25000), + m_reconn_attempts(0xFFFFFFFF), + m_reconn_made(0) { using websocketpp::log::alevel; #ifndef DEBUG @@ -43,17 +64,21 @@ namespace sio m_client.set_access_channels(alevel::connect|alevel::disconnect|alevel::app); #endif // Initialize the Asio transport policy - m_client.init_asio(); + if (options.io_context != nullptr) { + m_client.init_asio(options.io_context); + } else { + m_client.init_asio(); + } // Bind the clients we are using - using websocketpp::lib::placeholders::_1; - using websocketpp::lib::placeholders::_2; - m_client.set_open_handler(lib::bind(&client_impl::on_open,this,_1)); - m_client.set_close_handler(lib::bind(&client_impl::on_close,this,_1)); - m_client.set_fail_handler(lib::bind(&client_impl::on_fail,this,_1)); - m_client.set_message_handler(lib::bind(&client_impl::on_message,this,_1,_2)); - m_packet_mgr.set_decode_callback(lib::bind(&client_impl::on_decode,this,_1)); - m_packet_mgr.set_encode_callback(lib::bind(&client_impl::on_encode,this,_1,_2)); + using std::placeholders::_1; + using std::placeholders::_2; + m_client.set_open_handler(std::bind(&client_impl::on_open,this,_1)); + m_client.set_close_handler(std::bind(&client_impl::on_close,this,_1)); + m_client.set_fail_handler(std::bind(&client_impl::on_fail,this,_1)); + m_client.set_message_handler(std::bind(&client_impl::on_message,this,_1,_2)); + m_packet_mgr.set_decode_callback(std::bind(&client_impl::on_decode,this,_1)); + m_packet_mgr.set_encode_callback(std::bind(&client_impl::on_encode,this,_1,_2)); template_init(); } @@ -63,9 +88,17 @@ namespace sio this->sockets_invoke_void(socket_on_close()); sync_close(); } - + + template + void client_impl::set_proxy_basic_auth(const std::string& uri, const std::string& username, const std::string& password) + { + m_proxy_base_url = uri; + m_proxy_basic_username = username; + m_proxy_basic_password = password; + } + template - void client_impl::connect(const string& uri, const map& query, const map& headers) + void client_impl::connect(const string& uri, const map& query, const map& headers, const message::ptr& auth) { if(m_reconn_timer) { @@ -100,16 +133,18 @@ namespace sio query_str.append("&"); query_str.append(it->first); query_str.append("="); - query_str.append(it->second); + string query_str_value=encode_query_string(it->second); + query_str.append(query_str_value); } - m_query_string=move(query_str); + m_query_string=std::move(query_str); m_http_headers = headers; + m_auth = auth; this->reset_states(); - m_client.get_io_service().dispatch(lib::bind(&client_impl::connect_impl,this,m_base_url,m_query_string)); - m_network_thread.reset(new thread(lib::bind(&client_impl::run_loop,this)));//uri lifecycle? - + m_abort_retries = false; + m_client.get_io_service().dispatch(std::bind(&client_impl::connect_impl,this,m_base_url,m_query_string)); + m_network_thread.reset(new thread(std::bind(&client_impl::run_loop,this)));//uri lifecycle? } template @@ -138,7 +173,7 @@ namespace sio } else { - pair p(aux,shared_ptr(new_socket(aux))); + pair p(aux,shared_ptr(new_socket(aux, m_auth))); return (m_sockets.insert(p).first)->second; } } @@ -147,16 +182,18 @@ namespace sio void client_impl::close() { m_con_state = con_closing; + m_abort_retries = true; this->sockets_invoke_void(&sio::socket::close); - m_client.get_io_service().dispatch(lib::bind(&client_impl::close_impl, this,close::status::normal,"End by user")); + m_client.get_io_service().dispatch(std::bind(&client_impl::close_impl, this,close::status::normal,"End by user")); } template void client_impl::sync_close() { m_con_state = con_closing; + m_abort_retries = true; this->sockets_invoke_void(&sio::socket::close); - m_client.get_io_service().dispatch(lib::bind(&client_impl::close_impl, this,close::status::normal,"End by user")); + m_client.get_io_service().dispatch(std::bind(&client_impl::close_impl, this,close::status::normal,"End by user")); if(m_network_thread) { m_network_thread->join(); @@ -164,6 +201,25 @@ namespace sio } } + template + void client_impl::set_logs_default() + { + m_client.clear_access_channels(websocketpp::log::alevel::all); + m_client.set_access_channels(websocketpp::log::alevel::connect | websocketpp::log::alevel::disconnect | websocketpp::log::alevel::app); + } + + template + void client_impl::set_logs_quiet() + { + m_client.clear_access_channels(websocketpp::log::alevel::all); + } + + template + void client_impl::set_logs_verbose() + { + m_client.set_access_channels(websocketpp::log::alevel::all); + } + /*************************protected:*************************/ template void client_impl::send(packet& p) @@ -183,7 +239,7 @@ namespace sio } template - boost::asio::io_service& client_impl::get_io_service() + asio::io_service& client_impl::get_io_service() { return m_client.get_io_service(); } @@ -235,7 +291,12 @@ namespace sio } else { ss<0){ ss<<"&sid="<replace_header(header.first, header.second); } + + if (!m_proxy_base_url.empty()) { + con->set_proxy(m_proxy_base_url, ec); + if (ec) { + m_client.get_alog().write(websocketpp::log::alevel::app, + "Set Proxy Error: " + ec.message()); + break; + } + if (!m_proxy_basic_username.empty()) { + con->set_proxy_basic_auth(m_proxy_basic_username, m_proxy_basic_password, ec); + if (ec) { + m_client.get_alog().write(websocketpp::log::alevel::app, + "Set Proxy Basic Auth Error: " + ec.message()); + break; + } + } + } m_client.connect(con); return; @@ -287,13 +365,6 @@ namespace sio { if(m_con_state == con_opened) { - //delay the ping, since we already have message to send. - boost::system::error_code timeout_ec; - if(m_ping_timer) - { - m_ping_timer->expires_from_now(milliseconds(m_ping_interval),timeout_ec); - m_ping_timer->async_wait(lib::bind(&client_impl::ping,this,lib::placeholders::_1)); - } lib::error_code ec; m_client.send(m_con,*payload_ptr,opcode,ec); if(ec) @@ -304,49 +375,18 @@ namespace sio } template - void client_impl::ping(const boost::system::error_code& ec) - { - if(ec || m_con.expired()) - { - if (ec != boost::asio::error::operation_aborted) - LOG("ping exit,con is expired?"< payload) - { - lib::error_code ec; - this->m_client.send(this->m_con, *payload, frame::opcode::text, ec); - }); - if(m_ping_timer) - { - boost::system::error_code e_code; - m_ping_timer->expires_from_now(milliseconds(m_ping_interval), e_code); - m_ping_timer->async_wait(lib::bind(&client_impl::ping,this,lib::placeholders::_1)); - } - if(!m_ping_timeout_timer) - { - m_ping_timeout_timer.reset(new boost::asio::deadline_timer(m_client.get_io_service())); - boost::system::error_code timeout_ec; - m_ping_timeout_timer->expires_from_now(milliseconds(m_ping_timeout), timeout_ec); - m_ping_timeout_timer->async_wait(lib::bind(&client_impl::timeout_pong, this,lib::placeholders::_1)); - } - } - - template - void client_impl::timeout_pong(const boost::system::error_code &ec) + void client_impl::timeout_ping(const asio::error_code &ec) { if(ec) { return; } - LOG("Pong timeout"<::close_impl, this,close::status::policy_violation,"Pong timeout")); + LOG("Ping timeout"<::close_impl, this,close::status::policy_violation,"Ping timeout")); } template - void client_impl::timeout_reconnect(boost::system::error_code const& ec) + void client_impl::timeout_reconnect(asio::error_code const& ec) { if(ec) { @@ -359,7 +399,7 @@ namespace sio this->reset_states(); LOG("Reconnecting..."<::connect_impl,this,m_base_url,m_query_string)); + m_client.get_io_service().dispatch(std::bind(&client_impl::connect_impl,this,m_base_url,m_query_string)); } } @@ -400,21 +440,27 @@ namespace sio } template - void client_impl::on_fail(connection_hdl con) + void client_impl::on_fail(connection_hdl) { + if (m_con_state == con_closing) { + LOG("Connection failed while closing." << endl); + this->close(); + return; + } + m_con.reset(); m_con_state = con_closed; this->sockets_invoke_void(socket_on_disconnect()); LOG("Connection failed." << endl); - if(m_reconn_madenext_delay(); if(m_reconnect_listener) m_reconnect_listener(m_reconn_made,delay); - m_reconn_timer.reset(new boost::asio::deadline_timer(m_client.get_io_service())); - boost::system::error_code ec; + m_reconn_timer.reset(new asio::steady_timer(m_client.get_io_service())); + asio::error_code ec; m_reconn_timer->expires_from_now(milliseconds(delay), ec); - m_reconn_timer->async_wait(lib::bind(&client_impl::timeout_reconnect,this,lib::placeholders::_1)); + m_reconn_timer->async_wait(std::bind(&client_impl::timeout_reconnect,this,lib::placeholders::_1)); } else { @@ -425,6 +471,12 @@ namespace sio template void client_impl::on_open(connection_hdl con) { + if (m_con_state == con_closing) { + LOG("Connection opened while closing." << endl); + this->close(); + return; + } + LOG("Connected." << endl); m_con_state = con_opened; m_con = con; @@ -438,6 +490,7 @@ namespace sio void client_impl::on_close(connection_hdl con) { LOG("Client Disconnected." << endl); + con_state m_con_state_was = m_con_state; m_con_state = con_closed; lib::error_code ec; close::status::value code = close::status::normal; @@ -453,7 +506,11 @@ namespace sio m_con.reset(); this->clear_timers(); client::close_reason reason; - if(code == close::status::normal) + + // If we initiated the close, no matter what the close status was, + // we'll consider it a normal close. (When using TLS, we can + // sometimes get a TLS Short Read error when closing.) + if(code == close::status::normal || m_con_state_was == con_closing) { this->sockets_invoke_void(socket_on_disconnect()); reason = client::close_reason_normal; @@ -461,15 +518,15 @@ namespace sio else { this->sockets_invoke_void(socket_on_disconnect()); - if(m_reconn_madenext_delay(); if(m_reconnect_listener) m_reconnect_listener(m_reconn_made,delay); - m_reconn_timer.reset(new boost::asio::deadline_timer(m_client.get_io_service())); - boost::system::error_code ec; + m_reconn_timer.reset(new asio::steady_timer(m_client.get_io_service())); + asio::error_code ec; m_reconn_timer->expires_from_now(milliseconds(delay), ec); - m_reconn_timer->async_wait(lib::bind(&client_impl::timeout_reconnect,this,lib::placeholders::_1)); + m_reconn_timer->async_wait(std::bind(&client_impl::timeout_reconnect,this,lib::placeholders::_1)); return; } reason = client::close_reason_drop; @@ -480,15 +537,10 @@ namespace sio m_close_listener(reason); } } - + template - void client_impl::on_message(connection_hdl con, message_ptr msg) + void client_impl::on_message(connection_hdl, typename client_type::message_ptr msg) { - if (m_ping_timeout_timer) { - boost::system::error_code ec; - m_ping_timeout_timer->expires_from_now(milliseconds(m_ping_timeout),ec); - m_ping_timeout_timer->async_wait(lib::bind(&client_impl::timeout_pong, this,lib::placeholders::_1)); - } // Parse the incoming message according to socket.IO rules m_packet_mgr.put_payload(msg->get_payload()); } @@ -526,27 +578,28 @@ namespace sio m_ping_timeout = 60000; } - m_ping_timer.reset(new boost::asio::deadline_timer(m_client.get_io_service())); - boost::system::error_code ec; - m_ping_timer->expires_from_now(milliseconds(m_ping_interval), ec); - if(ec)LOG("ec:"<async_wait(lib::bind(&client_impl::ping,this,lib::placeholders::_1)); - LOG("On handshake,sid:"<::close_impl, this,close::status::policy_violation,"Handshake error")); + m_client.get_io_service().dispatch(std::bind(&client_impl::close_impl, this,close::status::policy_violation,"Handshake error")); } template - void client_impl::on_pong() + void client_impl::on_ping() { - if(m_ping_timeout_timer) + // Reply with pong packet. + packet p(packet::frame_pong); + m_packet_mgr.encode(p, [&](bool /*isBin*/,shared_ptr payload) { - m_ping_timeout_timer->cancel(); - m_ping_timeout_timer.reset(); - } + this->m_client.send(this->m_con, *payload, frame::opcode::text); + }); + + // Reset the ping timeout. + update_ping_timeout_timer(); } template @@ -567,8 +620,8 @@ namespace sio //FIXME how to deal? this->close_impl(close::status::abnormal_close, "End by server"); break; - case packet::frame_pong: - this->on_pong(); + case packet::frame_ping: + this->on_ping(); break; default: @@ -580,24 +633,30 @@ namespace sio void client_impl::on_encode(bool isBinary,shared_ptr const& payload) { LOG("encoded payload length:"<length()<::send_impl,this,payload,isBinary?frame::opcode::binary:frame::opcode::text)); + m_client.get_io_service().dispatch(std::bind(&client_impl::send_impl,this,payload,isBinary?frame::opcode::binary:frame::opcode::text)); } template void client_impl::clear_timers() { LOG("clear timers"<cancel(ec); m_ping_timeout_timer.reset(); } - if(m_ping_timer) - { - m_ping_timer->cancel(ec); - m_ping_timer.reset(); + } + + template + void client_impl::update_ping_timeout_timer() { + if (!m_ping_timeout_timer) { + m_ping_timeout_timer = std::unique_ptr(new asio::steady_timer(get_io_service())); } + + asio::error_code ec; + m_ping_timeout_timer->expires_from_now(milliseconds(m_ping_interval + m_ping_timeout), ec); + m_ping_timeout_timer->async_wait(std::bind(&client_impl::timeout_ping, this, std::placeholders::_1)); } template @@ -614,14 +673,16 @@ namespace sio } #if SIO_TLS - typedef websocketpp::lib::shared_ptr context_ptr; - static context_ptr on_tls_init(connection_hdl conn) - { - context_ptr ctx = context_ptr(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1)); - boost::system::error_code ec; - ctx->set_options(boost::asio::ssl::context::default_workarounds | - boost::asio::ssl::context::no_sslv2 | - boost::asio::ssl::context::single_dh_use,ec); + + template<> client_impl::context_ptr + client_impl::on_tls_init(connection_hdl conn) + { + context_ptr ctx = context_ptr(new asio::ssl::context(asio::ssl::context::tls)); + asio::error_code ec; + ctx->set_options(asio::ssl::context::default_workarounds | + asio::ssl::context::no_tlsv1 | + asio::ssl::context::no_tlsv1_1 | + asio::ssl::context::single_dh_use,ec); if(ec) { cerr<<"Init tls failed,reason:"<< ec.message()< void client_impl::template_init() { - m_client.set_tls_init_handler(&on_tls_init); + using std::placeholders::_1; + m_client.set_tls_init_handler(std::bind(&client_impl::on_tls_init,this,_1)); } #endif bool client_impl_base::is_tls(const string& uri) { websocketpp::uri uo(uri); - if(boost::iequals(uo.get_scheme(), "http") || boost::iequals(uo.get_scheme(), "ws")) + if(iequals(uo.get_scheme(), "http") || iequals(uo.get_scheme(), "ws")) { return false; } #if SIO_TLS - else if(boost::iequals(uo.get_scheme(), "https") || boost::iequals(uo.get_scheme(), "wss")) + else if(iequals(uo.get_scheme(), "https") || iequals(uo.get_scheme(), "wss")) { return true; } @@ -657,8 +719,8 @@ namespace sio } socket* - client_impl_base::new_socket(const string& nsp) - { return new sio::socket(this, nsp); } + client_impl_base::new_socket(const string& nsp, const message::ptr &auth) + { return new sio::socket(this, nsp, auth); } void client_impl_base::socket_on_message_packet(socket::ptr& s, const packet& p) @@ -668,4 +730,19 @@ namespace sio #if SIO_TLS template class client_impl; #endif + + std::string client_impl_base::encode_query_string(const std::string &query){ + ostringstream ss; + ss << std::hex; + // Percent-encode (RFC3986) non-alphanumeric characters. + for(const char c : query){ + if((c >= 'a' && c <= 'z') || (c>= 'A' && c<= 'Z') || (c >= '0' && c<= '9')){ + ss << c; + } else { + ss << '%' << std::uppercase << std::setw(2) << int((unsigned char) c) << std::nouppercase; + } + } + ss << std::dec; + return ss.str(); + } } diff --git a/src/internal/sio_client_impl.h b/src/internal/sio_client_impl.h index 9f197a82..a08e700a 100644 --- a/src/internal/sio_client_impl.h +++ b/src/internal/sio_client_impl.h @@ -4,7 +4,6 @@ #include #ifdef _WIN32 #define _WEBSOCKETPP_CPP11_THREAD_ -#define BOOST_ALL_NO_LIB //#define _WEBSOCKETPP_CPP11_RANDOM_DEVICE_ #define _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_ #define INTIALIZER(__TYPE__) @@ -28,8 +27,16 @@ typedef websocketpp::config::asio_tls_client client_config_tls; #include typedef websocketpp::config::asio_client client_config; #endif //DEBUG -#include +#if SIO_TLS +#include +#endif + +#include +#include +#include + +#include #include #include #include @@ -45,7 +52,8 @@ namespace sio typedef websocketpp::client client_type_tls; #endif - struct client_impl_base { + class client_impl_base { + public: enum con_state { con_opening, @@ -65,12 +73,17 @@ namespace sio virtual void set_close_listener(client::close_listener const&)=0; virtual void set_socket_open_listener(client::socket_listener const&)=0; virtual void set_socket_close_listener(client::socket_listener const&)=0; + virtual void set_proxy_basic_auth(const std::string&, const std::string&, const std::string&) = 0; // used by sio::client + virtual void set_logs_default() = 0; + virtual void set_logs_quiet() = 0; + virtual void set_logs_verbose() = 0; + virtual void clear_con_listeners()=0; virtual void clear_socket_listeners()=0; virtual void connect(const std::string& uri, const std::map& queryString, - const std::map& httpExtraHeaders)=0; + const std::map& httpExtraHeaders, const message::ptr& auth) = 0; virtual sio::socket::ptr const& socket(const std::string& nsp)=0; virtual void close()=0; virtual void sync_close()=0; @@ -83,7 +96,7 @@ namespace sio // used by sio::socket virtual void send(packet& p)=0; virtual void remove_socket(std::string const& nsp)=0; - virtual boost::asio::io_service& get_io_service()=0; + virtual asio::io_service& get_io_service()=0; virtual void on_socket_closed(std::string const& nsp)=0; virtual void on_socket_opened(std::string const& nsp)=0; @@ -92,12 +105,15 @@ namespace sio protected: // Wrap protected member functions of sio::socket because only client_impl_base is friended. - sio::socket* new_socket(std::string const&); + sio::socket* new_socket(std::string const&, const message::ptr& auth); void socket_on_message_packet(sio::socket::ptr&, packet const&); typedef void (sio::socket::*socket_void_fn)(void); inline socket_void_fn socket_on_close() { return &sio::socket::on_close; } inline socket_void_fn socket_on_disconnect() { return &sio::socket::on_disconnect; } inline socket_void_fn socket_on_open() { return &sio::socket::on_open; } + + // Percent encode query string + std::string encode_query_string(const std::string &query); }; template @@ -105,14 +121,14 @@ namespace sio public: typedef typename client_type::message_ptr message_ptr; - client_impl(const std::string& uri = std::string()); + client_impl(const client_options& options); void template_init(); // template-specific initialization ~client_impl(); //set listeners and event bindings. #define SYNTHESIS_SETTER(__TYPE__,__FIELD__) \ - void set_##__FIELD__(__TYPE__ const& l) \ + void set_##__FIELD__(__TYPE__ const& l) override \ { m_##__FIELD__ = l;} SYNTHESIS_SETTER(client::con_listener,open_listener) @@ -128,11 +144,10 @@ namespace sio SYNTHESIS_SETTER(client::socket_listener,socket_open_listener) SYNTHESIS_SETTER(client::socket_listener,socket_close_listener) - + #undef SYNTHESIS_SETTER - - - void clear_con_listeners() + + void clear_con_listeners() override { m_open_listener = nullptr; m_close_listener = nullptr; @@ -141,7 +156,7 @@ namespace sio m_reconnecting_listener = nullptr; } - void clear_socket_listeners() + void clear_socket_listeners() override { m_socket_open_listener = nullptr; m_socket_close_listener = nullptr; @@ -149,35 +164,50 @@ namespace sio // Client Functions - such as send, etc. void connect(const std::string& uri, const std::map& queryString, - const std::map& httpExtraHeaders); + const std::map& httpExtraHeaders, const message::ptr& auth) override; - sio::socket::ptr const& socket(const std::string& nsp); + sio::socket::ptr const& socket(const std::string& nsp) override; // Closes the connection - void close(); + void close() override; - void sync_close(); + void sync_close() override; - bool opened() const { return m_con_state == con_opened; } + bool opened() const override { return m_con_state == con_opened; } - std::string const& get_sessionid() const { return m_sid; } + std::string const& get_sessionid() const override { return m_sid; } - void set_reconnect_attempts(unsigned attempts) {m_reconn_attempts = attempts;} + void set_reconnect_attempts(unsigned attempts) override {m_reconn_attempts = attempts;} - void set_reconnect_delay(unsigned millis) {m_reconn_delay = millis;if(m_reconn_delay_maxmillis) m_reconn_delay = millis;} + void set_reconnect_delay_max(unsigned millis) override { + m_reconn_delay_max = millis; + if(m_reconn_delay>millis) m_reconn_delay = millis; + } public: - void send(packet& p); + + void set_logs_default() override; + + void set_logs_quiet() override; + + void set_logs_verbose() override; + + void set_proxy_basic_auth(const std::string& uri, const std::string& username, const std::string& password) override; + + void send(packet& p) override; - void remove_socket(std::string const& nsp); + void remove_socket(std::string const& nsp) override; - boost::asio::io_service& get_io_service(); + asio::io_service& get_io_service() override; - void on_socket_closed(std::string const& nsp); + void on_socket_closed(std::string const& nsp) override; - void on_socket_opened(std::string const& nsp); + void on_socket_opened(std::string const& nsp) override; private: void run_loop(); @@ -188,11 +218,11 @@ namespace sio void send_impl(std::shared_ptr const& payload_ptr,frame::opcode::value opcode); - void ping(const boost::system::error_code& ec); + void ping(const asio::error_code& ec); - void timeout_pong(const boost::system::error_code& ec); + void timeout_ping(const asio::error_code& ec); - void timeout_reconnect(boost::system::error_code const& ec); + void timeout_reconnect(asio::error_code const& ec); unsigned next_delay() const; @@ -215,11 +245,19 @@ namespace sio //socketio callbacks void on_handshake(message::ptr const& message); - void on_pong(); + void on_ping(); void reset_states(); void clear_timers(); + + void update_ping_timeout_timer(); + + #if SIO_TLS + typedef websocketpp::lib::shared_ptr context_ptr; + + context_ptr on_tls_init(connection_hdl con); + #endif // Connection pointer for client functions. connection_hdl m_con; @@ -229,6 +267,10 @@ namespace sio std::string m_base_url; std::string m_query_string; std::map m_http_headers; + message::ptr m_auth; + std::string m_proxy_base_url; + std::string m_proxy_basic_username; + std::string m_proxy_basic_password; unsigned int m_ping_interval; unsigned int m_ping_timeout; @@ -237,11 +279,9 @@ namespace sio packet_manager m_packet_mgr; - std::unique_ptr m_ping_timer; - - std::unique_ptr m_ping_timeout_timer; + std::unique_ptr m_ping_timeout_timer; - std::unique_ptr m_reconn_timer; + std::unique_ptr m_reconn_timer; con_state m_con_state; @@ -265,7 +305,9 @@ namespace sio unsigned m_reconn_attempts; unsigned m_reconn_made; - + + std::atomic m_abort_retries { false }; + friend class sio::client; friend class sio::socket; }; diff --git a/src/internal/sio_packet.cpp b/src/internal/sio_packet.cpp index ec4551d9..4b810987 100755 --- a/src/internal/sio_packet.cpp +++ b/src/internal/sio_packet.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #define kBIN_PLACE_HOLDER "_placeholder" @@ -54,13 +53,7 @@ namespace sio Value numVal; numVal.SetInt((int)buffers.size()); val.AddMember("num", numVal, doc.GetAllocator()); - //FIXME can not avoid binary copy here. - shared_ptr write_buffer = make_shared(); - write_buffer->reserve(msg.get_binary()->size()+1); - char frame_char = packet::frame_message; - write_buffer->append(&frame_char,1); - write_buffer->append(*(msg.get_binary())); - buffers.push_back(write_buffer); + buffers.push_back(msg.get_binary()); } void accept_array_message(array_message const& msg,Value& val,Document& doc,vector >& buffers) @@ -198,8 +191,8 @@ namespace sio _frame(frame_message), _type((isAck?type_ack : type_event) | type_undetermined), _nsp(nsp), - _message(msg), _pack_id(pack_id), + _message(msg), _pending_buffers(0) { assert((!isAck @@ -210,8 +203,8 @@ namespace sio _frame(frame_message), _type(type), _nsp(nsp), - _message(msg), _pack_id(-1), + _message(msg), _pending_buffers(0) { @@ -254,7 +247,7 @@ namespace sio { if (_pending_buffers > 0) { assert(is_binary_message(buf_payload));//this is ensured by outside. - _buffers.push_back(std::make_shared(buf_payload.data()+1,buf_payload.size()-1)); + _buffers.push_back(std::make_shared(buf_payload.data(),buf_payload.size())); _pending_buffers--; if (_pending_buffers == 0) { @@ -288,7 +281,7 @@ namespace sio pos++; if (_type == type_binary_event || _type == type_binary_ack) { size_t score_pos = payload_ptr.find('-'); - _pending_buffers = boost::lexical_cast(payload_ptr.substr(pos,score_pos - pos)); + _pending_buffers = static_cast(std::stoul(payload_ptr.substr(pos, score_pos - pos))); pos = score_pos+1; } } @@ -328,7 +321,7 @@ namespace sio if(pos(payload_ptr.substr(pos,json_pos - pos)); + _pack_id = std::stoi(payload_ptr.substr(pos,json_pos - pos)); } if (_frame == frame_message && (_type == type_binary_event || _type == type_binary_ack)) { //parse later when all buffers are arrived. diff --git a/src/sio_client.cpp b/src/sio_client.cpp index 6922f559..a8e4d3ed 100644 --- a/src/sio_client.cpp +++ b/src/sio_client.cpp @@ -8,26 +8,22 @@ #include "internal/sio_client_impl.h" using namespace websocketpp; -using boost::posix_time::milliseconds; using std::stringstream; namespace sio { - client::client(): - m_impl(new client_impl()) - { - } - - client::client(const std::string& uri) + client::client() : m_impl(new client_impl({})) {} + + client::client(client_options const& options) { - if(!client_impl_base::is_tls(uri)) + if(!client_impl_base::is_tls(options.uri)) { - m_impl = new client_impl(uri); + m_impl = new client_impl(options); } #if SIO_TLS else { - m_impl = new client_impl(uri); + m_impl = new client_impl(options); } #endif } @@ -81,26 +77,47 @@ namespace sio { m_impl->clear_socket_listeners(); } + + void client::set_proxy_basic_auth(const std::string& uri, const std::string& username, const std::string& password) + { + m_impl->set_proxy_basic_auth(uri, username, password); + } void client::connect() { - m_impl->connect(std::string(), {}, {}); + connect(""); } void client::connect(const std::string& uri) { - m_impl->connect(uri, {}, {}); + m_impl->connect(uri, {}, {}, {}); + } + + void client::connect(const std::string& uri, const message::ptr& auth) + { + m_impl->connect(uri, {}, {}, auth); } void client::connect(const std::string& uri, const std::map& query) { - m_impl->connect(uri, query, {}); + m_impl->connect(uri, query, {}, {}); + } + + void client::connect(const std::string& uri, const std::map& query, const message::ptr& auth) + { + m_impl->connect(uri, query, {}, auth); } void client::connect(const std::string& uri, const std::map& query, const std::map& http_extra_headers) { - m_impl->connect(uri, query, http_extra_headers); + m_impl->connect(uri, query, http_extra_headers, {}); + } + + void client::connect(const std::string& uri, const std::map& query, + const std::map& http_extra_headers, const message::ptr& auth) + { + m_impl->connect(uri, query, http_extra_headers, auth); } socket::ptr const& client::socket(const std::string& nsp) @@ -143,5 +160,20 @@ namespace sio { m_impl->set_reconnect_delay_max(millis); } - + + void client::set_logs_default() + { + m_impl->set_logs_default(); + } + + void client::set_logs_quiet() + { + m_impl->set_logs_quiet(); + } + + void client::set_logs_verbose() + { + m_impl->set_logs_verbose(); + } + } diff --git a/src/sio_client.h b/src/sio_client.h index 043f535f..01c007f9 100644 --- a/src/sio_client.h +++ b/src/sio_client.h @@ -11,9 +11,27 @@ #include "sio_message.h" #include "sio_socket.h" +namespace asio { + class io_context; +} + namespace sio { class client_impl_base; + + struct client_options { + asio::io_context* io_context = nullptr; + + /** + * @brief URI to connect after construction. + * @details If this is set, the constructor selects TLS or non-TLS as needed. If building + * the library without SIO_TLS support, you may only use http:// or ws:// schemes, or an + * exception is thrown. When using this constructor, you may later call connect() without + * passing the URI again. If you pass another URI later to connect() it must have the same + * scheme as the one given here, or an exception will be raised. + */ + std::string uri; + }; class client { public: @@ -31,17 +49,21 @@ namespace sio typedef std::function socket_listener; - // The default constructor builds a TLS-only or a non-TLS client depending - // on which library you link with. + /** + * @brief Default constructor. + * @details Build a TLS-only or a non-TLS client depending on which library you link with. + */ client(); - // This version of the constructor takes a given connection URI and selects - // TLS or non-TLS as needed. If building the library without SIO_TLS support, - // you may only use http:// or ws:// schemes, or an exception is thrown. - // When using this constructor, you may later call connect() without passing - // the URI again. If you pass another URI later to connect() it must have the - // same scheme as the one given here, or an exception will be raised. - client(const std::string& uri); + /** + * @brief Construct a new client object + * @details This version of the constructor is a convenience for building a client with + * options from @ref client_options and the uri value set to @p uri. + * @param uri URI to connect after construction. + */ + client(const std::string& uri) : client(client_options{nullptr, uri}) {} + + client(client_options const& options); ~client(); @@ -69,17 +91,30 @@ namespace sio void connect(const std::string& uri); + void connect(const std::string& uri, const message::ptr& auth); + void connect(const std::string& uri, const std::map& query); + void connect(const std::string& uri, const std::map& query, const message::ptr& auth); + void connect(const std::string& uri, const std::map& query, const std::map& http_extra_headers); + void connect(const std::string& uri, const std::map& query, + const std::map& http_extra_headers, const message::ptr& auth); + void set_reconnect_attempts(int attempts); void set_reconnect_delay(unsigned millis); void set_reconnect_delay_max(unsigned millis); - + + void set_logs_default(); + + void set_logs_quiet(); + + void set_logs_verbose(); + sio::socket::ptr const& socket(const std::string& nsp = ""); // Closes the connection @@ -87,14 +122,16 @@ namespace sio void sync_close(); + void set_proxy_basic_auth(const std::string& uri, const std::string& username, const std::string& password); + bool opened() const; std::string const& get_sessionid() const; private: //disable copy constructor and assign operator. - client(client const& cl){} - void operator=(client const& cl){} + client(client const&){} + void operator=(client const&){} client_impl_base* m_impl; }; diff --git a/src/sio_socket.cpp b/src/sio_socket.cpp index 59696fb5..033f3fb7 100644 --- a/src/sio_socket.cpp +++ b/src/sio_socket.cpp @@ -1,10 +1,12 @@ #include "sio_socket.h" #include "internal/sio_packet.h" #include "internal/sio_client_impl.h" -#include -#include +#include +#include #include +#include #include +#include #if DEBUG || _DEBUG #define LOG(x) std::cout << x @@ -106,7 +108,7 @@ namespace sio { public: - impl(client_impl_base *,std::string const&); + impl(client_impl_base *, std::string const&, message::ptr const&); ~impl(); void on(std::string const& event_name,event_listener_aux const& func); @@ -157,7 +159,7 @@ namespace sio void ack(int msgId,string const& name,message::list const& ack_message); - void timeout_connection(const boost::system::error_code &ec); + void timeout_connection(const asio::error_code &ec); void send_connect(); @@ -171,6 +173,7 @@ namespace sio bool m_connected; std::string m_nsp; + message::ptr m_auth; std::map > m_acks; @@ -178,7 +181,7 @@ namespace sio error_listener m_error_listener; - std::unique_ptr m_connection_timer; + std::unique_ptr m_connection_timer; std::queue m_packet_queue; @@ -226,10 +229,11 @@ namespace sio m_error_listener = nullptr; } - socket::impl::impl(client_impl_base* client, std::string const& nsp): + socket::impl::impl(client_impl_base *client, std::string const& nsp, message::ptr const& auth): m_client(client), + m_connected(false), m_nsp(nsp), - m_connected(false) + m_auth(auth) { NULL_GUARD(client); if(m_client->opened()) @@ -267,15 +271,11 @@ namespace sio void socket::impl::send_connect() { NULL_GUARD(m_client); - if(m_nsp == "/") - { - return; - } - packet p(packet::type_connect,m_nsp); + packet p(packet::type_connect, m_nsp, m_auth); m_client->send(p); - m_connection_timer.reset(new boost::asio::deadline_timer(m_client->get_io_service())); - boost::system::error_code ec; - m_connection_timer->expires_from_now(boost::posix_time::milliseconds(20000), ec); + m_connection_timer.reset(new asio::steady_timer(m_client->get_io_service())); + asio::error_code ec; + m_connection_timer->expires_from_now(std::chrono::milliseconds(20000), ec); m_connection_timer->async_wait(std::bind(&socket::impl::timeout_connection,this, std::placeholders::_1)); } @@ -289,11 +289,11 @@ namespace sio if(!m_connection_timer) { - m_connection_timer.reset(new boost::asio::deadline_timer(m_client->get_io_service())); + m_connection_timer.reset(new asio::steady_timer(m_client->get_io_service())); } - boost::system::error_code ec; - m_connection_timer->expires_from_now(boost::posix_time::milliseconds(3000), ec); - m_connection_timer->async_wait(lib::bind(&socket::impl::on_close, this)); + asio::error_code ec; + m_connection_timer->expires_from_now(std::chrono::milliseconds(3000), ec); + m_connection_timer->async_wait(std::bind(&socket::impl::on_close, this)); } } @@ -418,7 +418,7 @@ namespace sio message::list msglist(ptr->get_vector()); this->on_socketio_ack(p.get_pack_id(),msglist); } - else + else { this->on_socketio_ack(p.get_pack_id(),message::list(ptr)); } @@ -449,7 +449,7 @@ namespace sio } } - void socket::impl::ack(int msgId, const string &name, const message::list &ack_message) + void socket::impl::ack(int msgId, const string &, const message::list &ack_message) { packet p(m_nsp, ack_message.to_array_message(),msgId,true); send_packet(p); @@ -475,7 +475,7 @@ namespace sio if(m_error_listener)m_error_listener(err_message); } - void socket::impl::timeout_connection(const boost::system::error_code &ec) + void socket::impl::timeout_connection(const asio::error_code &ec) { NULL_GUARD(m_client); if(ec) @@ -525,8 +525,8 @@ namespace sio return socket::event_listener(); } - socket::socket(client_impl_base* client,std::string const& nsp): - m_impl(new impl(client,nsp)) + socket::socket(client_impl_base* client,std::string const& nsp,message::ptr const& auth): + m_impl(new impl(client,nsp,auth)) { } diff --git a/src/sio_socket.h b/src/sio_socket.h index 4fd54c07..3703b108 100644 --- a/src/sio_socket.h +++ b/src/sio_socket.h @@ -75,7 +75,7 @@ namespace sio std::string const& get_namespace() const; protected: - socket(client_impl_base*,std::string const&); + socket(client_impl_base*,std::string const&,message::ptr const&); void on_connected(); @@ -91,8 +91,8 @@ namespace sio private: //disable copy constructor and assign operator. - socket(socket const& sock){} - void operator=(socket const& sock){} + socket(socket const&){} + void operator=(socket const&){} class impl; impl *m_impl; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c9c78d81..78e5d24e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,9 +1,14 @@ -cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) -include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt) -find_package(Boost ${BOOST_VER} REQUIRED COMPONENTS unit_test_framework) +include(FetchContent) + +FetchContent_Declare( + Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG v3.3.2 +) +FetchContent_MakeAvailable(Catch2) + add_executable(sio_test sio_test.cpp) set_property(TARGET sio_test PROPERTY CXX_STANDARD 11) set_property(TARGET sio_test PROPERTY CXX_STANDARD_REQUIRED ON) -target_link_libraries(sioclient PRIVATE ${Boost_LIBRARIES}) -target_link_libraries(sio_test sioclient) -target_include_directories(sio_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../src" ${Boost_INCLUDE_DIRS} ) +target_link_libraries(sio_test PRIVATE Catch2::Catch2WithMain sioclient) +add_test(sioclient_test sio_test) diff --git a/test/README.md b/test/README.md deleted file mode 100644 index ee7b663f..00000000 --- a/test/README.md +++ /dev/null @@ -1,18 +0,0 @@ -You need have your boost unpacked on your disk, at least staged following modules: - -* system -* date_time -* random -* unit_test_framework - -Then use following instruction to gen makefile or VS project. -```bash -cmake -DBOOST_LIBRARYDIR=`` -DBOOST_INCLUDEDIR=`` -DBOOST_VER:STRING=`` -DCMAKE_BUILD_TYPE=Debug ./ -``` -Then run `make` or open by VS. - -For example I've installed boost 1.57.0 at `D:\boost_1_57_0` and staged the static lib at `D\boost_1_57_0\build\lib` then the command should be: -```bash -cmake -DBOOST_LIBRARYDIR=D:\boost_1_57_0\build\lib -DBOOST_INCLUDEDIR=D:\boost_1_57_0 -DBOOST_VER:STRING=1.57.0 -DCMAKE_BUILD_TYPE=Debug ./ -``` -In this case(Windows) CMake will create a VS project under `./test` folder. Open in VS and run it. \ No newline at end of file diff --git a/test/echo_server/index.js b/test/echo_server/index.js index 2c59ab1c..049066be 100644 --- a/test/echo_server/index.js +++ b/test/echo_server/index.js @@ -1,19 +1,17 @@ var port = 3000; -var io = require('socket.io').listen(port); +var io = require('socket.io')().listen(port); console.log("Listening on port " + port); /* Socket.IO events */ io.on("connection", function(socket){ console.log("new connection"); - socket.on('test_text',function() - { - console.log("test text event received."); + socket.on('test_text', (...args) => { + console.log("test text event received.", args); }); - socket.on('test_binary',function() - { - var args =Array.prototype.slice.call(arguments); + socket.on('test_binary', (...args) => { + console.log("test binary event received", args); if(args[0] instanceof Buffer) { console.log("test binary event received,binary length:"+ args[0].length); diff --git a/test/echo_server/package-lock.json b/test/echo_server/package-lock.json new file mode 100644 index 00000000..15ee0cb0 --- /dev/null +++ b/test/echo_server/package-lock.json @@ -0,0 +1,165 @@ +{ + "name": "echo_server", + "version": "0.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/component-emitter": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz", + "integrity": "sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg==" + }, + "@types/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-y7mImlc/rNkvCRmg8gC3/lj87S7pTUIJ6QGjwHR9WQJcFs+ZMTOaoPrkdFA/YdbuqVEmEbb5RdhVxMkAcgOnpg==" + }, + "@types/cors": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.9.tgz", + "integrity": "sha512-zurD1ibz21BRlAOIKP8yhrxlqKx6L9VCwkB5kMiP6nZAhoF5MvC7qS1qPA7nRcr1GJolfkQC7/EAL4hdYejLtg==" + }, + "@types/node": { + "version": "14.14.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.20.tgz", + "integrity": "sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A==" + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "base64-arraybuffer": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", + "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=" + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "engine.io": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-4.0.6.tgz", + "integrity": "sha512-rf7HAVZpcRrcKEKddgIzYUnwg0g5HE1RvJaTLwkcfJmce4g+po8aMuE6vxzp6JwlK8FEq/vi0KWN6tA585DjaA==", + "requires": { + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~4.0.0", + "ws": "~7.4.2" + } + }, + "engine.io-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.2.tgz", + "integrity": "sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/MqJdZbUjW97JU72iYg==", + "requires": { + "base64-arraybuffer": "0.1.4" + } + }, + "mime-db": { + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", + "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==" + }, + "mime-types": { + "version": "2.1.28", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", + "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", + "requires": { + "mime-db": "1.45.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "socket.io": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-3.0.5.tgz", + "integrity": "sha512-5yWQ43P/4IttmPCGKDQ3CVocBiJWGpibyhYJxgUhf69EHMzmK8XW0DkmHIoYdLmZaVZJyiEkUqpeC7rSCIqekw==", + "requires": { + "@types/cookie": "^0.4.0", + "@types/cors": "^2.8.8", + "@types/node": "^14.14.10", + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.1", + "engine.io": "~4.0.6", + "socket.io-adapter": "~2.0.3", + "socket.io-parser": "~4.0.3" + } + }, + "socket.io-adapter": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.0.3.tgz", + "integrity": "sha512-2wo4EXgxOGSFueqvHAdnmi5JLZzWqMArjuP4nqC26AtLh5PoCPsaRbRdah2xhcwTAMooZfjYiNVNkkmmSMaxOQ==" + }, + "socket.io-parser": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.5.tgz", + "integrity": "sha512-sNjbT9dX63nqUFIOv95tTVm6elyIU4RvB1m8dOeZt+IgWwcWklFDOdmGcfo3zSiRsnR/3pJkjY5lfoGqEe4Eig==", + "requires": { + "@types/component-emitter": "^1.2.10", + "component-emitter": "~1.3.0", + "debug": "~4.3.1" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" + } + } +} diff --git a/test/echo_server/package.json b/test/echo_server/package.json index e4a4727e..b980f3c8 100644 --- a/test/echo_server/package.json +++ b/test/echo_server/package.json @@ -1,8 +1,8 @@ { "name": "echo_server", - "author":"Melo Yao", - "version":"0.0.0", + "author": "Melo Yao", + "version": "0.0.0", "dependencies": { - "socket.io": "1.*" - } + "socket.io": "^3.0.5" + } } diff --git a/test/sio_test b/test/sio_test new file mode 100755 index 00000000..55c24ea1 Binary files /dev/null and b/test/sio_test differ diff --git a/test/sio_test.cpp b/test/sio_test.cpp index fb6f3e50..3901f05e 100644 --- a/test/sio_test.cpp +++ b/test/sio_test.cpp @@ -10,65 +10,65 @@ #include #include -#define BOOST_TEST_MODULE sio_test +#include -#include #ifndef _WIN32 #include "json.hpp" //nlohmann::json cannot build in MSVC #endif using namespace sio; -BOOST_AUTO_TEST_SUITE(test_packet) -BOOST_AUTO_TEST_CASE( test_packet_construct_1 ) +TEST_CASE( "test_packet_construct_1" ) { packet p("/nsp",nullptr,1001,true); - BOOST_CHECK(p.get_frame() == packet::frame_message); - BOOST_CHECK(p.get_message() == nullptr); - BOOST_CHECK(p.get_nsp() == std::string("/nsp")); - BOOST_CHECK(p.get_pack_id() == 1001); + CHECK(p.get_frame() == packet::frame_message); + CHECK(p.get_message() == nullptr); + CHECK(p.get_nsp() == std::string("/nsp")); + CHECK(p.get_pack_id() == 1001); } -BOOST_AUTO_TEST_CASE( test_packet_construct_2 ) +TEST_CASE( "test_packet_construct_2" ) { packet p(packet::frame_ping); - BOOST_CHECK(p.get_frame() == packet::frame_ping); - BOOST_CHECK(p.get_message() == nullptr); - BOOST_CHECK(p.get_nsp() == std::string("")); - BOOST_CHECK(p.get_pack_id() == 0xFFFFFFFF); + CHECK(p.get_frame() == packet::frame_ping); + CHECK(p.get_message() == nullptr); + CHECK(p.get_nsp() == std::string("")); + CHECK(p.get_pack_id() == 0xFFFFFFFF); } -BOOST_AUTO_TEST_CASE( test_packet_construct_3 ) +TEST_CASE( "test_packet_construct_3" ) { packet p(packet::type_connect,"/nsp",nullptr); - BOOST_CHECK(p.get_frame() == packet::frame_message); - BOOST_CHECK(p.get_type() == packet::type_connect); - BOOST_CHECK(p.get_message() == nullptr); - BOOST_CHECK(p.get_nsp() == std::string("/nsp")); - BOOST_CHECK(p.get_pack_id() == 0xFFFFFFFF); + CHECK(p.get_frame() == packet::frame_message); + CHECK(p.get_type() == packet::type_connect); + CHECK(p.get_message() == nullptr); + CHECK(p.get_nsp() == std::string("/nsp")); + CHECK(p.get_pack_id() == 0xFFFFFFFF); } -BOOST_AUTO_TEST_CASE( test_packet_accept_1 ) +TEST_CASE( "test_packet_accept_1" ) { packet p(packet::type_connect,"/nsp",nullptr); std::string payload; std::vector > buffers; p.accept(payload,buffers); - BOOST_CHECK(buffers.size() == 0); - BOOST_CHECK_MESSAGE(payload == "40/nsp",std::string("outputing payload:")+payload); + CHECK(buffers.size() == 0); + CHECK(payload == "40/nsp"); + INFO("outputing payload:" << payload); } -BOOST_AUTO_TEST_CASE( test_packet_accept_2 ) +TEST_CASE( "test_packet_accept_2" ) { packet p(packet::frame_ping); std::string payload; std::vector > buffers; p.accept(payload,buffers); - BOOST_CHECK(buffers.size() == 0); - BOOST_CHECK_MESSAGE(payload == "2",std::string("outputing payload:")+payload); + CHECK(buffers.size() == 0); + CHECK(payload == "2"); + INFO("outputing payload:" << payload); } -BOOST_AUTO_TEST_CASE( test_packet_accept_3 ) +TEST_CASE( "test_packet_accept_3" ) { message::ptr array = array_message::create(); array->get_vector().push_back(string_message::create("event")); @@ -77,13 +77,14 @@ BOOST_AUTO_TEST_CASE( test_packet_accept_3 ) std::string payload; std::vector > buffers; p.accept(payload,buffers); - BOOST_CHECK(p.get_type() == packet::type_ack); - BOOST_CHECK(buffers.size() == 0); - BOOST_CHECK_MESSAGE(payload == "43/nsp,1001[\"event\",\"text\"]",std::string("outputing payload:")+payload); + CHECK(p.get_type() == packet::type_ack); + CHECK(buffers.size() == 0); + CHECK(payload == "43/nsp,1001[\"event\",\"text\"]"); + INFO("outputing payload:" << payload); } #ifndef _WIN32 -BOOST_AUTO_TEST_CASE( test_packet_accept_4 ) +TEST_CASE( "test_packet_accept_4" ) { message::ptr binObj = object_message::create(); binObj->get_map()["desc"] = string_message::create("Bin of 100 bytes"); @@ -98,132 +99,138 @@ BOOST_AUTO_TEST_CASE( test_packet_accept_4 ) std::string payload; std::vector > buffers; p.accept(payload,buffers); - BOOST_CHECK(p.get_type() == packet::type_binary_event); - BOOST_REQUIRE(buffers.size() == 2); + CHECK(p.get_type() == packet::type_binary_event); + REQUIRE(buffers.size() == 2); size_t json_start = payload.find("{"); - BOOST_REQUIRE(json_start!=std::string::npos); + REQUIRE(json_start!=std::string::npos); std::string header = payload.substr(0,json_start); - BOOST_CHECK_MESSAGE(header=="452-/nsp,1001",std::string("outputing payload header:")+header); + CHECK(header=="452-/nsp,1001"); + INFO("outputing payload:" << payload); std::string json = payload.substr(json_start); nlohmann::json j = nlohmann::json::parse(json); - BOOST_CHECK_MESSAGE(j["desc"].get() == "Bin of 100 bytes", std::string("outputing payload desc:") + j["desc"].get()); - BOOST_CHECK_MESSAGE((bool)j["bin1"]["_placeholder"] , std::string("outputing payload bin1:") + j["bin1"].dump()); - BOOST_CHECK_MESSAGE((bool)j["bin2"]["_placeholder"] , std::string("outputing payload bin2:") + j["bin2"].dump()); + CHECK(j["desc"].get() == "Bin of 100 bytes"); + INFO("outputing payload desc::" << j["desc"].get()); + CHECK((bool)j["bin1"]["_placeholder"]); + INFO("outputing payload bin1:" << j["bin1"].dump()); + CHECK((bool)j["bin2"]["_placeholder"]); + INFO("outputing payload bin2:" << j["bin2"].dump()); int bin1Num = j["bin1"]["num"].get(); char numchar[] = {0,0}; numchar[0] = bin1Num+'0'; - BOOST_CHECK_MESSAGE(buffers[bin1Num]->length()==101 , std::string("outputing payload bin1 num:")+numchar); - BOOST_CHECK(buffers[bin1Num]->at(50)==0 && buffers[bin1Num]->at(0) == packet::frame_message); + CHECK(buffers[bin1Num]->length()==100); + INFO("outputing payload bin1 num:" << numchar); + CHECK(buffers[bin1Num]->at(50)==0); + CHECK(buffers[bin1Num]->at(0) == 0); int bin2Num = j["bin2"]["num"].get(); numchar[0] = bin2Num+'0'; - BOOST_CHECK_MESSAGE(buffers[bin2Num]->length()==51 , std::string("outputing payload bin2 num:") + numchar); - BOOST_CHECK(buffers[bin2Num]->at(25)==1 && buffers[bin2Num]->at(0) == packet::frame_message); + CHECK(buffers[bin2Num]->length()==50); + INFO("outputing payload bin2 num:" << numchar); + CHECK(buffers[bin2Num]->at(25)==1); + CHECK(buffers[bin2Num]->at(0) == 1); } #endif -BOOST_AUTO_TEST_CASE( test_packet_parse_1 ) +TEST_CASE( "test_packet_parse_1" ) { packet p; bool hasbin = p.parse("42/nsp,1001[\"event\",\"text\"]"); - BOOST_CHECK(!hasbin); - BOOST_CHECK(p.get_frame() == packet::frame_message); - BOOST_CHECK(p.get_type() == packet::type_event); - BOOST_CHECK(p.get_nsp() == "/nsp"); - BOOST_CHECK(p.get_pack_id() == 1001); - BOOST_CHECK(p.get_message()->get_flag() == message::flag_array); - BOOST_REQUIRE(p.get_message()->get_vector()[0]->get_flag() == message::flag_string); - BOOST_CHECK(p.get_message()->get_vector()[0]->get_string() == "event"); - BOOST_REQUIRE(p.get_message()->get_vector()[1]->get_flag() == message::flag_string); - BOOST_CHECK(p.get_message()->get_vector()[1]->get_string() == "text"); + CHECK(!hasbin); + CHECK(p.get_frame() == packet::frame_message); + CHECK(p.get_type() == packet::type_event); + CHECK(p.get_nsp() == "/nsp"); + CHECK(p.get_pack_id() == 1001); + CHECK(p.get_message()->get_flag() == message::flag_array); + REQUIRE(p.get_message()->get_vector()[0]->get_flag() == message::flag_string); + CHECK(p.get_message()->get_vector()[0]->get_string() == "event"); + REQUIRE(p.get_message()->get_vector()[1]->get_flag() == message::flag_string); + CHECK(p.get_message()->get_vector()[1]->get_string() == "text"); hasbin = p.parse("431111[\"ack\",{\"count\":5}]"); - BOOST_CHECK(!hasbin); - BOOST_CHECK(p.get_frame() == packet::frame_message); - BOOST_CHECK(p.get_type() == packet::type_ack); - BOOST_CHECK(p.get_pack_id() == 1111); - BOOST_CHECK(p.get_nsp() == "/"); - BOOST_CHECK(p.get_message()->get_flag() == message::flag_array); - BOOST_REQUIRE(p.get_message()->get_vector()[0]->get_flag() == message::flag_string); - BOOST_CHECK(p.get_message()->get_vector()[0]->get_string() == "ack"); - BOOST_REQUIRE(p.get_message()->get_vector()[1]->get_flag() == message::flag_object); - BOOST_CHECK(p.get_message()->get_vector()[1]->get_map()["count"]->get_int() == 5); + CHECK(!hasbin); + CHECK(p.get_frame() == packet::frame_message); + CHECK(p.get_type() == packet::type_ack); + CHECK(p.get_pack_id() == 1111); + CHECK(p.get_nsp() == "/"); + CHECK(p.get_message()->get_flag() == message::flag_array); + REQUIRE(p.get_message()->get_vector()[0]->get_flag() == message::flag_string); + CHECK(p.get_message()->get_vector()[0]->get_string() == "ack"); + REQUIRE(p.get_message()->get_vector()[1]->get_flag() == message::flag_object); + CHECK(p.get_message()->get_vector()[1]->get_map()["count"]->get_int() == 5); } -BOOST_AUTO_TEST_CASE( test_packet_parse_2 ) +TEST_CASE( "test_packet_parse_2" ) { packet p; bool hasbin = p.parse("3"); - BOOST_CHECK(!hasbin); - BOOST_CHECK(p.get_frame() == packet::frame_pong); - BOOST_CHECK(!p.get_message()); - BOOST_CHECK(p.get_nsp() == "/"); - BOOST_CHECK(p.get_pack_id() == -1); + CHECK(!hasbin); + CHECK(p.get_frame() == packet::frame_pong); + CHECK(!p.get_message()); + CHECK(p.get_nsp() == "/"); + CHECK(p.get_pack_id() == -1); hasbin = p.parse("2"); - BOOST_CHECK(!hasbin); - BOOST_CHECK(p.get_frame() == packet::frame_ping); - BOOST_CHECK(!p.get_message()); - BOOST_CHECK(p.get_nsp() == "/"); - BOOST_CHECK(p.get_pack_id() == -1); + CHECK(!hasbin); + CHECK(p.get_frame() == packet::frame_ping); + CHECK(!p.get_message()); + CHECK(p.get_nsp() == "/"); + CHECK(p.get_pack_id() == -1); } -BOOST_AUTO_TEST_CASE( test_packet_parse_3 ) +TEST_CASE( "test_packet_parse_3" ) { packet p; bool hasbin = p.parse("40/nsp"); - BOOST_CHECK(!hasbin); - BOOST_CHECK(p.get_type() == packet::type_connect); - BOOST_CHECK(p.get_frame() == packet::frame_message); - BOOST_CHECK(p.get_nsp() == "/nsp"); - BOOST_CHECK(p.get_pack_id() == -1); - BOOST_CHECK(!p.get_message()); + CHECK(!hasbin); + CHECK(p.get_type() == packet::type_connect); + CHECK(p.get_frame() == packet::frame_message); + CHECK(p.get_nsp() == "/nsp"); + CHECK(p.get_pack_id() == -1); + CHECK(!p.get_message()); p.parse("40"); - BOOST_CHECK(p.get_type() == packet::type_connect); - BOOST_CHECK(p.get_nsp() == "/"); - BOOST_CHECK(p.get_pack_id() == -1); - BOOST_CHECK(!p.get_message()); + CHECK(p.get_type() == packet::type_connect); + CHECK(p.get_nsp() == "/"); + CHECK(p.get_pack_id() == -1); + CHECK(!p.get_message()); p.parse("44\"error\""); - BOOST_CHECK(p.get_type() == packet::type_error); - BOOST_CHECK(p.get_nsp() == "/"); - BOOST_CHECK(p.get_pack_id() == -1); - BOOST_CHECK(p.get_message()->get_flag() == message::flag_string); + CHECK(p.get_type() == packet::type_error); + CHECK(p.get_nsp() == "/"); + CHECK(p.get_pack_id() == -1); + CHECK(p.get_message()->get_flag() == message::flag_string); p.parse("44/nsp,\"error\""); - BOOST_CHECK(p.get_type() == packet::type_error); - BOOST_CHECK(p.get_nsp() == "/nsp"); - BOOST_CHECK(p.get_pack_id() == -1); - BOOST_CHECK(p.get_message()->get_flag() == message::flag_string); + CHECK(p.get_type() == packet::type_error); + CHECK(p.get_nsp() == "/nsp"); + CHECK(p.get_pack_id() == -1); + CHECK(p.get_message()->get_flag() == message::flag_string); } -BOOST_AUTO_TEST_CASE( test_packet_parse_4 ) +TEST_CASE( "test_packet_parse_4" ) { packet p; bool hasbin = p.parse("452-/nsp,101[\"bin_event\",[{\"_placeholder\":true,\"num\":1},{\"_placeholder\":true,\"num\":0},\"text\"]]"); - BOOST_CHECK(hasbin); - char buf[101]; + CHECK(hasbin); + char buf[100]; buf[0] = packet::frame_message; - memset(buf+1,0,100); + memset(buf + 1,0,99); - std::string bufstr(buf,101); - std::string bufstr2(buf,51); - BOOST_CHECK(p.parse_buffer(bufstr)); - BOOST_CHECK(!p.parse_buffer(bufstr2)); + std::string bufstr(buf,100); + std::string bufstr2(buf,50); + CHECK(p.parse_buffer(bufstr)); + CHECK(!p.parse_buffer(bufstr2)); - BOOST_CHECK(p.get_frame() == packet::frame_message); - BOOST_CHECK(p.get_nsp() == "/nsp"); - BOOST_CHECK(p.get_pack_id() == 101); + CHECK(p.get_frame() == packet::frame_message); + CHECK(p.get_nsp() == "/nsp"); + CHECK(p.get_pack_id() == 101); message::ptr msg = p.get_message(); - BOOST_REQUIRE(msg&&msg->get_flag() == message::flag_array); - BOOST_CHECK(msg->get_vector()[0]->get_string() == "bin_event"); + REQUIRE(msg); + REQUIRE(msg->get_flag() == message::flag_array); + CHECK(msg->get_vector()[0]->get_string() == "bin_event"); message::ptr array = msg->get_vector()[1]; - BOOST_REQUIRE(array->get_flag() == message::flag_array); - BOOST_REQUIRE(array->get_vector()[0]->get_flag() == message::flag_binary); - BOOST_REQUIRE(array->get_vector()[1]->get_flag() == message::flag_binary); - BOOST_REQUIRE(array->get_vector()[2]->get_flag() == message::flag_string); - BOOST_CHECK(array->get_vector()[0]->get_binary()->size() == 50); - BOOST_CHECK(array->get_vector()[1]->get_binary()->size() == 100); - BOOST_CHECK(array->get_vector()[2]->get_string() == "text"); + REQUIRE(array->get_flag() == message::flag_array); + REQUIRE(array->get_vector()[0]->get_flag() == message::flag_binary); + REQUIRE(array->get_vector()[1]->get_flag() == message::flag_binary); + REQUIRE(array->get_vector()[2]->get_flag() == message::flag_string); + CHECK(array->get_vector()[0]->get_binary()->size() == 50); + CHECK(array->get_vector()[1]->get_binary()->size() == 100); + CHECK(array->get_vector()[2]->get_string() == "text"); } - -BOOST_AUTO_TEST_SUITE_END() -