Compare commits
	
		
			2 Commits
		
	
	
		
			v9.6.2
			...
			feature/wi
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					bf2145eb8a | ||
| 
						 | 
					a35f8f2250 | 
							
								
								
									
										47
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							@@ -5,39 +5,7 @@ on:
 | 
			
		||||
    - 'docs/**'
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  linux:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v1
 | 
			
		||||
    - name: make test_make
 | 
			
		||||
      run: make test_make
 | 
			
		||||
 | 
			
		||||
  mac_tsan_sectransport:
 | 
			
		||||
    runs-on: macOS-latest
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v1
 | 
			
		||||
    - name: make test_tsan
 | 
			
		||||
      run: make test_tsan
 | 
			
		||||
 | 
			
		||||
  mac_tsan_openssl:
 | 
			
		||||
    runs-on: macOS-latest
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v1
 | 
			
		||||
    - name: install openssl
 | 
			
		||||
      run: brew install openssl@1.1
 | 
			
		||||
    - name: make test
 | 
			
		||||
      run: make test_tsan_openssl
 | 
			
		||||
 | 
			
		||||
  mac_tsan_mbedtls:
 | 
			
		||||
    runs-on: macOS-latest
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v1
 | 
			
		||||
    - name: install mbedtls
 | 
			
		||||
      run: brew install mbedtls
 | 
			
		||||
    - name: make test
 | 
			
		||||
      run: make test_tsan_mbedtls
 | 
			
		||||
 | 
			
		||||
  windows:
 | 
			
		||||
  windows_openssl:
 | 
			
		||||
    runs-on: windows-latest
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v1
 | 
			
		||||
@@ -45,24 +13,13 @@ jobs:
 | 
			
		||||
    - run: |
 | 
			
		||||
        mkdir build
 | 
			
		||||
        cd build
 | 
			
		||||
        cmake -DCMAKE_CXX_COMPILER=cl.exe -DUSE_WS=1 -DUSE_TEST=1 ..
 | 
			
		||||
        cmake -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0" -DCMAKE_CXX_COMPILER=cl.exe -DUSE_WS=1 -DUSE_TEST=1 ..
 | 
			
		||||
    - run: cmake --build build
 | 
			
		||||
 | 
			
		||||
    # Running the unittest does not work, the binary cannot be found
 | 
			
		||||
    #- run: ../build/test/ixwebsocket_unittest.exe
 | 
			
		||||
    # working-directory: test
 | 
			
		||||
 | 
			
		||||
  uwp:
 | 
			
		||||
    runs-on: windows-latest
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v1
 | 
			
		||||
    - uses: seanmiddleditch/gha-setup-vsdevenv@master
 | 
			
		||||
    - run: |
 | 
			
		||||
        mkdir build
 | 
			
		||||
        cd build
 | 
			
		||||
        cmake -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0" -DCMAKE_CXX_COMPILER=cl.exe -DUSE_TEST=1 ..
 | 
			
		||||
    - run: cmake --build build
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
#   Windows with OpenSSL is working but disabled as it takes 13 minutes (10 for openssl) to build with vcpkg
 | 
			
		||||
#
 | 
			
		||||
 
 | 
			
		||||
@@ -12,10 +12,6 @@ set (CMAKE_CXX_STANDARD 14)
 | 
			
		||||
set (CXX_STANDARD_REQUIRED ON)
 | 
			
		||||
set (CMAKE_CXX_EXTENSIONS OFF)
 | 
			
		||||
 | 
			
		||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
 | 
			
		||||
  set(CMAKE_POSITION_INDEPENDENT_CODE ON)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if (UNIX)
 | 
			
		||||
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic")
 | 
			
		||||
endif()
 | 
			
		||||
@@ -123,11 +119,6 @@ if (USE_TLS)
 | 
			
		||||
      if (NOT USE_MBED_TLS AND NOT USE_OPEN_SSL) # unless we want something else
 | 
			
		||||
        set(USE_SECURE_TRANSPORT ON)
 | 
			
		||||
      endif()
 | 
			
		||||
    # default to mbedtls on windows if nothing is configured
 | 
			
		||||
    elseif (WIN32)
 | 
			
		||||
      if (NOT USE_OPEN_SSL) # unless we want something else
 | 
			
		||||
        set(USE_MBED_TLS ON)
 | 
			
		||||
      endif()
 | 
			
		||||
    else() # default to OpenSSL on all other platforms
 | 
			
		||||
      if (NOT USE_MBED_TLS) # Unless mbedtls is requested
 | 
			
		||||
        set(USE_OPEN_SSL ON)
 | 
			
		||||
@@ -153,8 +144,6 @@ add_library( ixwebsocket STATIC
 | 
			
		||||
    ${IXWEBSOCKET_HEADERS}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
add_library ( ixwebsocket::ixwebsocket ALIAS ixwebsocket )
 | 
			
		||||
 | 
			
		||||
if (USE_TLS)
 | 
			
		||||
    target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_TLS)
 | 
			
		||||
    if (USE_MBED_TLS)
 | 
			
		||||
@@ -176,28 +165,26 @@ if (USE_TLS)
 | 
			
		||||
    if (APPLE)
 | 
			
		||||
      set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /usr/local/opt/openssl/lib)
 | 
			
		||||
      set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} /usr/local/opt/openssl/include)
 | 
			
		||||
 | 
			
		||||
      # This is for MacPort OpenSSL 1.0
 | 
			
		||||
      # set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /opt/local/lib/openssl-1.0)
 | 
			
		||||
      # set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} /opt/local/include/openssl-1.0)
 | 
			
		||||
    endif()
 | 
			
		||||
 | 
			
		||||
    # This OPENSSL_FOUND check is to help find a cmake manually configured OpenSSL
 | 
			
		||||
    if (NOT OPENSSL_FOUND)
 | 
			
		||||
	    include(FindOpenSSL)
 | 
			
		||||
      find_package(OpenSSL REQUIRED)
 | 
			
		||||
    endif()
 | 
			
		||||
    message(STATUS "OpenSSL: " ${OPENSSL_VERSION})
 | 
			
		||||
 | 
			
		||||
    target_link_libraries(ixwebsocket PUBLIC OpenSSL::SSL OpenSSL::Crypto)
 | 
			
		||||
    add_definitions(${OPENSSL_DEFINITIONS})
 | 
			
		||||
    target_include_directories(ixwebsocket PUBLIC ${OPENSSL_INCLUDE_DIR})
 | 
			
		||||
    target_link_libraries(ixwebsocket ${OPENSSL_LIBRARIES})
 | 
			
		||||
  elseif (USE_MBED_TLS)
 | 
			
		||||
    message(STATUS "TLS configured to use mbedtls")
 | 
			
		||||
 | 
			
		||||
    find_package(MbedTLS REQUIRED)
 | 
			
		||||
    target_include_directories(ixwebsocket PUBLIC ${MBEDTLS_INCLUDE_DIRS})
 | 
			
		||||
    target_link_libraries(ixwebsocket PUBLIC ${MBEDTLS_LIBRARIES})
 | 
			
		||||
    target_link_libraries(ixwebsocket ${MBEDTLS_LIBRARIES})
 | 
			
		||||
  elseif (USE_SECURE_TRANSPORT)
 | 
			
		||||
    message(STATUS "TLS configured to use secure transport")
 | 
			
		||||
    target_link_libraries(ixwebsocket PUBLIC "-framework foundation" "-framework security")
 | 
			
		||||
    target_link_libraries(ixwebsocket "-framework foundation" "-framework security")
 | 
			
		||||
  endif()
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
@@ -207,25 +194,25 @@ if (NOT ZLIB_FOUND)
 | 
			
		||||
endif()
 | 
			
		||||
if (ZLIB_FOUND)
 | 
			
		||||
  include_directories(${ZLIB_INCLUDE_DIRS})
 | 
			
		||||
  target_link_libraries(ixwebsocket PUBLIC ${ZLIB_LIBRARIES})
 | 
			
		||||
  target_link_libraries(ixwebsocket ${ZLIB_LIBRARIES})
 | 
			
		||||
else()
 | 
			
		||||
  include_directories(third_party/zlib ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib)
 | 
			
		||||
  add_subdirectory(third_party/zlib EXCLUDE_FROM_ALL)
 | 
			
		||||
  target_link_libraries(ixwebsocket PRIVATE $<LINK_ONLY:zlibstatic>)
 | 
			
		||||
  add_subdirectory(third_party/zlib)
 | 
			
		||||
  target_link_libraries(ixwebsocket zlibstatic)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if (WIN32)
 | 
			
		||||
  target_link_libraries(ixwebsocket PUBLIC wsock32 ws2_32 shlwapi)
 | 
			
		||||
  target_link_libraries(ixwebsocket wsock32 ws2_32 shlwapi)
 | 
			
		||||
  add_definitions(-D_CRT_SECURE_NO_WARNINGS)
 | 
			
		||||
 | 
			
		||||
  if (USE_TLS)
 | 
			
		||||
    target_link_libraries(ixwebsocket PUBLIC Crypt32)
 | 
			
		||||
    target_link_libraries(ixwebsocket Crypt32)
 | 
			
		||||
  endif()
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if (UNIX)
 | 
			
		||||
  find_package(Threads)
 | 
			
		||||
  target_link_libraries(ixwebsocket PUBLIC ${CMAKE_THREAD_LIBS_INIT})
 | 
			
		||||
  target_link_libraries(ixwebsocket ${CMAKE_THREAD_LIBS_INIT})
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -238,23 +225,15 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
 | 
			
		||||
    target_compile_options(ixwebsocket PRIVATE /MP)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
target_include_directories(ixwebsocket PUBLIC $<BUILD_INTERFACE:${IXWEBSOCKET_INCLUDE_DIRS}> $<INSTALL_INTERFACE:include/ixwebsocket>)
 | 
			
		||||
target_include_directories(ixwebsocket PUBLIC ${IXWEBSOCKET_INCLUDE_DIRS})
 | 
			
		||||
 | 
			
		||||
set_target_properties(ixwebsocket PROPERTIES PUBLIC_HEADER "${IXWEBSOCKET_HEADERS}")
 | 
			
		||||
 | 
			
		||||
install(TARGETS ixwebsocket EXPORT ixwebsocket
 | 
			
		||||
	ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
 | 
			
		||||
	PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_PREFIX}/include/ixwebsocket/
 | 
			
		||||
install(TARGETS ixwebsocket
 | 
			
		||||
        ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
 | 
			
		||||
        PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_PREFIX}/include/ixwebsocket/
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# This gets in the way of vcpkg in ways I do not know how to fix
 | 
			
		||||
# https://github.com/microsoft/vcpkg/pull/11030
 | 
			
		||||
# Maybe using vcpkg_fixup_cmake_targets could fix it
 | 
			
		||||
if (INSTALL_CMAKE_FILE)
 | 
			
		||||
  install(EXPORT ixwebsocket NAMESPACE ixwebsocket:: DESTINATION lib/cmake/ixwebsocket)
 | 
			
		||||
  export(EXPORT ixwebsocket NAMESPACE ixwebsocket:: FILE ixwebsocketConfig.cmake)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if (USE_WS OR USE_TEST)
 | 
			
		||||
  add_subdirectory(ixcore)
 | 
			
		||||
  add_subdirectory(ixcrypto)
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,3 @@ IXWebSocket client code is autobahn compliant beginning with the 6.0.0 version.
 | 
			
		||||
If your company or project is using this library, feel free to open an issue or PR to amend this list.
 | 
			
		||||
 | 
			
		||||
- [Machine Zone](https://www.mz.com)
 | 
			
		||||
- [Tokio](https://gitlab.com/HCInk/tokio), a discord library focused on audio playback with node bindings.
 | 
			
		||||
- [libDiscordBot](https://github.com/tostc/libDiscordBot/tree/master), a work in progress discord library
 | 
			
		||||
- [gwebsocket](https://github.com/norrbotten/gwebsocket), a websocket (lua) module for Garry's Mod
 | 
			
		||||
- [DisCPP](https://github.com/DisCPP/DisCPP), a simple but feature rich Discord API wrapper
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ FROM alpine:3.11 as build
 | 
			
		||||
 | 
			
		||||
RUN apk add --no-cache \
 | 
			
		||||
    gcc g++ musl-dev linux-headers \
 | 
			
		||||
    cmake mbedtls-dev make zlib-dev ninja
 | 
			
		||||
    cmake mbedtls-dev make zlib-dev
 | 
			
		||||
 | 
			
		||||
RUN addgroup -S app && \
 | 
			
		||||
    adduser -S -G app app && \
 | 
			
		||||
 
 | 
			
		||||
@@ -1,46 +1,6 @@
 | 
			
		||||
# Changelog
 | 
			
		||||
All changes to this project will be documented in this file.
 | 
			
		||||
 | 
			
		||||
## [9.6.2] - 2020-05-17
 | 
			
		||||
 | 
			
		||||
(cmake) make install cmake files optional to not conflict with vcpkg
 | 
			
		||||
 | 
			
		||||
## [9.6.1] - 2020-05-17
 | 
			
		||||
 | 
			
		||||
(windows + tls) mbedtls is the default windows tls backend + add ability to load system certificates with mbdetls on windows
 | 
			
		||||
 | 
			
		||||
## [9.6.0] - 2020-05-12
 | 
			
		||||
 | 
			
		||||
(ixbots) add options to limit how many messages per minute should be processed
 | 
			
		||||
 | 
			
		||||
## [9.5.9] - 2020-05-12
 | 
			
		||||
 | 
			
		||||
(ixbots) add new class to configure a bot to simplify passing options around
 | 
			
		||||
 | 
			
		||||
## [9.5.8] - 2020-05-08
 | 
			
		||||
 | 
			
		||||
(openssl tls) (openssl < 1.1) logic inversion - crypto locking callback are not registered properly
 | 
			
		||||
 | 
			
		||||
## [9.5.7] - 2020-05-08
 | 
			
		||||
 | 
			
		||||
(cmake) default TLS back to mbedtls on Windows Universal Platform
 | 
			
		||||
 | 
			
		||||
## [9.5.6] - 2020-05-06
 | 
			
		||||
 | 
			
		||||
(cobra bots) add a --heartbeat_timeout option to specify when the bot should terminate because no events are received
 | 
			
		||||
 | 
			
		||||
## [9.5.5] - 2020-05-06
 | 
			
		||||
 | 
			
		||||
(openssl tls) when OpenSSL is older than 1.1, register the crypto locking callback to be thread safe. Should fix lots of CI failures
 | 
			
		||||
 | 
			
		||||
## [9.5.4] - 2020-05-04
 | 
			
		||||
 | 
			
		||||
(cobra bots) do not use a queue to store messages pending processing, let the bot handle queuing
 | 
			
		||||
 | 
			
		||||
## [9.5.3] - 2020-04-29
 | 
			
		||||
 | 
			
		||||
(http client) better current request cancellation support when the HttpClient destructor is invoked (see #189)
 | 
			
		||||
 | 
			
		||||
## [9.5.2] - 2020-04-27
 | 
			
		||||
 | 
			
		||||
(cmake) fix cmake broken tls option parsing
 | 
			
		||||
 
 | 
			
		||||
@@ -8,15 +8,16 @@ set (IXBOTS_SOURCES
 | 
			
		||||
    ixbots/IXCobraToSentryBot.cpp
 | 
			
		||||
    ixbots/IXCobraToStatsdBot.cpp
 | 
			
		||||
    ixbots/IXCobraToStdoutBot.cpp
 | 
			
		||||
    ixbots/IXQueueManager.cpp
 | 
			
		||||
    ixbots/IXStatsdClient.cpp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set (IXBOTS_HEADERS
 | 
			
		||||
    ixbots/IXCobraBot.h
 | 
			
		||||
    ixbots/IXCobraBotConfig.h
 | 
			
		||||
    ixbots/IXCobraToSentryBot.h
 | 
			
		||||
    ixbots/IXCobraToStatsdBot.h
 | 
			
		||||
    ixbots/IXCobraToStdoutBot.h
 | 
			
		||||
    ixbots/IXQueueManager.h
 | 
			
		||||
    ixbots/IXStatsdClient.h
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
 | 
			
		||||
#include "IXCobraBot.h"
 | 
			
		||||
 | 
			
		||||
#include "IXQueueManager.h"
 | 
			
		||||
#include <ixcobra/IXCobraConnection.h>
 | 
			
		||||
#include <ixcore/utils/IXCoreLogger.h>
 | 
			
		||||
 | 
			
		||||
@@ -17,33 +18,32 @@
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    int64_t CobraBot::run(const CobraBotConfig& botConfig)
 | 
			
		||||
    int64_t CobraBot::run(const CobraConfig& config,
 | 
			
		||||
                          const std::string& channel,
 | 
			
		||||
                          const std::string& filter,
 | 
			
		||||
                          const std::string& position,
 | 
			
		||||
                          bool verbose,
 | 
			
		||||
                          size_t maxQueueSize,
 | 
			
		||||
                          bool useQueue,
 | 
			
		||||
                          bool enableHeartbeat,
 | 
			
		||||
                          int runtime)
 | 
			
		||||
    {
 | 
			
		||||
        auto config = botConfig.cobraConfig;
 | 
			
		||||
        auto channel = botConfig.channel;
 | 
			
		||||
        auto filter = botConfig.filter;
 | 
			
		||||
        auto position = botConfig.position;
 | 
			
		||||
        auto enableHeartbeat = botConfig.enableHeartbeat;
 | 
			
		||||
        auto heartBeatTimeout = botConfig.heartBeatTimeout;
 | 
			
		||||
        auto runtime = botConfig.runtime;
 | 
			
		||||
        auto maxEventsPerMinute = botConfig.maxEventsPerMinute;
 | 
			
		||||
        auto limitReceivedEvents = botConfig.limitReceivedEvents;
 | 
			
		||||
 | 
			
		||||
        ix::CobraConnection conn;
 | 
			
		||||
        conn.configure(config);
 | 
			
		||||
        conn.connect();
 | 
			
		||||
 | 
			
		||||
        Json::FastWriter jsonWriter;
 | 
			
		||||
        std::atomic<uint64_t> sentCount(0);
 | 
			
		||||
        std::atomic<uint64_t> receivedCount(0);
 | 
			
		||||
        uint64_t sentCountTotal(0);
 | 
			
		||||
        uint64_t receivedCountTotal(0);
 | 
			
		||||
        uint64_t sentCountPerSecs(0);
 | 
			
		||||
        uint64_t receivedCountPerSecs(0);
 | 
			
		||||
        std::atomic<int> receivedCountPerMinutes(0);
 | 
			
		||||
        std::atomic<bool> stop(false);
 | 
			
		||||
        std::atomic<bool> throttled(false);
 | 
			
		||||
        std::atomic<bool> fatalCobraError(false);
 | 
			
		||||
        int minuteCounter = 0;
 | 
			
		||||
 | 
			
		||||
        QueueManager queueManager(maxQueueSize);
 | 
			
		||||
 | 
			
		||||
        auto timer = [&sentCount,
 | 
			
		||||
                      &receivedCount,
 | 
			
		||||
@@ -51,8 +51,6 @@ namespace ix
 | 
			
		||||
                      &receivedCountTotal,
 | 
			
		||||
                      &sentCountPerSecs,
 | 
			
		||||
                      &receivedCountPerSecs,
 | 
			
		||||
                      &receivedCountPerMinutes,
 | 
			
		||||
                      &minuteCounter,
 | 
			
		||||
                      &stop] {
 | 
			
		||||
            while (!stop)
 | 
			
		||||
            {
 | 
			
		||||
@@ -73,19 +71,13 @@ namespace ix
 | 
			
		||||
                CoreLogger::info(ss.str());
 | 
			
		||||
 | 
			
		||||
                receivedCountPerSecs = receivedCount - receivedCountTotal;
 | 
			
		||||
                sentCountPerSecs = sentCount - sentCountTotal;
 | 
			
		||||
                sentCountPerSecs = sentCount - receivedCountTotal;
 | 
			
		||||
 | 
			
		||||
                receivedCountTotal += receivedCountPerSecs;
 | 
			
		||||
                sentCountTotal += sentCountPerSecs;
 | 
			
		||||
 | 
			
		||||
                auto duration = std::chrono::seconds(1);
 | 
			
		||||
                std::this_thread::sleep_for(duration);
 | 
			
		||||
 | 
			
		||||
                if (minuteCounter++ == 60)
 | 
			
		||||
                {
 | 
			
		||||
                    receivedCountPerMinutes = 0;
 | 
			
		||||
                    minuteCounter = 0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            CoreLogger::info("timer thread done");
 | 
			
		||||
@@ -93,7 +85,7 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
        std::thread t1(timer);
 | 
			
		||||
 | 
			
		||||
        auto heartbeat = [&sentCount, &receivedCount, &stop, &enableHeartbeat, &heartBeatTimeout, &fatalCobraError] {
 | 
			
		||||
        auto heartbeat = [&sentCount, &receivedCount, &stop, &enableHeartbeat] {
 | 
			
		||||
            std::string state("na");
 | 
			
		||||
 | 
			
		||||
            if (!enableHeartbeat) return;
 | 
			
		||||
@@ -109,12 +101,11 @@ namespace ix
 | 
			
		||||
                if (currentState == state)
 | 
			
		||||
                {
 | 
			
		||||
                    CoreLogger::error("no messages received or sent for 1 minute, exiting");
 | 
			
		||||
                    fatalCobraError = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                    exit(1);
 | 
			
		||||
                }
 | 
			
		||||
                state = currentState;
 | 
			
		||||
 | 
			
		||||
                auto duration = std::chrono::seconds(heartBeatTimeout);
 | 
			
		||||
                auto duration = std::chrono::minutes(1);
 | 
			
		||||
                std::this_thread::sleep_for(duration);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -123,6 +114,40 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
        std::thread t2(heartbeat);
 | 
			
		||||
 | 
			
		||||
        auto sender =
 | 
			
		||||
            [this, &queueManager, verbose, &sentCount, &stop, &throttled, &fatalCobraError] {
 | 
			
		||||
                while (true)
 | 
			
		||||
                {
 | 
			
		||||
                    auto data = queueManager.pop();
 | 
			
		||||
                    Json::Value msg = data.first;
 | 
			
		||||
                    std::string position = data.second;
 | 
			
		||||
 | 
			
		||||
                    if (stop) break;
 | 
			
		||||
                    if (msg.isNull()) continue;
 | 
			
		||||
 | 
			
		||||
                    if (_onBotMessageCallback &&
 | 
			
		||||
                        _onBotMessageCallback(msg, position, verbose, throttled, fatalCobraError))
 | 
			
		||||
                    {
 | 
			
		||||
                        // That might be too noisy
 | 
			
		||||
                        if (verbose)
 | 
			
		||||
                        {
 | 
			
		||||
                            CoreLogger::info("cobra bot: sending succesfull");
 | 
			
		||||
                        }
 | 
			
		||||
                        ++sentCount;
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        CoreLogger::error("cobra bot: error sending");
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (stop) break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                CoreLogger::info("sender thread done");
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
        std::thread t3(sender);
 | 
			
		||||
 | 
			
		||||
        std::string subscriptionPosition(position);
 | 
			
		||||
 | 
			
		||||
        conn.setEventCallback([this,
 | 
			
		||||
@@ -130,12 +155,13 @@ namespace ix
 | 
			
		||||
                               &channel,
 | 
			
		||||
                               &filter,
 | 
			
		||||
                               &subscriptionPosition,
 | 
			
		||||
                               &jsonWriter,
 | 
			
		||||
                               verbose,
 | 
			
		||||
                               &throttled,
 | 
			
		||||
                               &receivedCount,
 | 
			
		||||
                               &receivedCountPerMinutes,
 | 
			
		||||
                               maxEventsPerMinute,
 | 
			
		||||
                               limitReceivedEvents,
 | 
			
		||||
                               &fatalCobraError,
 | 
			
		||||
                               &useQueue,
 | 
			
		||||
                               &queueManager,
 | 
			
		||||
                               &sentCount](const CobraEventPtr& event) {
 | 
			
		||||
            if (event->type == ix::CobraEventType::Open)
 | 
			
		||||
            {
 | 
			
		||||
@@ -156,34 +182,58 @@ namespace ix
 | 
			
		||||
                CoreLogger::info("Subscribing to " + channel);
 | 
			
		||||
                CoreLogger::info("Subscribing at position " + subscriptionPosition);
 | 
			
		||||
                CoreLogger::info("Subscribing with filter " + filter);
 | 
			
		||||
                conn.subscribe(channel, filter, subscriptionPosition,
 | 
			
		||||
                    [&sentCount, &receivedCountPerMinutes,
 | 
			
		||||
                     maxEventsPerMinute, limitReceivedEvents,
 | 
			
		||||
                     &throttled, &receivedCount,
 | 
			
		||||
                     &subscriptionPosition, &fatalCobraError,
 | 
			
		||||
                     this](const Json::Value& msg, const std::string& position) {
 | 
			
		||||
                        subscriptionPosition = position;
 | 
			
		||||
                        ++receivedCount;
 | 
			
		||||
                conn.subscribe(channel,
 | 
			
		||||
                               filter,
 | 
			
		||||
                               subscriptionPosition,
 | 
			
		||||
                               [this,
 | 
			
		||||
                                &jsonWriter,
 | 
			
		||||
                                verbose,
 | 
			
		||||
                                &throttled,
 | 
			
		||||
                                &receivedCount,
 | 
			
		||||
                                &queueManager,
 | 
			
		||||
                                &useQueue,
 | 
			
		||||
                                &subscriptionPosition,
 | 
			
		||||
                                &fatalCobraError,
 | 
			
		||||
                                &sentCount](const Json::Value& msg, const std::string& position) {
 | 
			
		||||
                                   if (verbose)
 | 
			
		||||
                                   {
 | 
			
		||||
                                       CoreLogger::info("Subscriber received message "
 | 
			
		||||
                                                        + position + " -> " + jsonWriter.write(msg));
 | 
			
		||||
                                   }
 | 
			
		||||
 | 
			
		||||
                        ++receivedCountPerMinutes;
 | 
			
		||||
                        if (limitReceivedEvents)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (receivedCountPerMinutes > maxEventsPerMinute)
 | 
			
		||||
                            {
 | 
			
		||||
                                return;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                                   subscriptionPosition = position;
 | 
			
		||||
 | 
			
		||||
                        // If we cannot send to sentry fast enough, drop the message
 | 
			
		||||
                        if (throttled)
 | 
			
		||||
                        {
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                                   // If we cannot send to sentry fast enough, drop the message
 | 
			
		||||
                                   if (throttled)
 | 
			
		||||
                                   {
 | 
			
		||||
                                       return;
 | 
			
		||||
                                   }
 | 
			
		||||
 | 
			
		||||
                        _onBotMessageCallback(
 | 
			
		||||
                            msg, position, throttled,
 | 
			
		||||
                            fatalCobraError, sentCount);
 | 
			
		||||
                    });
 | 
			
		||||
                                   ++receivedCount;
 | 
			
		||||
 | 
			
		||||
                                   if (useQueue)
 | 
			
		||||
                                   {
 | 
			
		||||
                                       queueManager.add(msg, position);
 | 
			
		||||
                                   }
 | 
			
		||||
                                   else
 | 
			
		||||
                                   {
 | 
			
		||||
                                       if (_onBotMessageCallback &&
 | 
			
		||||
                                           _onBotMessageCallback(
 | 
			
		||||
                                               msg, position, verbose, throttled, fatalCobraError))
 | 
			
		||||
                                       {
 | 
			
		||||
                                           // That might be too noisy
 | 
			
		||||
                                           if (verbose)
 | 
			
		||||
                                           {
 | 
			
		||||
                                               CoreLogger::info("cobra bot: sending succesfull");
 | 
			
		||||
                                           }
 | 
			
		||||
                                           ++sentCount;
 | 
			
		||||
                                       }
 | 
			
		||||
                                       else
 | 
			
		||||
                                       {
 | 
			
		||||
                                           CoreLogger::error("cobra bot: error sending");
 | 
			
		||||
                                       }
 | 
			
		||||
                                   }
 | 
			
		||||
                               });
 | 
			
		||||
            }
 | 
			
		||||
            else if (event->type == ix::CobraEventType::Subscribed)
 | 
			
		||||
            {
 | 
			
		||||
@@ -258,6 +308,9 @@ namespace ix
 | 
			
		||||
        // heartbeat thread
 | 
			
		||||
        if (t2.joinable()) t2.join();
 | 
			
		||||
 | 
			
		||||
        // sentry sender thread
 | 
			
		||||
        t3.join();
 | 
			
		||||
 | 
			
		||||
        return fatalCobraError ? -1 : (int64_t) sentCount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,24 +8,33 @@
 | 
			
		||||
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include "IXCobraBotConfig.h"
 | 
			
		||||
#include <ixcobra/IXCobraConfig.h>
 | 
			
		||||
#include <json/json.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    using OnBotMessageCallback = std::function<void(const Json::Value&,
 | 
			
		||||
    using OnBotMessageCallback = std::function<bool(const Json::Value&,
 | 
			
		||||
                                                    const std::string&,
 | 
			
		||||
                                                    const bool verbose,
 | 
			
		||||
                                                    std::atomic<bool>&,
 | 
			
		||||
                                                    std::atomic<bool>&,
 | 
			
		||||
                                                    std::atomic<uint64_t>&)>;
 | 
			
		||||
                                                    std::atomic<bool>&)>;
 | 
			
		||||
 | 
			
		||||
    class CobraBot
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        CobraBot() = default;
 | 
			
		||||
 | 
			
		||||
        int64_t run(const CobraBotConfig& botConfig);
 | 
			
		||||
        int64_t run(const CobraConfig& config,
 | 
			
		||||
                    const std::string& channel,
 | 
			
		||||
                    const std::string& filter,
 | 
			
		||||
                    const std::string& position,
 | 
			
		||||
                    bool verbose,
 | 
			
		||||
                    size_t maxQueueSize,
 | 
			
		||||
                    bool useQueue,
 | 
			
		||||
                    bool enableHeartbeat,
 | 
			
		||||
                    int runtime);
 | 
			
		||||
 | 
			
		||||
        void setOnBotMessageCallback(const OnBotMessageCallback& callback);
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  IXCobraBotConfig.h
 | 
			
		||||
 *  Author: Benjamin Sergeant
 | 
			
		||||
 *  Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <ixcobra/IXCobraConfig.h>
 | 
			
		||||
 | 
			
		||||
#ifdef max
 | 
			
		||||
#undef max
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    struct CobraBotConfig
 | 
			
		||||
    {
 | 
			
		||||
        CobraConfig cobraConfig;
 | 
			
		||||
        std::string channel;
 | 
			
		||||
        std::string filter;
 | 
			
		||||
        std::string position = std::string("$");
 | 
			
		||||
        bool enableHeartbeat = true;
 | 
			
		||||
        int heartBeatTimeout = 60;
 | 
			
		||||
        int runtime = -1;
 | 
			
		||||
        int maxEventsPerMinute = std::numeric_limits<int>::max();
 | 
			
		||||
        bool limitReceivedEvents = false;
 | 
			
		||||
    };
 | 
			
		||||
} // namespace ix
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
#include "IXCobraToSentryBot.h"
 | 
			
		||||
 | 
			
		||||
#include "IXCobraBot.h"
 | 
			
		||||
#include "IXQueueManager.h"
 | 
			
		||||
#include <ixcobra/IXCobraConnection.h>
 | 
			
		||||
#include <ixcore/utils/IXCoreLogger.h>
 | 
			
		||||
 | 
			
		||||
@@ -16,61 +17,101 @@
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    int64_t cobra_to_sentry_bot(const CobraBotConfig& config,
 | 
			
		||||
    int64_t cobra_to_sentry_bot(const CobraConfig& config,
 | 
			
		||||
                                const std::string& channel,
 | 
			
		||||
                                const std::string& filter,
 | 
			
		||||
                                const std::string& position,
 | 
			
		||||
                                SentryClient& sentryClient,
 | 
			
		||||
                                bool verbose)
 | 
			
		||||
                                bool verbose,
 | 
			
		||||
                                size_t maxQueueSize,
 | 
			
		||||
                                bool enableHeartbeat,
 | 
			
		||||
                                int runtime)
 | 
			
		||||
    {
 | 
			
		||||
        CobraBot bot;
 | 
			
		||||
        bot.setOnBotMessageCallback([&sentryClient, &verbose](const Json::Value& msg,
 | 
			
		||||
        bot.setOnBotMessageCallback([&sentryClient](const Json::Value& msg,
 | 
			
		||||
                                                    const std::string& /*position*/,
 | 
			
		||||
                                                    const bool verbose,
 | 
			
		||||
                                                    std::atomic<bool>& throttled,
 | 
			
		||||
                                                    std::atomic<bool>& /*fatalCobraError*/,
 | 
			
		||||
                                                    std::atomic<uint64_t>& sentCount) -> void {
 | 
			
		||||
            sentryClient.send(msg, verbose,
 | 
			
		||||
                [&sentCount, &throttled](const HttpResponsePtr& response) {
 | 
			
		||||
                if (!response)
 | 
			
		||||
                                                    std::atomic<bool> &
 | 
			
		||||
                                                    /*fatalCobraError*/) -> bool {
 | 
			
		||||
            auto ret = sentryClient.send(msg, verbose);
 | 
			
		||||
            HttpResponsePtr response = ret.first;
 | 
			
		||||
 | 
			
		||||
            if (!response)
 | 
			
		||||
            {
 | 
			
		||||
                CoreLogger::warn("Null HTTP Response");
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (verbose)
 | 
			
		||||
            {
 | 
			
		||||
                for (auto it : response->headers)
 | 
			
		||||
                {
 | 
			
		||||
                    CoreLogger::warn("Null HTTP Response");
 | 
			
		||||
                    return;
 | 
			
		||||
                    CoreLogger::info(it.first + ": " + it.second);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (response->statusCode == 200)
 | 
			
		||||
                {
 | 
			
		||||
                    sentCount++;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    CoreLogger::error("Error sending data to sentry: " + std::to_string(response->statusCode));
 | 
			
		||||
                    CoreLogger::error("Response: " + response->payload);
 | 
			
		||||
                CoreLogger::info("Upload size: " + std::to_string(response->uploadSize));
 | 
			
		||||
                CoreLogger::info("Download size: " + std::to_string(response->downloadSize));
 | 
			
		||||
 | 
			
		||||
                    // Error 429 Too Many Requests
 | 
			
		||||
                    if (response->statusCode == 429)
 | 
			
		||||
                CoreLogger::info("Status: " + std::to_string(response->statusCode));
 | 
			
		||||
                if (response->errorCode != HttpErrorCode::Ok)
 | 
			
		||||
                {
 | 
			
		||||
                    CoreLogger::info("error message: " + response->errorMsg);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (response->headers["Content-Type"] != "application/octet-stream")
 | 
			
		||||
                {
 | 
			
		||||
                    CoreLogger::info("payload: " + response->payload);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            bool success = response->statusCode == 200;
 | 
			
		||||
 | 
			
		||||
            if (!success)
 | 
			
		||||
            {
 | 
			
		||||
                CoreLogger::error("Error sending data to sentry: " + std::to_string(response->statusCode));
 | 
			
		||||
                CoreLogger::error("Body: " + ret.second);
 | 
			
		||||
                CoreLogger::error("Response: " + response->payload);
 | 
			
		||||
 | 
			
		||||
                // Error 429 Too Many Requests
 | 
			
		||||
                if (response->statusCode == 429)
 | 
			
		||||
                {
 | 
			
		||||
                    auto retryAfter = response->headers["Retry-After"];
 | 
			
		||||
                    std::stringstream ss;
 | 
			
		||||
                    ss << retryAfter;
 | 
			
		||||
                    int seconds;
 | 
			
		||||
                    ss >> seconds;
 | 
			
		||||
 | 
			
		||||
                    if (!ss.eof() || ss.fail())
 | 
			
		||||
                    {
 | 
			
		||||
                        auto retryAfter = response->headers["Retry-After"];
 | 
			
		||||
                        std::stringstream ss;
 | 
			
		||||
                        ss << retryAfter;
 | 
			
		||||
                        int seconds;
 | 
			
		||||
                        ss >> seconds;
 | 
			
		||||
 | 
			
		||||
                        if (!ss.eof() || ss.fail())
 | 
			
		||||
                        {
 | 
			
		||||
                            seconds = 30;
 | 
			
		||||
                            CoreLogger::warn("Error parsing Retry-After header. "
 | 
			
		||||
                                             "Using " + retryAfter + " for the sleep duration");
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        CoreLogger::warn("Error 429 - Too Many Requests. ws will sleep "
 | 
			
		||||
                                         "and retry after " + retryAfter + " seconds");
 | 
			
		||||
 | 
			
		||||
                        throttled = true;
 | 
			
		||||
                        auto duration = std::chrono::seconds(seconds);
 | 
			
		||||
                        std::this_thread::sleep_for(duration);
 | 
			
		||||
                        throttled = false;
 | 
			
		||||
                        seconds = 30;
 | 
			
		||||
                        CoreLogger::warn("Error parsing Retry-After header. "
 | 
			
		||||
                                         "Using " + retryAfter + " for the sleep duration");
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    CoreLogger::warn("Error 429 - Too Many Requests. ws will sleep "
 | 
			
		||||
                                     "and retry after " + retryAfter + " seconds");
 | 
			
		||||
 | 
			
		||||
                    throttled = true;
 | 
			
		||||
                    auto duration = std::chrono::seconds(seconds);
 | 
			
		||||
                    std::this_thread::sleep_for(duration);
 | 
			
		||||
                    throttled = false;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return success;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return bot.run(config);
 | 
			
		||||
        bool useQueue = true;
 | 
			
		||||
 | 
			
		||||
        return bot.run(config,
 | 
			
		||||
                       channel,
 | 
			
		||||
                       filter,
 | 
			
		||||
                       position,
 | 
			
		||||
                       verbose,
 | 
			
		||||
                       maxQueueSize,
 | 
			
		||||
                       useQueue,
 | 
			
		||||
                       enableHeartbeat,
 | 
			
		||||
                       runtime);
 | 
			
		||||
    }
 | 
			
		||||
} // namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -6,13 +6,19 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include "IXCobraBotConfig.h"
 | 
			
		||||
#include <ixcobra/IXCobraConfig.h>
 | 
			
		||||
#include <ixsentry/IXSentryClient.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    int64_t cobra_to_sentry_bot(const CobraBotConfig& config,
 | 
			
		||||
    int64_t cobra_to_sentry_bot(const CobraConfig& config,
 | 
			
		||||
                                const std::string& channel,
 | 
			
		||||
                                const std::string& filter,
 | 
			
		||||
                                const std::string& position,
 | 
			
		||||
                                SentryClient& sentryClient,
 | 
			
		||||
                                bool verbose);
 | 
			
		||||
                                bool verbose,
 | 
			
		||||
                                size_t maxQueueSize,
 | 
			
		||||
                                bool enableHeartbeat,
 | 
			
		||||
                                int runtime);
 | 
			
		||||
} // namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
#include "IXCobraToStatsdBot.h"
 | 
			
		||||
 | 
			
		||||
#include "IXCobraBot.h"
 | 
			
		||||
#include "IXQueueManager.h"
 | 
			
		||||
#include "IXStatsdClient.h"
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <ixcobra/IXCobraConnection.h>
 | 
			
		||||
@@ -53,22 +54,32 @@ namespace ix
 | 
			
		||||
        return val;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int64_t cobra_to_statsd_bot(const ix::CobraBotConfig& config,
 | 
			
		||||
    int64_t cobra_to_statsd_bot(const ix::CobraConfig& config,
 | 
			
		||||
                                const std::string& channel,
 | 
			
		||||
                                const std::string& filter,
 | 
			
		||||
                                const std::string& position,
 | 
			
		||||
                                StatsdClient& statsdClient,
 | 
			
		||||
                                const std::string& fields,
 | 
			
		||||
                                const std::string& gauge,
 | 
			
		||||
                                const std::string& timer,
 | 
			
		||||
                                bool verbose)
 | 
			
		||||
                                bool verbose,
 | 
			
		||||
                                size_t maxQueueSize,
 | 
			
		||||
                                bool enableHeartbeat,
 | 
			
		||||
                                int runtime)
 | 
			
		||||
    {
 | 
			
		||||
        ix::CobraConnection conn;
 | 
			
		||||
        conn.configure(config);
 | 
			
		||||
        conn.connect();
 | 
			
		||||
 | 
			
		||||
        auto tokens = parseFields(fields);
 | 
			
		||||
 | 
			
		||||
        CobraBot bot;
 | 
			
		||||
        bot.setOnBotMessageCallback(
 | 
			
		||||
            [&statsdClient, &tokens, &gauge, &timer, &verbose](const Json::Value& msg,
 | 
			
		||||
            [&statsdClient, &tokens, &gauge, &timer](const Json::Value& msg,
 | 
			
		||||
                                                     const std::string& /*position*/,
 | 
			
		||||
                                                     const bool verbose,
 | 
			
		||||
                                                     std::atomic<bool>& /*throttled*/,
 | 
			
		||||
                                                     std::atomic<bool>& fatalCobraError,
 | 
			
		||||
                                                     std::atomic<uint64_t>& sentCount) -> void {
 | 
			
		||||
                                                     std::atomic<bool>& fatalCobraError) -> bool {
 | 
			
		||||
                std::string id;
 | 
			
		||||
                for (auto&& attr : tokens)
 | 
			
		||||
                {
 | 
			
		||||
@@ -111,7 +122,7 @@ namespace ix
 | 
			
		||||
                    {
 | 
			
		||||
                        CoreLogger::error("Gauge " + gauge + " is not a numeric type");
 | 
			
		||||
                        fatalCobraError = true;
 | 
			
		||||
                        return;
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (verbose)
 | 
			
		||||
@@ -129,9 +140,19 @@ namespace ix
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                sentCount++;
 | 
			
		||||
                return true;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        return bot.run(config);
 | 
			
		||||
        bool useQueue = true;
 | 
			
		||||
 | 
			
		||||
        return bot.run(config,
 | 
			
		||||
                       channel,
 | 
			
		||||
                       filter,
 | 
			
		||||
                       position,
 | 
			
		||||
                       verbose,
 | 
			
		||||
                       maxQueueSize,
 | 
			
		||||
                       useQueue,
 | 
			
		||||
                       enableHeartbeat,
 | 
			
		||||
                       runtime);
 | 
			
		||||
    }
 | 
			
		||||
} // namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -7,16 +7,22 @@
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <ixbots/IXStatsdClient.h>
 | 
			
		||||
#include "IXCobraBotConfig.h"
 | 
			
		||||
#include <ixcobra/IXCobraConfig.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    int64_t cobra_to_statsd_bot(const ix::CobraBotConfig& config,
 | 
			
		||||
    int64_t cobra_to_statsd_bot(const ix::CobraConfig& config,
 | 
			
		||||
                                const std::string& channel,
 | 
			
		||||
                                const std::string& filter,
 | 
			
		||||
                                const std::string& position,
 | 
			
		||||
                                StatsdClient& statsdClient,
 | 
			
		||||
                                const std::string& fields,
 | 
			
		||||
                                const std::string& gauge,
 | 
			
		||||
                                const std::string& timer,
 | 
			
		||||
                                bool verbose);
 | 
			
		||||
                                bool verbose,
 | 
			
		||||
                                size_t maxQueueSize,
 | 
			
		||||
                                bool enableHeartbeat,
 | 
			
		||||
                                int runtime);
 | 
			
		||||
} // namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
#include "IXCobraToStdoutBot.h"
 | 
			
		||||
 | 
			
		||||
#include "IXCobraBot.h"
 | 
			
		||||
#include "IXQueueManager.h"
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
@@ -63,9 +64,16 @@ namespace ix
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int64_t cobra_to_stdout_bot(const ix::CobraBotConfig& config,
 | 
			
		||||
    int64_t cobra_to_stdout_bot(const CobraConfig& config,
 | 
			
		||||
                                const std::string& channel,
 | 
			
		||||
                                const std::string& filter,
 | 
			
		||||
                                const std::string& position,
 | 
			
		||||
                                bool fluentd,
 | 
			
		||||
                                bool quiet)
 | 
			
		||||
                                bool quiet,
 | 
			
		||||
                                bool verbose,
 | 
			
		||||
                                size_t maxQueueSize,
 | 
			
		||||
                                bool enableHeartbeat,
 | 
			
		||||
                                int runtime)
 | 
			
		||||
    {
 | 
			
		||||
        CobraBot bot;
 | 
			
		||||
        auto jsonWriter = makeStreamWriter();
 | 
			
		||||
@@ -73,16 +81,27 @@ namespace ix
 | 
			
		||||
        bot.setOnBotMessageCallback(
 | 
			
		||||
            [&fluentd, &quiet, &jsonWriter](const Json::Value& msg,
 | 
			
		||||
                                            const std::string& position,
 | 
			
		||||
                                            const bool /*verbose*/,
 | 
			
		||||
                                            std::atomic<bool>& /*throttled*/,
 | 
			
		||||
                                            std::atomic<bool>& /*fatalCobraError*/,
 | 
			
		||||
                                            std::atomic<uint64_t>& sentCount) -> void {
 | 
			
		||||
                                            std::atomic<bool> &
 | 
			
		||||
                                            /*fatalCobraError*/) -> bool {
 | 
			
		||||
                if (!quiet)
 | 
			
		||||
                {
 | 
			
		||||
                    writeToStdout(fluentd, jsonWriter, msg, position);
 | 
			
		||||
                }
 | 
			
		||||
                sentCount++;
 | 
			
		||||
                return true;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        return bot.run(config);
 | 
			
		||||
        bool useQueue = false;
 | 
			
		||||
 | 
			
		||||
        return bot.run(config,
 | 
			
		||||
                       channel,
 | 
			
		||||
                       filter,
 | 
			
		||||
                       position,
 | 
			
		||||
                       verbose,
 | 
			
		||||
                       maxQueueSize,
 | 
			
		||||
                       useQueue,
 | 
			
		||||
                       enableHeartbeat,
 | 
			
		||||
                       runtime);
 | 
			
		||||
    }
 | 
			
		||||
} // namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -6,13 +6,20 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include "IXCobraBotConfig.h"
 | 
			
		||||
#include <ixcobra/IXCobraConfig.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    int64_t cobra_to_stdout_bot(const ix::CobraBotConfig& config,
 | 
			
		||||
    int64_t cobra_to_stdout_bot(const ix::CobraConfig& config,
 | 
			
		||||
                                const std::string& channel,
 | 
			
		||||
                                const std::string& filter,
 | 
			
		||||
                                const std::string& position,
 | 
			
		||||
                                bool fluentd,
 | 
			
		||||
                                bool quiet);
 | 
			
		||||
                                bool quiet,
 | 
			
		||||
                                bool verbose,
 | 
			
		||||
                                size_t maxQueueSize,
 | 
			
		||||
                                bool enableHeartbeat,
 | 
			
		||||
                                int runtime);
 | 
			
		||||
} // namespace ix
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										67
									
								
								ixbots/ixbots/IXQueueManager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								ixbots/ixbots/IXQueueManager.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  IXQueueManager.cpp
 | 
			
		||||
 *  Author: Benjamin Sergeant
 | 
			
		||||
 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "IXQueueManager.h"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    std::pair<Json::Value, std::string> QueueManager::pop()
 | 
			
		||||
    {
 | 
			
		||||
        std::unique_lock<std::mutex> lock(_mutex);
 | 
			
		||||
 | 
			
		||||
        if (_queues.empty())
 | 
			
		||||
        {
 | 
			
		||||
            Json::Value val;
 | 
			
		||||
            return std::make_pair(val, std::string());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        std::vector<std::string> games;
 | 
			
		||||
        for (auto it : _queues)
 | 
			
		||||
        {
 | 
			
		||||
            games.push_back(it.first);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        std::random_shuffle(games.begin(), games.end());
 | 
			
		||||
        std::string game = games[0];
 | 
			
		||||
 | 
			
		||||
        auto duration = std::chrono::seconds(1);
 | 
			
		||||
        _condition.wait_for(lock, duration);
 | 
			
		||||
 | 
			
		||||
        if (_queues[game].empty())
 | 
			
		||||
        {
 | 
			
		||||
            Json::Value val;
 | 
			
		||||
            return std::make_pair(val, std::string());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto msg = _queues[game].front();
 | 
			
		||||
        _queues[game].pop();
 | 
			
		||||
        return msg;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void QueueManager::add(const Json::Value& msg, const std::string& position)
 | 
			
		||||
    {
 | 
			
		||||
        std::unique_lock<std::mutex> lock(_mutex);
 | 
			
		||||
 | 
			
		||||
        std::string game;
 | 
			
		||||
        if (msg.isMember("device") && msg["device"].isMember("game"))
 | 
			
		||||
        {
 | 
			
		||||
            game = msg["device"]["game"].asString();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (game.empty()) return;
 | 
			
		||||
 | 
			
		||||
        // if the sending is not fast enough there is no point
 | 
			
		||||
        // in queuing too many events.
 | 
			
		||||
        if (_queues[game].size() < _maxQueueSize)
 | 
			
		||||
        {
 | 
			
		||||
            _queues[game].push(std::make_pair(msg, position));
 | 
			
		||||
            _condition.notify_one();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
} // namespace ix
 | 
			
		||||
							
								
								
									
										35
									
								
								ixbots/ixbots/IXQueueManager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								ixbots/ixbots/IXQueueManager.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  IXQueueManager.h
 | 
			
		||||
 *  Author: Benjamin Sergeant
 | 
			
		||||
 *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <condition_variable>
 | 
			
		||||
#include <json/json.h>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <queue>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
{
 | 
			
		||||
    class QueueManager
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        QueueManager(size_t maxQueueSize)
 | 
			
		||||
            : _maxQueueSize(maxQueueSize)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        std::pair<Json::Value, std::string> pop();
 | 
			
		||||
        void add(const Json::Value& msg, const std::string& position);
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        std::map<std::string, std::queue<std::pair<Json::Value, std::string>>> _queues;
 | 
			
		||||
        std::mutex _mutex;
 | 
			
		||||
        std::condition_variable _condition;
 | 
			
		||||
        size_t _maxQueueSize;
 | 
			
		||||
    };
 | 
			
		||||
} // namespace ix
 | 
			
		||||
@@ -226,23 +226,20 @@ namespace ix
 | 
			
		||||
        return _jsonWriter.write(payload);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void SentryClient::send(
 | 
			
		||||
        const Json::Value& msg,
 | 
			
		||||
        bool verbose,
 | 
			
		||||
        const OnResponseCallback& onResponseCallback)
 | 
			
		||||
    std::pair<HttpResponsePtr, std::string> SentryClient::send(const Json::Value& msg, bool verbose)
 | 
			
		||||
    {
 | 
			
		||||
        auto args = _httpClient->createRequest();
 | 
			
		||||
        args->url = _url;
 | 
			
		||||
        args->verb = HttpClient::kPost;
 | 
			
		||||
        args->extraHeaders["X-Sentry-Auth"] = SentryClient::computeAuthHeader();
 | 
			
		||||
        args->connectTimeout = 60;
 | 
			
		||||
        args->transferTimeout = 5 * 60;
 | 
			
		||||
        args->followRedirects = true;
 | 
			
		||||
        args->verbose = verbose;
 | 
			
		||||
        args->logger = [](const std::string& msg) { CoreLogger::log(msg.c_str()); };
 | 
			
		||||
        args->body = computePayload(msg);
 | 
			
		||||
 | 
			
		||||
        _httpClient->performRequest(args, onResponseCallback);
 | 
			
		||||
        std::string body = computePayload(msg);
 | 
			
		||||
        HttpResponsePtr response = _httpClient->post(_url, body, args);
 | 
			
		||||
 | 
			
		||||
        return std::make_pair(response, body);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // https://sentry.io/api/12345/minidump?sentry_key=abcdefgh");
 | 
			
		||||
 
 | 
			
		||||
@@ -21,9 +21,12 @@ namespace ix
 | 
			
		||||
        SentryClient(const std::string& dsn);
 | 
			
		||||
        ~SentryClient() = default;
 | 
			
		||||
 | 
			
		||||
        void send(const Json::Value& msg,
 | 
			
		||||
                  bool verbose,
 | 
			
		||||
                  const OnResponseCallback& onResponseCallback);
 | 
			
		||||
        std::pair<HttpResponsePtr, std::string> send(const Json::Value& msg, bool verbose);
 | 
			
		||||
 | 
			
		||||
        Json::Value parseLuaStackTrace(const std::string& stack);
 | 
			
		||||
 | 
			
		||||
        // Mostly for testing
 | 
			
		||||
        void setTLSOptions(const SocketTLSOptions& tlsOptions);
 | 
			
		||||
 | 
			
		||||
        void uploadMinidump(const std::string& sentryMetadata,
 | 
			
		||||
                            const std::string& minidumpBytes,
 | 
			
		||||
@@ -36,12 +39,6 @@ namespace ix
 | 
			
		||||
                           bool verbose,
 | 
			
		||||
                           const OnResponseCallback& onResponseCallback);
 | 
			
		||||
 | 
			
		||||
        Json::Value parseLuaStackTrace(const std::string& stack);
 | 
			
		||||
 | 
			
		||||
        // Mostly for testing
 | 
			
		||||
        void setTLSOptions(const SocketTLSOptions& tlsOptions);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        int64_t getTimestamp();
 | 
			
		||||
        std::string computeAuthHeader();
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,6 @@
 | 
			
		||||
 | 
			
		||||
#include "IXCancellationRequest.h"
 | 
			
		||||
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
 | 
			
		||||
namespace ix
 | 
			
		||||
@@ -14,8 +13,6 @@ namespace ix
 | 
			
		||||
    CancellationRequest makeCancellationRequestWithTimeout(
 | 
			
		||||
        int secs, std::atomic<bool>& requestInitCancellation)
 | 
			
		||||
    {
 | 
			
		||||
        assert(secs > 0);
 | 
			
		||||
 | 
			
		||||
        auto start = std::chrono::system_clock::now();
 | 
			
		||||
        auto timeout = std::chrono::seconds(secs);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,19 +4,6 @@
 | 
			
		||||
 *  Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// On Windows Universal Platform (uwp), gai_strerror defaults behavior is to returns wchar_t
 | 
			
		||||
// which is different from all other platforms. We want the non unicode version.
 | 
			
		||||
// See https://github.com/microsoft/vcpkg/pull/11030
 | 
			
		||||
// We could do this in IXNetSystem.cpp but so far we are only using gai_strerror in here.
 | 
			
		||||
//
 | 
			
		||||
#ifdef _UNICODE
 | 
			
		||||
#undef _UNICODE
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef UNICODE
 | 
			
		||||
#undef UNICODE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "IXDNSLookup.h"
 | 
			
		||||
 | 
			
		||||
#include "IXNetSystem.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -25,12 +25,10 @@ namespace ix
 | 
			
		||||
    const std::string HttpClient::kHead = "HEAD";
 | 
			
		||||
    const std::string HttpClient::kDel = "DEL";
 | 
			
		||||
    const std::string HttpClient::kPut = "PUT";
 | 
			
		||||
    const std::string HttpClient::kPatch = "PATCH";
 | 
			
		||||
 | 
			
		||||
    HttpClient::HttpClient(bool async)
 | 
			
		||||
        : _async(async)
 | 
			
		||||
        , _stop(false)
 | 
			
		||||
        , _forceBody(false)
 | 
			
		||||
    {
 | 
			
		||||
        if (!_async) return;
 | 
			
		||||
 | 
			
		||||
@@ -51,11 +49,6 @@ namespace ix
 | 
			
		||||
        _tlsOptions = tlsOptions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void HttpClient::setForceBody(bool value)
 | 
			
		||||
    {
 | 
			
		||||
        _forceBody = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    HttpRequestArgsPtr HttpClient::createRequest(const std::string& url, const std::string& verb)
 | 
			
		||||
    {
 | 
			
		||||
        auto request = std::make_shared<HttpRequestArgs>();
 | 
			
		||||
@@ -199,7 +192,7 @@ namespace ix
 | 
			
		||||
            ss << "User-Agent: " << userAgent() << "\r\n";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (verb == kPost || verb == kPut || verb == kPatch || _forceBody)
 | 
			
		||||
        if (verb == kPost || verb == kPut)
 | 
			
		||||
        {
 | 
			
		||||
            ss << "Content-Length: " << body.size() << "\r\n";
 | 
			
		||||
 | 
			
		||||
@@ -227,10 +220,11 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
        std::string req(ss.str());
 | 
			
		||||
        std::string errMsg;
 | 
			
		||||
        std::atomic<bool> requestInitCancellation(false);
 | 
			
		||||
 | 
			
		||||
        // Make a cancellation object dealing with connection timeout
 | 
			
		||||
        auto isCancellationRequested =
 | 
			
		||||
            makeCancellationRequestWithTimeout(args->connectTimeout, _stop);
 | 
			
		||||
            makeCancellationRequestWithTimeout(args->connectTimeout, requestInitCancellation);
 | 
			
		||||
 | 
			
		||||
        bool success = _socket->connect(host, port, errMsg, isCancellationRequested);
 | 
			
		||||
        if (!success)
 | 
			
		||||
@@ -248,7 +242,8 @@ namespace ix
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Make a new cancellation object dealing with transfer timeout
 | 
			
		||||
        isCancellationRequested = makeCancellationRequestWithTimeout(args->transferTimeout, _stop);
 | 
			
		||||
        isCancellationRequested =
 | 
			
		||||
            makeCancellationRequestWithTimeout(args->transferTimeout, requestInitCancellation);
 | 
			
		||||
 | 
			
		||||
        if (args->verbose)
 | 
			
		||||
        {
 | 
			
		||||
@@ -567,20 +562,6 @@ namespace ix
 | 
			
		||||
        return request(url, kPut, body, args);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    HttpResponsePtr HttpClient::patch(const std::string& url,
 | 
			
		||||
                                      const HttpParameters& httpParameters,
 | 
			
		||||
                                      HttpRequestArgsPtr args)
 | 
			
		||||
    {
 | 
			
		||||
        return request(url, kPatch, serializeHttpParameters(httpParameters), args);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    HttpResponsePtr HttpClient::patch(const std::string& url,
 | 
			
		||||
                                      const std::string& body,
 | 
			
		||||
                                      const HttpRequestArgsPtr args)
 | 
			
		||||
    {
 | 
			
		||||
        return request(url, kPatch, body, args);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string HttpClient::urlEncode(const std::string& value)
 | 
			
		||||
    {
 | 
			
		||||
        std::ostringstream escaped;
 | 
			
		||||
 
 | 
			
		||||
@@ -46,19 +46,12 @@ namespace ix
 | 
			
		||||
                            const std::string& body,
 | 
			
		||||
                            HttpRequestArgsPtr args);
 | 
			
		||||
 | 
			
		||||
        HttpResponsePtr patch(const std::string& url,
 | 
			
		||||
                              const HttpParameters& httpParameters,
 | 
			
		||||
                              HttpRequestArgsPtr args);
 | 
			
		||||
        HttpResponsePtr patch(const std::string& url,
 | 
			
		||||
                              const std::string& body,
 | 
			
		||||
                              HttpRequestArgsPtr args);
 | 
			
		||||
 | 
			
		||||
        HttpResponsePtr request(const std::string& url,
 | 
			
		||||
                                const std::string& verb,
 | 
			
		||||
                                const std::string& body,
 | 
			
		||||
                                HttpRequestArgsPtr args,
 | 
			
		||||
                                int redirects = 0);
 | 
			
		||||
        void setForceBody(bool value);
 | 
			
		||||
 | 
			
		||||
        // Async API
 | 
			
		||||
        HttpRequestArgsPtr createRequest(const std::string& url = std::string(),
 | 
			
		||||
                                         const std::string& verb = HttpClient::kGet);
 | 
			
		||||
@@ -85,7 +78,6 @@ namespace ix
 | 
			
		||||
        const static std::string kHead;
 | 
			
		||||
        const static std::string kDel;
 | 
			
		||||
        const static std::string kPut;
 | 
			
		||||
        const static std::string kPatch;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        void log(const std::string& msg, HttpRequestArgsPtr args);
 | 
			
		||||
@@ -94,6 +86,7 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
        // Async API background thread runner
 | 
			
		||||
        void run();
 | 
			
		||||
 | 
			
		||||
        // Async API
 | 
			
		||||
        bool _async;
 | 
			
		||||
        std::queue<std::pair<HttpRequestArgsPtr, OnResponseCallback>> _queue;
 | 
			
		||||
@@ -106,7 +99,5 @@ namespace ix
 | 
			
		||||
        std::mutex _mutex; // to protect accessing the _socket (only one socket per client)
 | 
			
		||||
 | 
			
		||||
        SocketTLSOptions _tlsOptions;
 | 
			
		||||
 | 
			
		||||
        bool _forceBody;
 | 
			
		||||
    };
 | 
			
		||||
} // namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,6 @@ typedef unsigned long int nfds_t;
 | 
			
		||||
#else
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <netdb.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <netinet/ip.h>
 | 
			
		||||
 
 | 
			
		||||
@@ -43,55 +43,6 @@ namespace ix
 | 
			
		||||
        mbedtls_pk_init(&_pkey);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool SocketMbedTLS::loadSystemCertificates(std::string& errorMsg)
 | 
			
		||||
    {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
        DWORD flags = CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG |
 | 
			
		||||
                      CERT_SYSTEM_STORE_CURRENT_USER;
 | 
			
		||||
        HCERTSTORE systemStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, flags, L"Root");
 | 
			
		||||
 | 
			
		||||
        if (!systemStore)
 | 
			
		||||
        {
 | 
			
		||||
            errorMsg = "CertOpenStore failed with ";
 | 
			
		||||
            errorMsg += std::to_string(GetLastError());
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        PCCERT_CONTEXT certificateIterator = NULL;
 | 
			
		||||
 | 
			
		||||
        int certificateCount = 0;
 | 
			
		||||
        while (certificateIterator = CertEnumCertificatesInStore(systemStore, certificateIterator))
 | 
			
		||||
        {
 | 
			
		||||
            if (certificateIterator->dwCertEncodingType & X509_ASN_ENCODING)
 | 
			
		||||
            {
 | 
			
		||||
                int ret = mbedtls_x509_crt_parse(&_cacert,
 | 
			
		||||
                                                 certificateIterator->pbCertEncoded,
 | 
			
		||||
                                                 certificateIterator->cbCertEncoded);
 | 
			
		||||
                if (ret == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    ++certificateCount;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        CertFreeCertificateContext(certificateIterator);
 | 
			
		||||
        CertCloseStore(systemStore, 0);
 | 
			
		||||
 | 
			
		||||
        if (certificateCount == 0)
 | 
			
		||||
        {
 | 
			
		||||
            errorMsg = "No certificates found";
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
#else
 | 
			
		||||
        // On macOS we can query the system cert location from the keychain
 | 
			
		||||
        // On Linux we could try to fetch some local files based on the distribution
 | 
			
		||||
        // On Android we could use JNI to get to the system certs
 | 
			
		||||
        return false;
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool SocketMbedTLS::init(const std::string& host, bool isClient, std::string& errMsg)
 | 
			
		||||
    {
 | 
			
		||||
        initMBedTLS();
 | 
			
		||||
@@ -145,15 +96,13 @@ namespace ix
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // FIXME: should we call mbedtls_ssl_conf_verify ?
 | 
			
		||||
            mbedtls_ssl_conf_authmode(&_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
 | 
			
		||||
 | 
			
		||||
            // FIXME: should we call mbedtls_ssl_conf_verify ?
 | 
			
		||||
 | 
			
		||||
            if (_tlsOptions.isUsingSystemDefaults())
 | 
			
		||||
            {
 | 
			
		||||
                if (!loadSystemCertificates(errMsg))
 | 
			
		||||
                {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                ; // FIXME
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,6 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
        bool init(const std::string& host, bool isClient, std::string& errMsg);
 | 
			
		||||
        void initMBedTLS();
 | 
			
		||||
        bool loadSystemCertificates(std::string& errMsg);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
} // namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -85,8 +85,6 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
    std::atomic<bool> SocketOpenSSL::_openSSLInitializationSuccessful(false);
 | 
			
		||||
    std::once_flag SocketOpenSSL::_openSSLInitFlag;
 | 
			
		||||
    std::unique_ptr<std::mutex[]> SocketOpenSSL::_openSSLMutexes =
 | 
			
		||||
        std::make_unique<std::mutex[]>(CRYPTO_num_locks());
 | 
			
		||||
 | 
			
		||||
    SocketOpenSSL::SocketOpenSSL(const SocketTLSOptions& tlsOptions, int fd)
 | 
			
		||||
        : Socket(fd)
 | 
			
		||||
@@ -108,11 +106,6 @@ namespace ix
 | 
			
		||||
        if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, nullptr)) return;
 | 
			
		||||
#else
 | 
			
		||||
        (void) OPENSSL_config(nullptr);
 | 
			
		||||
 | 
			
		||||
        if (CRYPTO_get_locking_callback() == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            CRYPTO_set_locking_callback(SocketOpenSSL::openSSLLockingCallback);
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        (void) OpenSSL_add_ssl_algorithms();
 | 
			
		||||
@@ -121,21 +114,6 @@ namespace ix
 | 
			
		||||
        _openSSLInitializationSuccessful = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void SocketOpenSSL::openSSLLockingCallback(int mode,
 | 
			
		||||
                                               int type,
 | 
			
		||||
                                               const char* /*file*/,
 | 
			
		||||
                                               int /*line*/)
 | 
			
		||||
    {
 | 
			
		||||
        if (mode & CRYPTO_LOCK)
 | 
			
		||||
        {
 | 
			
		||||
            _openSSLMutexes[type].lock();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            _openSSLMutexes[type].unlock();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string SocketOpenSSL::getSSLError(int ret)
 | 
			
		||||
    {
 | 
			
		||||
        unsigned long e;
 | 
			
		||||
 
 | 
			
		||||
@@ -49,9 +49,6 @@ namespace ix
 | 
			
		||||
        bool handleTLSOptions(std::string& errMsg);
 | 
			
		||||
        bool openSSLServerHandshake(std::string& errMsg);
 | 
			
		||||
 | 
			
		||||
        // Required for OpenSSL < 1.1
 | 
			
		||||
        static void openSSLLockingCallback(int mode, int type, const char* /*file*/, int /*line*/);
 | 
			
		||||
 | 
			
		||||
        SSL* _ssl_connection;
 | 
			
		||||
        SSL_CTX* _ssl_context;
 | 
			
		||||
        const SSL_METHOD* _ssl_method;
 | 
			
		||||
@@ -61,7 +58,6 @@ namespace ix
 | 
			
		||||
 | 
			
		||||
        static std::once_flag _openSSLInitFlag;
 | 
			
		||||
        static std::atomic<bool> _openSSLInitializationSuccessful;
 | 
			
		||||
        static std::unique_ptr<std::mutex[]> _openSSLMutexes;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
} // namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -44,18 +44,6 @@ namespace ix
 | 
			
		||||
        return err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool UdpSocket::isWaitNeeded()
 | 
			
		||||
    {
 | 
			
		||||
        int err = getErrno();
 | 
			
		||||
 | 
			
		||||
        if (err == EWOULDBLOCK || err == EAGAIN || err == EINPROGRESS)
 | 
			
		||||
        {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void UdpSocket::closeSocket(int fd)
 | 
			
		||||
    {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
@@ -74,13 +62,6 @@ namespace ix
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
        unsigned long nonblocking = 1;
 | 
			
		||||
        ioctlsocket(_sockfd, FIONBIO, &nonblocking);
 | 
			
		||||
#else
 | 
			
		||||
        fcntl(_sockfd, F_SETFL, O_NONBLOCK); // make socket non blocking
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        memset(&_server, 0, sizeof(_server));
 | 
			
		||||
        _server.sin_family = AF_INET;
 | 
			
		||||
        _server.sin_port = htons(port);
 | 
			
		||||
@@ -112,15 +93,4 @@ namespace ix
 | 
			
		||||
        return (ssize_t)::sendto(
 | 
			
		||||
            _sockfd, buffer.data(), buffer.size(), 0, (struct sockaddr*) &_server, sizeof(_server));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ssize_t UdpSocket::recvfrom(char* buffer, size_t length)
 | 
			
		||||
    {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
        int addressLen = (int) sizeof(_server);
 | 
			
		||||
#else
 | 
			
		||||
        socklen_t addressLen = (socklen_t) sizeof(_server);
 | 
			
		||||
#endif
 | 
			
		||||
        return (ssize_t)::recvfrom(
 | 
			
		||||
            _sockfd, buffer, length, 0, (struct sockaddr*) &_server, &addressLen);
 | 
			
		||||
    }
 | 
			
		||||
} // namespace ix
 | 
			
		||||
 
 | 
			
		||||
@@ -28,12 +28,9 @@ namespace ix
 | 
			
		||||
        // Virtual methods
 | 
			
		||||
        bool init(const std::string& host, int port, std::string& errMsg);
 | 
			
		||||
        ssize_t sendto(const std::string& buffer);
 | 
			
		||||
        ssize_t recvfrom(char* buffer, size_t length);
 | 
			
		||||
 | 
			
		||||
        void close();
 | 
			
		||||
 | 
			
		||||
        static int getErrno();
 | 
			
		||||
        static bool isWaitNeeded();
 | 
			
		||||
        static void closeSocket(int fd);
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
 
 | 
			
		||||
@@ -6,4 +6,4 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#define IX_WEBSOCKET_VERSION "9.6.2"
 | 
			
		||||
#define IX_WEBSOCKET_VERSION "9.5.2"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								makefile
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								makefile
									
									
									
									
									
								
							@@ -20,13 +20,13 @@ install: brew
 | 
			
		||||
# Release, Debug, MinSizeRel, RelWithDebInfo are the build types
 | 
			
		||||
#
 | 
			
		||||
brew:
 | 
			
		||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; ninja install)
 | 
			
		||||
	mkdir -p build && (cd build ; cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; make -j 4 install)
 | 
			
		||||
 | 
			
		||||
# Docker default target. We've add problem with OpenSSL and TLS 1.3 (on the
 | 
			
		||||
# server side ?) and I can't work-around it easily, so we're using mbedtls on
 | 
			
		||||
# Linux for the SSL backend, which works great.
 | 
			
		||||
ws_mbedtls_install:
 | 
			
		||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 -DUSE_MBED_TLS=1 .. ; ninja install)
 | 
			
		||||
	mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 -DUSE_MBED_TLS=1 .. ; make -j 4 install)
 | 
			
		||||
 | 
			
		||||
ws:
 | 
			
		||||
	mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 .. ; make -j 4)
 | 
			
		||||
@@ -103,10 +103,6 @@ test_server:
 | 
			
		||||
# env TEST=Websocket_chat make test
 | 
			
		||||
# env TEST=heartbeat make test
 | 
			
		||||
test:
 | 
			
		||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; ninja install)
 | 
			
		||||
	(cd test ; python2.7 run.py -r)
 | 
			
		||||
 | 
			
		||||
test_make:
 | 
			
		||||
	mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; make -j 4)
 | 
			
		||||
	(cd test ; python2.7 run.py -r)
 | 
			
		||||
 | 
			
		||||
@@ -148,7 +144,7 @@ test_tsan_mbedtls:
 | 
			
		||||
	(cd test ; python2.7 run.py -r)
 | 
			
		||||
 | 
			
		||||
build_test_openssl:
 | 
			
		||||
	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_OPEN_SSL=1 -DUSE_TEST=1 .. ; ninja install)
 | 
			
		||||
	mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_OPEN_SSL=1 -DUSE_TEST=1 .. ; make -j 4)
 | 
			
		||||
 | 
			
		||||
test_openssl: build_test_openssl
 | 
			
		||||
	(cd test ; python2.7 run.py -r)
 | 
			
		||||
 
 | 
			
		||||
@@ -138,12 +138,11 @@ TEST_CASE("Cobra_to_sentry_bot", "[cobra_bots]")
 | 
			
		||||
 | 
			
		||||
        std::thread publisherThread(runPublisher, config, channel);
 | 
			
		||||
 | 
			
		||||
        ix::CobraBotConfig cobraBotConfig;
 | 
			
		||||
        cobraBotConfig.cobraConfig = config;
 | 
			
		||||
        cobraBotConfig.channel = channel;
 | 
			
		||||
        cobraBotConfig.runtime = 3; // Only run the bot for 3 seconds
 | 
			
		||||
        cobraBotConfig.enableHeartbeat = false;
 | 
			
		||||
        std::string filter;
 | 
			
		||||
        std::string position("$");
 | 
			
		||||
        bool verbose = true;
 | 
			
		||||
        size_t maxQueueSize = 10;
 | 
			
		||||
        bool enableHeartbeat = false;
 | 
			
		||||
 | 
			
		||||
        // FIXME: try to get this working with https instead of http
 | 
			
		||||
        //        to regress the TLS 1.3 OpenSSL bug
 | 
			
		||||
@@ -158,7 +157,18 @@ TEST_CASE("Cobra_to_sentry_bot", "[cobra_bots]")
 | 
			
		||||
        SentryClient sentryClient(dsn);
 | 
			
		||||
        sentryClient.setTLSOptions(tlsOptionsClient);
 | 
			
		||||
 | 
			
		||||
        int64_t sentCount = cobra_to_sentry_bot(cobraBotConfig, sentryClient, verbose);
 | 
			
		||||
        // Only run the bot for 3 seconds
 | 
			
		||||
        int runtime = 3;
 | 
			
		||||
 | 
			
		||||
        int64_t sentCount = cobra_to_sentry_bot(config,
 | 
			
		||||
                                                channel,
 | 
			
		||||
                                                filter,
 | 
			
		||||
                                                position,
 | 
			
		||||
                                                sentryClient,
 | 
			
		||||
                                                verbose,
 | 
			
		||||
                                                maxQueueSize,
 | 
			
		||||
                                                enableHeartbeat,
 | 
			
		||||
                                                runtime);
 | 
			
		||||
        //
 | 
			
		||||
        // We want at least 2 messages to be sent
 | 
			
		||||
        //
 | 
			
		||||
 
 | 
			
		||||
@@ -87,11 +87,14 @@ TEST_CASE("Cobra_to_statsd_bot", "[cobra_bots]")
 | 
			
		||||
 | 
			
		||||
        std::thread publisherThread(runPublisher, config, channel);
 | 
			
		||||
 | 
			
		||||
        ix::CobraBotConfig cobraBotConfig;
 | 
			
		||||
        cobraBotConfig.cobraConfig = config;
 | 
			
		||||
        cobraBotConfig.channel = channel;
 | 
			
		||||
        cobraBotConfig.runtime = 3; // Only run the bot for 3 seconds
 | 
			
		||||
        cobraBotConfig.enableHeartbeat = false;
 | 
			
		||||
        std::string filter;
 | 
			
		||||
        std::string position("$");
 | 
			
		||||
        bool verbose = true;
 | 
			
		||||
        size_t maxQueueSize = 10;
 | 
			
		||||
        bool enableHeartbeat = false;
 | 
			
		||||
 | 
			
		||||
        // Only run the bot for 3 seconds
 | 
			
		||||
        int runtime = 3;
 | 
			
		||||
 | 
			
		||||
        std::string hostname("127.0.0.1");
 | 
			
		||||
        // std::string hostname("www.google.com");
 | 
			
		||||
@@ -110,10 +113,19 @@ TEST_CASE("Cobra_to_statsd_bot", "[cobra_bots]")
 | 
			
		||||
        std::string fields("device.game\ndevice.os_name");
 | 
			
		||||
        std::string gauge;
 | 
			
		||||
        std::string timer;
 | 
			
		||||
        bool verbose = true;
 | 
			
		||||
 | 
			
		||||
        int64_t sentCount =
 | 
			
		||||
            ix::cobra_to_statsd_bot(cobraBotConfig, statsdClient, fields, gauge, timer, verbose);
 | 
			
		||||
        int64_t sentCount = ix::cobra_to_statsd_bot(config,
 | 
			
		||||
                                                    channel,
 | 
			
		||||
                                                    filter,
 | 
			
		||||
                                                    position,
 | 
			
		||||
                                                    statsdClient,
 | 
			
		||||
                                                    fields,
 | 
			
		||||
                                                    gauge,
 | 
			
		||||
                                                    timer,
 | 
			
		||||
                                                    verbose,
 | 
			
		||||
                                                    maxQueueSize,
 | 
			
		||||
                                                    enableHeartbeat,
 | 
			
		||||
                                                    runtime);
 | 
			
		||||
        //
 | 
			
		||||
        // We want at least 2 messages to be sent
 | 
			
		||||
        //
 | 
			
		||||
 
 | 
			
		||||
@@ -85,17 +85,29 @@ TEST_CASE("Cobra_to_stdout_bot", "[cobra_bots]")
 | 
			
		||||
 | 
			
		||||
        std::thread publisherThread(runPublisher, config, channel);
 | 
			
		||||
 | 
			
		||||
        ix::CobraBotConfig cobraBotConfig;
 | 
			
		||||
        cobraBotConfig.cobraConfig = config;
 | 
			
		||||
        cobraBotConfig.channel = channel;
 | 
			
		||||
        cobraBotConfig.runtime = 3; // Only run the bot for 3 seconds
 | 
			
		||||
        cobraBotConfig.enableHeartbeat = false;
 | 
			
		||||
        std::string filter;
 | 
			
		||||
        std::string position("$");
 | 
			
		||||
        bool verbose = true;
 | 
			
		||||
        bool quiet = false;
 | 
			
		||||
        size_t maxQueueSize = 10;
 | 
			
		||||
        bool enableHeartbeat = false;
 | 
			
		||||
 | 
			
		||||
        // Only run the bot for 3 seconds
 | 
			
		||||
        int runtime = 3;
 | 
			
		||||
 | 
			
		||||
        // We could try to capture the output ... not sure how.
 | 
			
		||||
        bool fluentd = true;
 | 
			
		||||
 | 
			
		||||
        int64_t sentCount = ix::cobra_to_stdout_bot(cobraBotConfig, fluentd, quiet);
 | 
			
		||||
        int64_t sentCount = ix::cobra_to_stdout_bot(config,
 | 
			
		||||
                                                    channel,
 | 
			
		||||
                                                    filter,
 | 
			
		||||
                                                    position,
 | 
			
		||||
                                                    fluentd,
 | 
			
		||||
                                                    quiet,
 | 
			
		||||
                                                    verbose,
 | 
			
		||||
                                                    maxQueueSize,
 | 
			
		||||
                                                    enableHeartbeat,
 | 
			
		||||
                                                    runtime);
 | 
			
		||||
        //
 | 
			
		||||
        // We want at least 2 messages to be sent
 | 
			
		||||
        //
 | 
			
		||||
 
 | 
			
		||||
@@ -4,14 +4,6 @@
 | 
			
		||||
 *  Copyright (c) 2019 Machine Zone. All rights reserved.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// Using inet_addr will trigger an error on uwp without this
 | 
			
		||||
// FIXME: use a different api
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
 | 
			
		||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "IXGetFreePort.h"
 | 
			
		||||
 | 
			
		||||
#include <ixwebsocket/IXNetSystem.h>
 | 
			
		||||
 
 | 
			
		||||
@@ -93,11 +93,10 @@ TEST_CASE("subprotocol", "[websocket_subprotocol]")
 | 
			
		||||
        webSocket.setUrl(url);
 | 
			
		||||
        webSocket.start();
 | 
			
		||||
 | 
			
		||||
        // Give us 3 seconds to connect
 | 
			
		||||
        int attempts = 0;
 | 
			
		||||
        while (!connected)
 | 
			
		||||
        {
 | 
			
		||||
            REQUIRE(attempts++ < 300);
 | 
			
		||||
            REQUIRE(attempts++ < 10);
 | 
			
		||||
            ix::msleep(10);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										89
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										89
									
								
								ws/ws.cpp
									
									
									
									
									
								
							@@ -19,8 +19,8 @@
 | 
			
		||||
#include <ixwebsocket/IXNetSystem.h>
 | 
			
		||||
#include <ixwebsocket/IXSocket.h>
 | 
			
		||||
#include <ixwebsocket/IXUserAgent.h>
 | 
			
		||||
#include <spdlog/sinks/basic_file_sink.h>
 | 
			
		||||
#include <spdlog/spdlog.h>
 | 
			
		||||
#include <spdlog/sinks/basic_file_sink.h>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
@@ -120,7 +120,6 @@ int main(int argc, char** argv)
 | 
			
		||||
    std::string logfile;
 | 
			
		||||
    ix::SocketTLSOptions tlsOptions;
 | 
			
		||||
    ix::CobraConfig cobraConfig;
 | 
			
		||||
    ix::CobraBotConfig cobraBotConfig;
 | 
			
		||||
    std::string ciphers;
 | 
			
		||||
    std::string redirectUrl;
 | 
			
		||||
    bool headersOnly = false;
 | 
			
		||||
@@ -149,7 +148,9 @@ int main(int argc, char** argv)
 | 
			
		||||
    int delayMs = -1;
 | 
			
		||||
    int count = 1;
 | 
			
		||||
    uint32_t maxWaitBetweenReconnectionRetries;
 | 
			
		||||
    size_t maxQueueSize = 100;
 | 
			
		||||
    int pingIntervalSecs = 30;
 | 
			
		||||
    int runtime = -1; // run indefinitely
 | 
			
		||||
 | 
			
		||||
    auto addTLSOptions = [&tlsOptions, &verifyNone](CLI::App* app) {
 | 
			
		||||
        app->add_option(
 | 
			
		||||
@@ -173,24 +174,6 @@ int main(int argc, char** argv)
 | 
			
		||||
        app->add_option("--rolesecret", cobraConfig.rolesecret, "Role secret")->required();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    auto addCobraBotConfig = [&cobraBotConfig](CLI::App* app) {
 | 
			
		||||
        app->add_option("--appkey", cobraBotConfig.cobraConfig.appkey, "Appkey")->required();
 | 
			
		||||
        app->add_option("--endpoint", cobraBotConfig.cobraConfig.endpoint, "Endpoint")->required();
 | 
			
		||||
        app->add_option("--rolename", cobraBotConfig.cobraConfig.rolename, "Role name")->required();
 | 
			
		||||
        app->add_option("--rolesecret", cobraBotConfig.cobraConfig.rolesecret, "Role secret")
 | 
			
		||||
            ->required();
 | 
			
		||||
        app->add_option("--channel", cobraBotConfig.channel, "Channel")->required();
 | 
			
		||||
        app->add_option("--filter", cobraBotConfig.filter, "Filter");
 | 
			
		||||
        app->add_option("--position", cobraBotConfig.position, "Position");
 | 
			
		||||
        app->add_option("--runtime", cobraBotConfig.runtime, "Runtime");
 | 
			
		||||
        app->add_option("--heartbeat", cobraBotConfig.enableHeartbeat, "Runtime");
 | 
			
		||||
        app->add_option("--heartbeat_timeout", cobraBotConfig.heartBeatTimeout, "Runtime");
 | 
			
		||||
        app->add_flag(
 | 
			
		||||
            "--limit_received_events", cobraBotConfig.limitReceivedEvents, "Max events per minute");
 | 
			
		||||
        app->add_option(
 | 
			
		||||
            "--max_events_per_minute", cobraBotConfig.maxEventsPerMinute, "Max events per minute");
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    app.add_flag("--version", version, "Print ws version");
 | 
			
		||||
    app.add_option("--logfile", logfile, "path where all logs will be redirected");
 | 
			
		||||
 | 
			
		||||
@@ -298,11 +281,15 @@ int main(int argc, char** argv)
 | 
			
		||||
 | 
			
		||||
    CLI::App* cobraSubscribeApp = app.add_subcommand("cobra_subscribe", "Cobra subscriber");
 | 
			
		||||
    cobraSubscribeApp->fallthrough();
 | 
			
		||||
    cobraSubscribeApp->add_option("--channel", channel, "Channel")->required();
 | 
			
		||||
    cobraSubscribeApp->add_option("--pidfile", pidfile, "Pid file");
 | 
			
		||||
    cobraSubscribeApp->add_option("--filter", filter, "Stream SQL Filter");
 | 
			
		||||
    cobraSubscribeApp->add_option("--position", position, "Stream position");
 | 
			
		||||
    cobraSubscribeApp->add_flag("-q", quiet, "Quiet / only display stats");
 | 
			
		||||
    cobraSubscribeApp->add_flag("--fluentd", fluentd, "Write fluentd prefix");
 | 
			
		||||
    cobraSubscribeApp->add_option("--runtime", runtime, "Runtime in seconds");
 | 
			
		||||
    addTLSOptions(cobraSubscribeApp);
 | 
			
		||||
    addCobraBotConfig(cobraSubscribeApp);
 | 
			
		||||
    addCobraConfig(cobraSubscribeApp);
 | 
			
		||||
 | 
			
		||||
    CLI::App* cobraPublish = app.add_subcommand("cobra_publish", "Cobra publisher");
 | 
			
		||||
    cobraPublish->fallthrough();
 | 
			
		||||
@@ -336,18 +323,32 @@ int main(int argc, char** argv)
 | 
			
		||||
        ->join();
 | 
			
		||||
    cobra2statsd->add_option("--timer", timer, "Value to extract, and use as a statsd timer")
 | 
			
		||||
        ->join();
 | 
			
		||||
    cobra2statsd->add_option("channel", channel, "Channel")->required();
 | 
			
		||||
    cobra2statsd->add_flag("-v", verbose, "Verbose");
 | 
			
		||||
    cobra2statsd->add_option("--pidfile", pidfile, "Pid file");
 | 
			
		||||
    cobra2statsd->add_option("--filter", filter, "Stream SQL Filter");
 | 
			
		||||
    cobra2statsd->add_option("--position", position, "Stream position");
 | 
			
		||||
    cobra2statsd->add_option("--queue_size",
 | 
			
		||||
                             maxQueueSize,
 | 
			
		||||
                             "Size of the queue to hold messages before they are sent to Sentry");
 | 
			
		||||
    cobra2statsd->add_option("--runtime", runtime, "Runtime in seconds");
 | 
			
		||||
    addTLSOptions(cobra2statsd);
 | 
			
		||||
    addCobraBotConfig(cobra2statsd);
 | 
			
		||||
    addCobraConfig(cobra2statsd);
 | 
			
		||||
 | 
			
		||||
    CLI::App* cobra2sentry = app.add_subcommand("cobra_to_sentry", "Cobra metrics to sentry");
 | 
			
		||||
    cobra2sentry->fallthrough();
 | 
			
		||||
    cobra2sentry->add_option("--dsn", dsn, "Sentry DSN");
 | 
			
		||||
    cobra2sentry->add_option("--queue_size",
 | 
			
		||||
                             maxQueueSize,
 | 
			
		||||
                             "Size of the queue to hold messages before they are sent to Sentry");
 | 
			
		||||
    cobra2sentry->add_option("channel", channel, "Channel")->required();
 | 
			
		||||
    cobra2sentry->add_flag("-v", verbose, "Verbose");
 | 
			
		||||
    cobra2sentry->add_option("--pidfile", pidfile, "Pid file");
 | 
			
		||||
    cobra2sentry->add_option("--filter", filter, "Stream SQL Filter");
 | 
			
		||||
    cobra2sentry->add_option("--position", position, "Stream position");
 | 
			
		||||
    cobra2sentry->add_option("--runtime", runtime, "Runtime in seconds");
 | 
			
		||||
    addTLSOptions(cobra2sentry);
 | 
			
		||||
    addCobraBotConfig(cobra2sentry);
 | 
			
		||||
    addCobraConfig(cobra2sentry);
 | 
			
		||||
 | 
			
		||||
    CLI::App* cobra2redisApp =
 | 
			
		||||
        app.add_subcommand("cobra_metrics_to_redis", "Cobra metrics to redis");
 | 
			
		||||
@@ -458,10 +459,6 @@ int main(int argc, char** argv)
 | 
			
		||||
    cobraConfig.webSocketPerMessageDeflateOptions = ix::WebSocketPerMessageDeflateOptions(true);
 | 
			
		||||
    cobraConfig.socketTLSOptions = tlsOptions;
 | 
			
		||||
 | 
			
		||||
    cobraBotConfig.cobraConfig.webSocketPerMessageDeflateOptions =
 | 
			
		||||
        ix::WebSocketPerMessageDeflateOptions(true);
 | 
			
		||||
    cobraBotConfig.cobraConfig.socketTLSOptions = tlsOptions;
 | 
			
		||||
 | 
			
		||||
    int ret = 1;
 | 
			
		||||
    if (app.got_subcommand("transfer"))
 | 
			
		||||
    {
 | 
			
		||||
@@ -531,7 +528,17 @@ int main(int argc, char** argv)
 | 
			
		||||
    }
 | 
			
		||||
    else if (app.got_subcommand("cobra_subscribe"))
 | 
			
		||||
    {
 | 
			
		||||
        int64_t sentCount = ix::cobra_to_stdout_bot(cobraBotConfig, fluentd, quiet);
 | 
			
		||||
        bool enableHeartbeat = true;
 | 
			
		||||
        int64_t sentCount = ix::cobra_to_stdout_bot(cobraConfig,
 | 
			
		||||
                                                    channel,
 | 
			
		||||
                                                    filter,
 | 
			
		||||
                                                    position,
 | 
			
		||||
                                                    fluentd,
 | 
			
		||||
                                                    quiet,
 | 
			
		||||
                                                    verbose,
 | 
			
		||||
                                                    maxQueueSize,
 | 
			
		||||
                                                    enableHeartbeat,
 | 
			
		||||
                                                    runtime);
 | 
			
		||||
        ret = (int) sentCount;
 | 
			
		||||
    }
 | 
			
		||||
    else if (app.got_subcommand("cobra_publish"))
 | 
			
		||||
@@ -552,6 +559,7 @@ int main(int argc, char** argv)
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            bool enableHeartbeat = true;
 | 
			
		||||
            ix::StatsdClient statsdClient(hostname, statsdPort, prefix);
 | 
			
		||||
 | 
			
		||||
            std::string errMsg;
 | 
			
		||||
@@ -563,17 +571,36 @@ int main(int argc, char** argv)
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                ret = (int) ix::cobra_to_statsd_bot(
 | 
			
		||||
                    cobraBotConfig, statsdClient, fields, gauge, timer, verbose);
 | 
			
		||||
                ret = (int) ix::cobra_to_statsd_bot(cobraConfig,
 | 
			
		||||
                                                    channel,
 | 
			
		||||
                                                    filter,
 | 
			
		||||
                                                    position,
 | 
			
		||||
                                                    statsdClient,
 | 
			
		||||
                                                    fields,
 | 
			
		||||
                                                    gauge,
 | 
			
		||||
                                                    timer,
 | 
			
		||||
                                                    verbose,
 | 
			
		||||
                                                    maxQueueSize,
 | 
			
		||||
                                                    enableHeartbeat,
 | 
			
		||||
                                                    runtime);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else if (app.got_subcommand("cobra_to_sentry"))
 | 
			
		||||
    {
 | 
			
		||||
        bool enableHeartbeat = true;
 | 
			
		||||
        ix::SentryClient sentryClient(dsn);
 | 
			
		||||
        sentryClient.setTLSOptions(tlsOptions);
 | 
			
		||||
 | 
			
		||||
        ret = (int) ix::cobra_to_sentry_bot(cobraBotConfig, sentryClient, verbose);
 | 
			
		||||
        ret = (int) ix::cobra_to_sentry_bot(cobraConfig,
 | 
			
		||||
                                            channel,
 | 
			
		||||
                                            filter,
 | 
			
		||||
                                            position,
 | 
			
		||||
                                            sentryClient,
 | 
			
		||||
                                            verbose,
 | 
			
		||||
                                            maxQueueSize,
 | 
			
		||||
                                            enableHeartbeat,
 | 
			
		||||
                                            runtime);
 | 
			
		||||
    }
 | 
			
		||||
    else if (app.got_subcommand("cobra_metrics_to_redis"))
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user