Compare commits

..

1 Commits

Author SHA1 Message Date
d8597b054c bump version for universal windows platform fixes 2020-05-01 11:32:58 -07:00
36 changed files with 545 additions and 449 deletions

View File

@ -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,18 +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/
)
install(EXPORT ixwebsocket NAMESPACE ixwebsocket:: DESTINATION lib/cmake/ixwebsocket)
export(EXPORT ixwebsocket NAMESPACE ixwebsocket:: FILE ixwebsocketConfig.cmake)
if (USE_WS OR USE_TEST)
add_subdirectory(ixcore)
add_subdirectory(ixcrypto)

View File

@ -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)
- [dis-light](https://gitlab.com/HCInk/dis-light), a discord library with a node frontend.
- [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

View File

@ -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 && \

View File

@ -1,37 +1,9 @@
# Changelog
All changes to this project will be documented in this file.
## [9.6.1] - 2020-05-17
## [9.5.4] - 2020-05-01
(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
(windows) fix build for universal windows platform
## [9.5.3] - 2020-04-29

View File

@ -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
)

View File

@ -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;
}

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View 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

View File

@ -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");

View File

@ -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();

View File

@ -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);

View File

@ -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";
@ -248,7 +241,8 @@ namespace ix
}
// Make a new cancellation object dealing with transfer timeout
isCancellationRequested = makeCancellationRequestWithTimeout(args->transferTimeout, _stop);
isCancellationRequested =
makeCancellationRequestWithTimeout(args->transferTimeout, _stop);
if (args->verbose)
{
@ -567,20 +561,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;

View File

@ -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

View File

@ -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>

View File

@ -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
{

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -6,4 +6,4 @@
#pragma once
#define IX_WEBSOCKET_VERSION "9.6.1"
#define IX_WEBSOCKET_VERSION "9.5.4"

View File

@ -26,7 +26,7 @@ brew:
# 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)
@ -148,7 +148,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)

View File

@ -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
//

View File

@ -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
//

View File

@ -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
//

View File

@ -4,7 +4,7 @@
* Copyright (c) 2019 Machine Zone. All rights reserved.
*/
// Using inet_addr will trigger an error on uwp without this
// Using inet_addr will trigger an error on uwp without this
// FIXME: use a different api
#ifdef _WIN32
#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS

View File

@ -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);
}

View File

@ -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"))
{