Compare commits
	
		
			1 Commits
		
	
	
		
			v7.8.8
			...
			feature/ma
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 84361c16a9 | 
| @@ -1,48 +1,13 @@ | ||||
| # Changelog | ||||
| All changes to this project will be documented in this file. | ||||
|  | ||||
| ## [7.8.7] - 2019-12-28 | ||||
|  | ||||
| (mbedtls) fix related to private key file parsing and initialization | ||||
|  | ||||
| ## [7.8.6] - 2019-12-28 | ||||
|  | ||||
| (ws cobra to sentry/statsd) fix for handling null events properly for empty queues + use queue to send data to statsd | ||||
|  | ||||
| ## [7.8.5] - 2019-12-28 | ||||
|  | ||||
| (ws cobra to sentry) handle null events for empty queues | ||||
|  | ||||
| ## [7.8.4] - 2019-12-27 | ||||
|  | ||||
| (ws cobra to sentry) game is picked in a fair manner, so that all games get the same share of sent events | ||||
|  | ||||
| ## [7.8.3] - 2019-12-27 | ||||
|  | ||||
| (ws cobra to sentry) refactor queue related code into a class | ||||
|  | ||||
| ## [7.8.2] - 2019-12-25 | ||||
|  | ||||
| (ws cobra to sentry) bound the queue size used to hold up cobra messages before they are sent to sentry. Default queue size is a 100 messages. Without such limit the program runs out of memory when a subscriber receive a lot of messages that cannot make it to sentry | ||||
|  | ||||
| ## [7.8.1] - 2019-12-25 | ||||
|  | ||||
| (ws client) use correct compilation defines so that spdlog is not used as a header only library (reduce binary size and increase compilation speed) | ||||
|  | ||||
| ## [7.8.0] - 2019-12-24 | ||||
|  | ||||
| (ws client) all commands use spdlog instead of std::cerr or std::cout for logging | ||||
|  | ||||
| ## [7.6.5] - 2019-12-24 | ||||
|  | ||||
| (cobra client) send a websocket ping every 30s to keep the connection opened | ||||
|  | ||||
| ## [7.6.4] - 2019-12-22 | ||||
|  | ||||
| (client) error handling, quote url in error case when failing to parse one | ||||
| (ws) ws_cobra_publish: register callbacks before connecting | ||||
| (doc) mention mbedtls in supported ssl server backend | ||||
|  | ||||
|  | ||||
| ## [7.6.3] - 2019-12-20 | ||||
|  | ||||
| (tls) add a simple description of the TLS configuration routine for debugging | ||||
|   | ||||
| @@ -24,7 +24,6 @@ namespace ix | ||||
|     PublishTrackerCallback CobraConnection::_publishTrackerCallback = nullptr; | ||||
|     constexpr size_t CobraConnection::kQueueMaxSize; | ||||
|     constexpr CobraConnection::MsgId CobraConnection::kInvalidMsgId; | ||||
|     constexpr int CobraConnection::kPingIntervalSecs; | ||||
|  | ||||
|     CobraConnection::CobraConnection() : | ||||
|         _webSocket(new WebSocket()), | ||||
| @@ -229,10 +228,6 @@ namespace ix | ||||
|                     ss << "HTTP Status: "      << msg->errorInfo.http_status << std::endl; | ||||
|                     invokeErrorCallback(ss.str(), std::string()); | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Pong) | ||||
|                 { | ||||
|                     invokeEventCallback(ix::CobraConnection_EventType_Pong); | ||||
|                 } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| @@ -265,7 +260,6 @@ namespace ix | ||||
|         _webSocket->setUrl(url); | ||||
|         _webSocket->setPerMessageDeflateOptions(webSocketPerMessageDeflateOptions); | ||||
|         _webSocket->setTLSOptions(socketTLSOptions); | ||||
|         _webSocket->setPingInterval(kPingIntervalSecs); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|   | ||||
| @@ -30,8 +30,7 @@ namespace ix | ||||
|         CobraConnection_EventType_Closed = 3, | ||||
|         CobraConnection_EventType_Subscribed = 4, | ||||
|         CobraConnection_EventType_UnSubscribed = 5, | ||||
|         CobraConnection_EventType_Published = 6, | ||||
|         CobraConnection_EventType_Pong = 7 | ||||
|         CobraConnection_EventType_Published = 6 | ||||
|     }; | ||||
|  | ||||
|     enum CobraConnectionPublishMode | ||||
| @@ -216,9 +215,6 @@ namespace ix | ||||
|  | ||||
|         // Each pdu sent should have an incremental unique id | ||||
|         std::atomic<uint64_t> _id; | ||||
|  | ||||
|         // Frequency at which we send a websocket ping to the backing cobra connection | ||||
|         static constexpr int kPingIntervalSecs = 30; | ||||
|     }; | ||||
|  | ||||
| } // namespace ix | ||||
|   | ||||
| @@ -65,10 +65,6 @@ namespace ix | ||||
|                 { | ||||
|                     ss << "Published message " << msgId << " acked"; | ||||
|                 } | ||||
|                 else if (eventType == ix::CobraConnection_EventType_Pong) | ||||
|                 { | ||||
|                     ss << "Received websocket pong"; | ||||
|                 } | ||||
|  | ||||
|                 ix::IXCoreLogger::Log(ss.str().c_str()); | ||||
|         }); | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| #include "IXSocketConnect.h" | ||||
| #include "IXUserAgent.h" | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| #include <sstream> | ||||
| #include <vector> | ||||
|  | ||||
|   | ||||
| @@ -24,47 +24,9 @@ | ||||
|  | ||||
| #include <Security/SecureTransport.h> | ||||
|  | ||||
| namespace ix | ||||
| namespace | ||||
| { | ||||
|     SocketAppleSSL::SocketAppleSSL(const SocketTLSOptions& tlsOptions, int fd) | ||||
|         : Socket(fd) | ||||
|         , _sslContext(nullptr) | ||||
|         , _tlsOptions(tlsOptions) | ||||
|     { | ||||
|         ; | ||||
|     } | ||||
|  | ||||
|     SocketAppleSSL::~SocketAppleSSL() | ||||
|     { | ||||
|         SocketAppleSSL::close(); | ||||
|     } | ||||
|  | ||||
|     std::string SocketAppleSSL::getSSLErrorDescription(OSStatus status) | ||||
|     { | ||||
|         std::string errMsg("Unknown SSL error."); | ||||
|  | ||||
|         CFErrorRef error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, status, NULL); | ||||
|         if (error) | ||||
|         { | ||||
|             CFStringRef message = CFErrorCopyDescription(error); | ||||
|             if (message) | ||||
|             { | ||||
|                 char localBuffer[128]; | ||||
|                 Boolean success; | ||||
|                 success = CFStringGetCString(message, localBuffer, 128, kCFStringEncodingUTF8); | ||||
|                 if (success) | ||||
|                 { | ||||
|                     errMsg = localBuffer; | ||||
|                 } | ||||
|                 CFRelease(message); | ||||
|             } | ||||
|             CFRelease(error); | ||||
|         } | ||||
|  | ||||
|         return errMsg; | ||||
|     } | ||||
|  | ||||
|     OSStatus SocketAppleSSL::readFromSocket(SSLConnectionRef connection, void* data, size_t* len) | ||||
|     OSStatus read_from_socket(SSLConnectionRef connection, void* data, size_t* len) | ||||
|     { | ||||
|         int fd = (int) (long) connection; | ||||
|         if (fd < 0) return errSSLInternal; | ||||
| @@ -105,9 +67,7 @@ namespace ix | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     OSStatus SocketAppleSSL::writeToSocket(SSLConnectionRef connection, | ||||
|                                            const void* data, | ||||
|                                            size_t* len) | ||||
|     OSStatus write_to_socket(SSLConnectionRef connection, const void* data, size_t* len) | ||||
|     { | ||||
|         int fd = (int) (long) connection; | ||||
|         if (fd < 0) return errSSLInternal; | ||||
| @@ -145,6 +105,145 @@ namespace ix | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     std::string getSSLErrorDescription(OSStatus status) | ||||
|     { | ||||
|         std::string errMsg("Unknown SSL error."); | ||||
|  | ||||
|         CFErrorRef error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, status, NULL); | ||||
|         if (error) | ||||
|         { | ||||
|             CFStringRef message = CFErrorCopyDescription(error); | ||||
|             if (message) | ||||
|             { | ||||
|                 char localBuffer[128]; | ||||
|                 Boolean success; | ||||
|                 success = CFStringGetCString(message, localBuffer, 128, kCFStringEncodingUTF8); | ||||
|                 if (success) | ||||
|                 { | ||||
|                     errMsg = localBuffer; | ||||
|                 } | ||||
|                 CFRelease(message); | ||||
|             } | ||||
|             CFRelease(error); | ||||
|         } | ||||
|  | ||||
|         return errMsg; | ||||
|     } | ||||
|  | ||||
| #undef CURL_BUILD_IOS | ||||
|     OSStatus CopyIdentityFromPKCS12File( | ||||
|         const char *cPath, | ||||
|         const char *cPassword, | ||||
|         SecIdentityRef *out_cert_and_key) | ||||
|     { | ||||
|         OSStatus status = errSecItemNotFound; | ||||
|         CFURLRef pkcs_url = CFURLCreateFromFileSystemRepresentation( | ||||
|             NULL, (const UInt8 *)cPath, strlen(cPath), false); | ||||
|         CFStringRef password = cPassword ? CFStringCreateWithCString(NULL, | ||||
|             cPassword, kCFStringEncodingUTF8) : NULL; | ||||
|         CFDataRef pkcs_data = NULL; | ||||
|  | ||||
|         /* We can import P12 files on iOS or OS X 10.7 or later: */ | ||||
|         /* These constants are documented as having first appeared in 10.6 but they | ||||
|            raise linker errors when used on that cat for some reason. */ | ||||
|         if (CFURLCreateDataAndPropertiesFromResource( | ||||
|             NULL, pkcs_url, &pkcs_data, NULL, NULL, &status)) { | ||||
|             CFArrayRef items = NULL; | ||||
|  | ||||
|             /* On iOS SecPKCS12Import will never add the client certificate to the | ||||
|              * Keychain. | ||||
|              * | ||||
|              * It gives us back a SecIdentityRef that we can use directly. */ | ||||
| #if CURL_BUILD_IOS | ||||
|             const void *cKeys[] = {kSecImportExportPassphrase}; | ||||
|             const void *cValues[] = {password}; | ||||
|             CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues, | ||||
|                     password ? 1L : 0L, NULL, NULL); | ||||
|  | ||||
|             if (options != NULL) { | ||||
|                 status = SecPKCS12Import(pkcs_data, options, &items); | ||||
|                 CFRelease(options); | ||||
|             } | ||||
|  | ||||
|             /* On macOS SecPKCS12Import will always add the client certificate to | ||||
|              * the Keychain. | ||||
|              * | ||||
|              * As this doesn't match iOS, and apps may not want to see their client | ||||
|              * certificate saved in the the user's keychain, we use SecItemImport | ||||
|              * with a NULL keychain to avoid importing it. | ||||
|              * | ||||
|              * This returns a SecCertificateRef from which we can construct a | ||||
|              * SecIdentityRef. | ||||
|              */ | ||||
| #else | ||||
|             SecItemImportExportKeyParameters keyParams; | ||||
|             SecExternalFormat inputFormat = kSecFormatPKCS12; | ||||
|             SecExternalItemType inputType = kSecItemTypeCertificate; | ||||
|  | ||||
|             memset(&keyParams, 0x00, sizeof(keyParams)); | ||||
|             keyParams.version    = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; | ||||
|             keyParams.passphrase = password; | ||||
|  | ||||
|             status = SecItemImport(pkcs_data, NULL, &inputFormat, &inputType, | ||||
|                                    0, &keyParams, NULL, &items); | ||||
| #endif | ||||
|  | ||||
|             /* Extract the SecIdentityRef */ | ||||
|             if (status == errSecSuccess && items && CFArrayGetCount(items)) | ||||
|             { | ||||
|                 CFIndex i, count; | ||||
|                 count = CFArrayGetCount(items); | ||||
|  | ||||
|                 for (i = 0; i < count; i++) | ||||
|                 { | ||||
|                     CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(items, i); | ||||
|                     CFTypeID  itemID = CFGetTypeID(item); | ||||
|  | ||||
|                     if (itemID == CFDictionaryGetTypeID()) | ||||
|                     { | ||||
|                         CFTypeRef identity = (CFTypeRef) CFDictionaryGetValue( | ||||
|                                 (CFDictionaryRef) item, | ||||
|                                 kSecImportItemIdentity); | ||||
|                         CFRetain(identity); | ||||
|                         *out_cert_and_key = (SecIdentityRef) identity; | ||||
|                         break; | ||||
|                     } | ||||
|                     else if (itemID == SecCertificateGetTypeID()) | ||||
|                     { | ||||
|                         status = SecIdentityCreateWithCertificate(NULL, | ||||
|                                 (SecCertificateRef) item, | ||||
|                                 out_cert_and_key); | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (items) CFRelease(items); | ||||
|             CFRelease(pkcs_data); | ||||
|         } | ||||
|  | ||||
|         if (password) CFRelease(password); | ||||
|         CFRelease(pkcs_url); | ||||
|         return status; | ||||
|     } | ||||
|  | ||||
|  | ||||
| } // anonymous namespace | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     SocketAppleSSL::SocketAppleSSL(const SocketTLSOptions& tlsOptions, int fd) | ||||
|         : Socket(fd) | ||||
|         , _sslContext(nullptr) | ||||
|         , _tlsOptions(tlsOptions) | ||||
|     { | ||||
|         ; | ||||
|     } | ||||
|  | ||||
|     SocketAppleSSL::~SocketAppleSSL() | ||||
|     { | ||||
|         SocketAppleSSL::close(); | ||||
|     } | ||||
|  | ||||
|     bool SocketAppleSSL::accept(std::string& errMsg) | ||||
|     { | ||||
| @@ -152,6 +251,63 @@ namespace ix | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool SocketAppleSSL::handleTLSOptions(std::string& errMsg) | ||||
|     { | ||||
|         SecIdentityRef cert_and_key = NULL; | ||||
|  | ||||
|         const char* ssl_cert = _tlsOptions.certFile.c_str(); | ||||
|  | ||||
|         OSStatus err = CopyIdentityFromPKCS12File(ssl_cert, "foobar", &cert_and_key); | ||||
|  | ||||
|         if (err == noErr && cert_and_key) | ||||
|         { | ||||
|             SecCertificateRef cert = NULL; | ||||
|             CFTypeRef certs_c[1]; | ||||
|             CFArrayRef certs; | ||||
|  | ||||
|             err = SecIdentityCopyCertificate(cert_and_key, &cert); | ||||
|  | ||||
|             certs_c[0] = cert_and_key; | ||||
|             certs = CFArrayCreate(NULL, (const void **)certs_c, 1L, | ||||
|                     &kCFTypeArrayCallBacks); | ||||
|             err = SSLSetCertificate(_sslContext, certs); | ||||
|             if (err != noErr) | ||||
|             { | ||||
|                 errMsg = "SSLSetCertificate failed"; | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             switch(err) { | ||||
|                 case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */ | ||||
|                     errMsg = "SSL: Incorrect password for the certificate \"%s\" " | ||||
|                             "and its private key."; // , ssl_cert); | ||||
|                     break; | ||||
|                 case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */ | ||||
|                     errMsg = "SSL: Couldn't make sense of the data in the " | ||||
|                             "certificate \"%s\" and its private key."; | ||||
|                             ; // ssl_cert); | ||||
|                     break; | ||||
|                 case -25260: /* errSecPassphraseRequired */ | ||||
|                     errMsg = "SSL The certificate \"%s\" requires a password."; | ||||
|                             // ssl_cert); | ||||
|                     break; | ||||
|                 case errSecItemNotFound: | ||||
|                     errMsg = "SSL: Can't find the certificate \"%s\" and its private " | ||||
|                             "key in the Keychain."; // , ssl_cert); | ||||
|                     break; | ||||
|                 default: | ||||
|                     errMsg = "SSL: Can't load the certificate \"%s\" and its private " | ||||
|                             "key: OSStatus %d" ; // , ssl_cert, err); | ||||
|                     break; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     // No wait support | ||||
|     bool SocketAppleSSL::connect(const std::string& host, | ||||
|                                  int port, | ||||
| @@ -167,12 +323,13 @@ namespace ix | ||||
|  | ||||
|             _sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType); | ||||
|  | ||||
|             SSLSetIOFuncs( | ||||
|                 _sslContext, SocketAppleSSL::readFromSocket, SocketAppleSSL::writeToSocket); | ||||
|             SSLSetIOFuncs(_sslContext, read_from_socket, write_to_socket); | ||||
|             SSLSetConnection(_sslContext, (SSLConnectionRef)(long) _sockfd); | ||||
|             SSLSetProtocolVersionMin(_sslContext, kTLSProtocol12); | ||||
|             SSLSetPeerDomainName(_sslContext, host.c_str(), host.size()); | ||||
|  | ||||
|             if (!handleTLSOptions(errMsg)) return false; // FIXME not calling close() | ||||
|  | ||||
|             if (_tlsOptions.isPeerVerifyDisabled()) | ||||
|             { | ||||
|                 Boolean option(1); | ||||
|   | ||||
| @@ -34,9 +34,7 @@ namespace ix | ||||
|         virtual ssize_t recv(void* buffer, size_t length) final; | ||||
|  | ||||
|     private: | ||||
|         static std::string getSSLErrorDescription(OSStatus status); | ||||
|         static OSStatus writeToSocket(SSLConnectionRef connection, const void* data, size_t* len); | ||||
|         static OSStatus readFromSocket(SSLConnectionRef connection, void* data, size_t* len); | ||||
|         bool handleTLSOptions(std::string& errMsg); | ||||
|  | ||||
|         SSLContextRef _sslContext; | ||||
|         mutable std::mutex _mutex; // AppleSSL routines are not thread-safe | ||||
|   | ||||
| @@ -39,7 +39,6 @@ namespace ix | ||||
|         mbedtls_entropy_init(&_entropy); | ||||
|         mbedtls_x509_crt_init(&_cacert); | ||||
|         mbedtls_x509_crt_init(&_cert); | ||||
|         mbedtls_pk_init(&_pkey); | ||||
|     } | ||||
|  | ||||
|     bool SocketMbedTLS::init(const std::string& host, bool isClient, std::string& errMsg) | ||||
| @@ -82,11 +81,6 @@ namespace ix | ||||
|                 errMsg = "Cannot parse key file '" + _tlsOptions.keyFile + "'"; | ||||
|                 return false; | ||||
|             } | ||||
|             if (mbedtls_ssl_conf_own_cert(&_conf, &_cert, &_pkey) < 0) | ||||
|             { | ||||
|                 errMsg = "Problem configuring cert '" + _tlsOptions.certFile + "'"; | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (_tlsOptions.isPeerVerifyDisabled()) | ||||
| @@ -110,6 +104,11 @@ namespace ix | ||||
|             } | ||||
|  | ||||
|             mbedtls_ssl_conf_ca_chain(&_conf, &_cacert, NULL); | ||||
|  | ||||
|             if (_tlsOptions.hasCertAndKey()) | ||||
|             { | ||||
|                 mbedtls_ssl_conf_own_cert(&_conf, &_cert, &_pkey); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (mbedtls_ssl_setup(&_ssl, &_conf) != 0) | ||||
|   | ||||
| @@ -11,8 +11,8 @@ | ||||
| #include "IXSocketConnect.h" | ||||
| #include "IXSocketFactory.h" | ||||
| #include <assert.h> | ||||
| #include <iostream> | ||||
| #include <sstream> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
|  | ||||
| namespace ix | ||||
| @@ -45,13 +45,13 @@ namespace ix | ||||
|     void SocketServer::logError(const std::string& str) | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(_logMutex); | ||||
|         fprintf(stderr, "%s\n", str.c_str()); | ||||
|         std::cerr << str << std::endl; | ||||
|     } | ||||
|  | ||||
|     void SocketServer::logInfo(const std::string& str) | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(_logMutex); | ||||
|         fprintf(stdout, "%s\n", str.c_str()); | ||||
|         std::cout << str << std::endl; | ||||
|     } | ||||
|  | ||||
|     std::pair<bool, std::string> SocketServer::listen() | ||||
|   | ||||
| @@ -6,4 +6,4 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #define IX_WEBSOCKET_VERSION "7.8.7" | ||||
| #define IX_WEBSOCKET_VERSION "7.6.4" | ||||
|   | ||||
| @@ -23,8 +23,6 @@ include_directories( | ||||
|   ../ws | ||||
| ) | ||||
|  | ||||
| add_definitions(-DSPDLOG_COMPILED_LIB=1) | ||||
|  | ||||
| find_package(JsonCpp) | ||||
| if (NOT JSONCPP_FOUND) | ||||
|   include_directories(../third_party/jsoncpp) | ||||
| @@ -100,6 +98,4 @@ target_link_libraries(ixwebsocket_unittest ixcrypto) | ||||
| target_link_libraries(ixwebsocket_unittest ixcore) | ||||
| target_link_libraries(ixwebsocket_unittest ixsentry) | ||||
|  | ||||
| target_link_libraries(ixwebsocket_unittest spdlog) | ||||
|  | ||||
| install(TARGETS ixwebsocket_unittest DESTINATION bin) | ||||
|   | ||||
| @@ -37,7 +37,9 @@ namespace | ||||
|     class CobraChat | ||||
|     { | ||||
|     public: | ||||
|         CobraChat(const std::string& user, const std::string& session, const std::string& endpoint); | ||||
|         CobraChat(const std::string& user, | ||||
|                    const std::string& session, | ||||
|                    const std::string& endpoint); | ||||
|  | ||||
|         void subscribe(const std::string& channel); | ||||
|         void start(); | ||||
|   | ||||
| @@ -25,8 +25,6 @@ include_directories(ws ../third_party/statsd-client-cpp/src) | ||||
| include_directories(ws ../third_party/spdlog/include) | ||||
| include_directories(ws ../third_party/cpp-linenoise) | ||||
|  | ||||
| add_definitions(-DSPDLOG_COMPILED_LIB=1) | ||||
|  | ||||
| if (UNIX) | ||||
|   set( STATSD_CLIENT_SOURCES ../third_party/statsd-client-cpp/src/statsd_client.cpp) | ||||
| endif() | ||||
| @@ -74,8 +72,6 @@ target_link_libraries(ws ixcrypto) | ||||
| target_link_libraries(ws ixcore) | ||||
| target_link_libraries(ws ixsentry) | ||||
|  | ||||
| target_link_libraries(ws spdlog) | ||||
|  | ||||
| if(NOT APPLE AND NOT USE_MBED_TLS) | ||||
|   find_package(OpenSSL REQUIRED) | ||||
|   add_definitions(${OPENSSL_DEFINITIONS}) | ||||
|   | ||||
							
								
								
									
										27
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								ws/ws.cpp
									
									
									
									
									
								
							| @@ -11,6 +11,7 @@ | ||||
|  | ||||
| #include <cli11/CLI11.hpp> | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| #include <ixcore/utils/IXCoreLogger.h> | ||||
| #include <ixwebsocket/IXNetSystem.h> | ||||
| #include <ixwebsocket/IXSocket.h> | ||||
| @@ -38,13 +39,12 @@ int main(int argc, char** argv) | ||||
|     // Display command. | ||||
|     if (getenv("DEBUG")) | ||||
|     { | ||||
|         std::stringstream ss; | ||||
|         ss << "Command: "; | ||||
|         std::cout << "Command: "; | ||||
|         for (int i = 0; i < argc; ++i) | ||||
|         { | ||||
|             ss << argv[i] << " "; | ||||
|             std::cout << argv[i] << " "; | ||||
|         } | ||||
|         spdlog::info(ss.str()); | ||||
|         std::cout << std::endl; | ||||
|     } | ||||
|  | ||||
|     CLI::App app {"ws is a websocket tool"}; | ||||
| @@ -105,7 +105,6 @@ int main(int argc, char** argv) | ||||
|     int count = 1; | ||||
|     int jobs = 4; | ||||
|     uint32_t maxWaitBetweenReconnectionRetries; | ||||
|     size_t maxQueueSize = 100; | ||||
|  | ||||
|     auto addTLSOptions = [&tlsOptions, &verifyNone](CLI::App* app) { | ||||
|         app->add_option( | ||||
| @@ -269,9 +268,6 @@ int main(int argc, char** argv) | ||||
|     cobra2sentry->add_option("--rolesecret", rolesecret, "Role secret")->required(); | ||||
|     cobra2sentry->add_option("--dsn", dsn, "Sentry DSN"); | ||||
|     cobra2sentry->add_option("--jobs", jobs, "Number of thread sending events to Sentry"); | ||||
|     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_flag("-s", strict, "Strict mode. Error out when sending to sentry fails"); | ||||
| @@ -459,7 +455,6 @@ int main(int argc, char** argv) | ||||
|                                           verbose, | ||||
|                                           strict, | ||||
|                                           jobs, | ||||
|                                           maxQueueSize, | ||||
|                                           tlsOptions); | ||||
|     } | ||||
|     else if (app.got_subcommand("cobra_metrics_to_redis")) | ||||
| @@ -476,14 +471,8 @@ int main(int argc, char** argv) | ||||
|     } | ||||
|     else if (app.got_subcommand("snake")) | ||||
|     { | ||||
|         ret = ix::ws_snake_main(port, | ||||
|                                 hostname, | ||||
|                                 redisHosts, | ||||
|                                 redisPort, | ||||
|                                 redisPassword, | ||||
|                                 verbose, | ||||
|                                 appsConfigPath, | ||||
|                                 tlsOptions); | ||||
|         ret = ix::ws_snake_main( | ||||
|             port, hostname, redisHosts, redisPort, redisPassword, verbose, appsConfigPath, tlsOptions); | ||||
|     } | ||||
|     else if (app.got_subcommand("httpd")) | ||||
|     { | ||||
| @@ -507,11 +496,11 @@ int main(int argc, char** argv) | ||||
|     } | ||||
|     else if (version) | ||||
|     { | ||||
|         spdlog::info("ws {}", ix::userAgent()); | ||||
|         std::cout << "ws " << ix::userAgent() << std::endl; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         spdlog::error("A subcommand or --version is required"); | ||||
|         std::cerr << "A subcommand or --version is required" << std::endl; | ||||
|     } | ||||
|  | ||||
|     ix::uninitNetSystem(); | ||||
|   | ||||
							
								
								
									
										1
									
								
								ws/ws.h
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								ws/ws.h
									
									
									
									
									
								
							| @@ -119,7 +119,6 @@ namespace ix | ||||
|                                 bool verbose, | ||||
|                                 bool strict, | ||||
|                                 int jobs, | ||||
|                                 size_t maxQueueSize, | ||||
|                                 const ix::SocketTLSOptions& tlsOptions); | ||||
|  | ||||
|     int ws_cobra_metrics_to_redis(const std::string& appkey, | ||||
|   | ||||
| @@ -32,6 +32,7 @@ | ||||
|  | ||||
| #include <atomic> | ||||
| #include <condition_variable> | ||||
| #include <iostream> | ||||
| #include <ixwebsocket/IXSocket.h> | ||||
| #include <ixwebsocket/IXWebSocket.h> | ||||
| #include <mutex> | ||||
| @@ -90,7 +91,7 @@ namespace ix | ||||
|     { | ||||
|         if (!_quiet) | ||||
|         { | ||||
|             spdlog::info(msg); | ||||
|             std::cerr << msg; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -182,7 +183,7 @@ namespace ix | ||||
|         webSocket.setOnMessageCallback([&condition, &success](const ix::WebSocketMessagePtr& msg) { | ||||
|             if (msg->type == ix::WebSocketMessageType::Close) | ||||
|             { | ||||
|                 spdlog::info("Report generated"); | ||||
|                 std::cerr << "Report generated" << std::endl; | ||||
|                 condition.notify_one(); | ||||
|             } | ||||
|             else if (msg->type == ix::WebSocketMessageType::Error) | ||||
| @@ -192,7 +193,7 @@ namespace ix | ||||
|                 ss << "#retries: " << msg->errorInfo.retries << std::endl; | ||||
|                 ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl; | ||||
|                 ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl; | ||||
|                 spdlog::info(ss.str()); | ||||
|                 std::cerr << ss.str() << std::endl; | ||||
|  | ||||
|                 success = false; | ||||
|             } | ||||
| @@ -235,7 +236,7 @@ namespace ix | ||||
|                 ss << "#retries: " << msg->errorInfo.retries << std::endl; | ||||
|                 ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl; | ||||
|                 ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl; | ||||
|                 spdlog::info(ss.str()); | ||||
|                 std::cerr << ss.str() << std::endl; | ||||
|  | ||||
|                 condition.notify_one(); | ||||
|             } | ||||
| @@ -268,7 +269,7 @@ namespace ix | ||||
|     int ws_autobahn_main(const std::string& url, bool quiet) | ||||
|     { | ||||
|         int testCasesCount = getTestCaseCount(url); | ||||
|         spdlog::info("Test cases count: {}", testCasesCount); | ||||
|         std::cerr << "Test cases count: " << testCasesCount << std::endl; | ||||
|  | ||||
|         if (testCasesCount == -1) | ||||
|         { | ||||
|   | ||||
| @@ -4,18 +4,17 @@ | ||||
|  *  Copyright (c) 2018 Machine Zone, Inc. All rights reserved. | ||||
|  */ | ||||
|  | ||||
| #include <iostream> | ||||
| #include <ixwebsocket/IXWebSocketServer.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
|  | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     int ws_broadcast_server_main(int port, | ||||
|                                  const std::string& hostname, | ||||
|                                  const ix::SocketTLSOptions& tlsOptions) | ||||
|     { | ||||
|         spdlog::info("Listening on {}:{}", hostname, port); | ||||
|         std::cout << "Listening on " << hostname << ":" << port << std::endl; | ||||
|  | ||||
|         ix::WebSocketServer server(port, hostname); | ||||
|         server.setTLSOptions(tlsOptions); | ||||
| @@ -26,20 +25,20 @@ namespace ix | ||||
|                                                 const WebSocketMessagePtr& msg) { | ||||
|                 if (msg->type == ix::WebSocketMessageType::Open) | ||||
|                 { | ||||
|                     spdlog::info("New connection"); | ||||
|                     spdlog::info("id: {}", connectionState->getId()); | ||||
|                     spdlog::info("Uri: {}", msg->openInfo.uri); | ||||
|                     spdlog::info("Headers:"); | ||||
|                     std::cerr << "New connection" << std::endl; | ||||
|                     std::cerr << "id: " << connectionState->getId() << std::endl; | ||||
|                     std::cerr << "Uri: " << msg->openInfo.uri << std::endl; | ||||
|                     std::cerr << "Headers:" << std::endl; | ||||
|                     for (auto it : msg->openInfo.headers) | ||||
|                     { | ||||
|                         spdlog::info("{}: {}", it.first, it.second); | ||||
|                         std::cerr << it.first << ": " << it.second << std::endl; | ||||
|                     } | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Close) | ||||
|                 { | ||||
|                     spdlog::info("Closed connection: code {} reason {}", | ||||
|                                  msg->closeInfo.code, | ||||
|                                  msg->closeInfo.reason); | ||||
|                     std::cerr << "Closed connection" | ||||
|                               << " code " << msg->closeInfo.code << " reason " | ||||
|                               << msg->closeInfo.reason << std::endl; | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Error) | ||||
|                 { | ||||
| @@ -48,29 +47,30 @@ namespace ix | ||||
|                     ss << "#retries: " << msg->errorInfo.retries << std::endl; | ||||
|                     ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl; | ||||
|                     ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl; | ||||
|                     spdlog::info(ss.str()); | ||||
|                     std::cerr << ss.str(); | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Fragment) | ||||
|                 { | ||||
|                     spdlog::info("Received message fragment"); | ||||
|                     std::cerr << "Received message fragment" << std::endl; | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Message) | ||||
|                 { | ||||
|                     spdlog::info("Received {} bytes", msg->wireSize); | ||||
|                     std::cerr << "Received " << msg->wireSize << " bytes" << std::endl; | ||||
|  | ||||
|                     for (auto&& client : server.getClients()) | ||||
|                     { | ||||
|                         if (client != webSocket) | ||||
|                         { | ||||
|                             client->send(msg->str, msg->binary, [](int current, int total) -> bool { | ||||
|                                 spdlog::info("Step {} out of {}", current, total); | ||||
|                                 std::cerr << "Step " << current << " out of " << total << std::endl; | ||||
|                                 return true; | ||||
|                             }); | ||||
|  | ||||
|                             do | ||||
|                             { | ||||
|                                 size_t bufferedAmount = client->bufferedAmount(); | ||||
|                                 spdlog::info("{} bytes left to be sent", bufferedAmount); | ||||
|                                 std::cerr << bufferedAmount << " bytes left to be sent" | ||||
|                                           << std::endl; | ||||
|  | ||||
|                                 std::chrono::duration<double, std::milli> duration(10); | ||||
|                                 std::this_thread::sleep_for(duration); | ||||
| @@ -84,7 +84,7 @@ namespace ix | ||||
|         auto res = server.listen(); | ||||
|         if (!res.first) | ||||
|         { | ||||
|             spdlog::info(res.second); | ||||
|             std::cerr << res.second << std::endl; | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -9,12 +9,11 @@ | ||||
| // Broadcast server can be ran with `ws broadcast_server` | ||||
| // | ||||
|  | ||||
| #include "linenoise.hpp" | ||||
| #include "nlohmann/json.hpp" | ||||
| #include <iostream> | ||||
| #include <ixwebsocket/IXSocket.h> | ||||
| #include <ixwebsocket/IXWebSocket.h> | ||||
| #include <queue> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
|  | ||||
| // for convenience | ||||
| @@ -56,7 +55,7 @@ namespace ix | ||||
|  | ||||
|     void WebSocketChat::log(const std::string& msg) | ||||
|     { | ||||
|         spdlog::info(msg); | ||||
|         std::cout << msg << std::endl; | ||||
|     } | ||||
|  | ||||
|     size_t WebSocketChat::getReceivedMessagesCount() const | ||||
| @@ -86,21 +85,20 @@ namespace ix | ||||
|             if (msg->type == ix::WebSocketMessageType::Open) | ||||
|             { | ||||
|                 log("ws chat: connected"); | ||||
|                 spdlog::info("Uri: {}", msg->openInfo.uri); | ||||
|                 spdlog::info("Headers:"); | ||||
|                 std::cout << "Uri: " << msg->openInfo.uri << std::endl; | ||||
|                 std::cout << "Handshake Headers:" << std::endl; | ||||
|                 for (auto it : msg->openInfo.headers) | ||||
|                 { | ||||
|                     spdlog::info("{}: {}", it.first, it.second); | ||||
|                     std::cout << it.first << ": " << it.second << std::endl; | ||||
|                 } | ||||
|  | ||||
|                 spdlog::info("ws chat: user {} connected !", _user); | ||||
|                 ss << "ws chat: user " << _user << " Connected !"; | ||||
|                 log(ss.str()); | ||||
|             } | ||||
|             else if (msg->type == ix::WebSocketMessageType::Close) | ||||
|             { | ||||
|                 ss << "ws chat user disconnected: " << _user; | ||||
|                 ss << " code " << msg->closeInfo.code; | ||||
|                 ss << " reason " << msg->closeInfo.reason << std::endl; | ||||
|                 ss << "ws chat: user " << _user << " disconnected !" | ||||
|                    << " code " << msg->closeInfo.code << " reason " << msg->closeInfo.reason; | ||||
|                 log(ss.str()); | ||||
|             } | ||||
|             else if (msg->type == ix::WebSocketMessageType::Message) | ||||
| @@ -164,25 +162,25 @@ namespace ix | ||||
|  | ||||
|     int ws_chat_main(const std::string& url, const std::string& user) | ||||
|     { | ||||
|         spdlog::info("Type Ctrl-D to exit prompt..."); | ||||
|         std::cout << "Type Ctrl-D to exit prompt..." << std::endl; | ||||
|         WebSocketChat webSocketChat(url, user); | ||||
|         webSocketChat.start(); | ||||
|  | ||||
|         while (true) | ||||
|         { | ||||
|             // Read line | ||||
|             std::string line; | ||||
|             auto quit = linenoise::Readline("> ", line); | ||||
|             std::string text; | ||||
|             std::cout << user << " > " << std::flush; | ||||
|             std::getline(std::cin, text); | ||||
|  | ||||
|             if (quit) | ||||
|             if (!std::cin) | ||||
|             { | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             webSocketChat.sendMessage(line); | ||||
|             webSocketChat.sendMessage(text); | ||||
|         } | ||||
|  | ||||
|         spdlog::info(""); | ||||
|         std::cout << std::endl; | ||||
|         webSocketChat.stop(); | ||||
|  | ||||
|         return 0; | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
| #include <atomic> | ||||
| #include <chrono> | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| #include <ixcobra/IXCobraMetricsPublisher.h> | ||||
| #include <jsoncpp/json/json.h> | ||||
| #include <spdlog/spdlog.h> | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
| #include <atomic> | ||||
| #include <chrono> | ||||
| #include <condition_variable> | ||||
| #include <iostream> | ||||
| #include <ixcobra/IXCobraConnection.h> | ||||
| #include <ixsnake/IXRedisClient.h> | ||||
| #include <mutex> | ||||
| @@ -43,7 +44,8 @@ namespace ix | ||||
|         auto timer = [&msgPerSeconds, &msgCount] { | ||||
|             while (true) | ||||
|             { | ||||
|                 spdlog::info("#messages {} msg/s {}", msgCount, msgPerSeconds); | ||||
|                 std::cout << "#messages " << msgCount << " " | ||||
|                           << "msg/s " << msgPerSeconds << std::endl; | ||||
|  | ||||
|                 msgPerSeconds = 0; | ||||
|                 auto duration = std::chrono::seconds(1); | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
| #include <atomic> | ||||
| #include <chrono> | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| #include <ixcobra/IXCobraMetricsPublisher.h> | ||||
| #include <jsoncpp/json/json.h> | ||||
| #include <mutex> | ||||
| @@ -90,10 +91,6 @@ namespace ix | ||||
|                 spdlog::info("Published message id {} acked", msgId); | ||||
|                 messageAcked = true; | ||||
|             } | ||||
|             else if (eventType == ix::CobraConnection_EventType_Pong) | ||||
|             { | ||||
|                 spdlog::info("Received websocket pong"); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         conn.connect(); | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
|  | ||||
| #include <atomic> | ||||
| #include <chrono> | ||||
| #include <iostream> | ||||
| #include <ixcobra/IXCobraConnection.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
| @@ -40,7 +41,8 @@ namespace ix | ||||
|         auto timer = [&msgPerSeconds, &msgCount] { | ||||
|             while (true) | ||||
|             { | ||||
|                 spdlog::info("#messages {} msg/s {}", msgCount, msgPerSeconds); | ||||
|                 std::cout << "#messages " << msgCount << " " | ||||
|                           << "msg/s " << msgPerSeconds << std::endl; | ||||
|  | ||||
|                 msgPerSeconds = 0; | ||||
|                 auto duration = std::chrono::seconds(1); | ||||
| @@ -75,7 +77,7 @@ namespace ix | ||||
|                         [&jsonWriter, &quiet, &msgPerSeconds, &msgCount](const Json::Value& msg) { | ||||
|                             if (!quiet) | ||||
|                             { | ||||
|                                 spdlog::info(jsonWriter.write(msg)); | ||||
|                                 std::cerr << jsonWriter.write(msg) << std::endl; | ||||
|                             } | ||||
|  | ||||
|                             msgPerSeconds++; | ||||
| @@ -98,10 +100,6 @@ namespace ix | ||||
|                 { | ||||
|                     spdlog::error("Published message hacked: {}", msgId); | ||||
|                 } | ||||
|                 else if (eventType == ix::CobraConnection_EventType_Pong) | ||||
|                 { | ||||
|                     spdlog::info("Received websocket pong"); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         while (true) | ||||
|   | ||||
| @@ -7,9 +7,9 @@ | ||||
| #include <atomic> | ||||
| #include <chrono> | ||||
| #include <condition_variable> | ||||
| #include <iostream> | ||||
| #include <ixcobra/IXCobraConnection.h> | ||||
| #include <ixsentry/IXSentryClient.h> | ||||
| #include <map> | ||||
| #include <mutex> | ||||
| #include <queue> | ||||
| #include <spdlog/spdlog.h> | ||||
| @@ -19,81 +19,6 @@ | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     class QueueManager | ||||
|     { | ||||
|     public: | ||||
|         QueueManager(size_t maxQueueSize, std::atomic<bool>& stop) | ||||
|             : _maxQueueSize(maxQueueSize) | ||||
|             , _stop(stop) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         Json::Value pop(); | ||||
|         void add(Json::Value msg); | ||||
|  | ||||
|     private: | ||||
|         std::map<std::string, std::queue<Json::Value>> _queues; | ||||
|         std::mutex _mutex; | ||||
|         std::condition_variable _condition; | ||||
|         size_t _maxQueueSize; | ||||
|         std::atomic<bool>& _stop; | ||||
|     }; | ||||
|  | ||||
|     Json::Value QueueManager::pop() | ||||
|     { | ||||
|         std::unique_lock<std::mutex> lock(_mutex); | ||||
|  | ||||
|         if (_queues.empty()) | ||||
|         { | ||||
|             Json::Value val; | ||||
|             return val; | ||||
|         } | ||||
|  | ||||
|         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]; | ||||
|  | ||||
|         spdlog::info("Sending event for game '{}'", game); | ||||
|  | ||||
|         _condition.wait(lock, [this] { return !_stop; }); | ||||
|  | ||||
|         if (_queues[game].empty()) | ||||
|         { | ||||
|             Json::Value val; | ||||
|             return val; | ||||
|         } | ||||
|  | ||||
|         auto msg = _queues[game].front(); | ||||
|         _queues[game].pop(); | ||||
|         return msg; | ||||
|     } | ||||
|  | ||||
|     void QueueManager::add(Json::Value msg) | ||||
|     { | ||||
|         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(msg); | ||||
|             _condition.notify_one(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     int ws_cobra_to_sentry_main(const std::string& appkey, | ||||
|                                 const std::string& endpoint, | ||||
|                                 const std::string& rolename, | ||||
| @@ -104,7 +29,6 @@ namespace ix | ||||
|                                 bool verbose, | ||||
|                                 bool strict, | ||||
|                                 int jobs, | ||||
|                                 size_t maxQueueSize, | ||||
|                                 const ix::SocketTLSOptions& tlsOptions) | ||||
|     { | ||||
|         ix::CobraConnection conn; | ||||
| @@ -123,7 +47,9 @@ namespace ix | ||||
|         std::atomic<bool> stop(false); | ||||
|         std::atomic<bool> throttled(false); | ||||
|  | ||||
|         QueueManager queueManager(maxQueueSize, stop); | ||||
|         std::condition_variable condition; | ||||
|         std::mutex conditionVariableMutex; | ||||
|         std::queue<Json::Value> queue; | ||||
|  | ||||
|         auto timer = [&sentCount, &receivedCount] { | ||||
|             while (true) | ||||
| @@ -137,93 +63,105 @@ namespace ix | ||||
|  | ||||
|         std::thread t1(timer); | ||||
|  | ||||
|         auto sentrySender = | ||||
|             [&queueManager, verbose, &errorSending, &sentCount, &stop, &throttled, &dsn] { | ||||
|                 SentryClient sentryClient(dsn); | ||||
|         auto sentrySender = [&condition, | ||||
|                              &conditionVariableMutex, | ||||
|                              &queue, | ||||
|                              verbose, | ||||
|                              &errorSending, | ||||
|                              &sentCount, | ||||
|                              &stop, | ||||
|                              &throttled, | ||||
|                              &dsn] { | ||||
|             SentryClient sentryClient(dsn); | ||||
|  | ||||
|             while (true) | ||||
|             { | ||||
|                 Json::Value msg; | ||||
|  | ||||
|                 while (true) | ||||
|                 { | ||||
|                     Json::Value msg = queueManager.pop(); | ||||
|                     std::unique_lock<std::mutex> lock(conditionVariableMutex); | ||||
|                     condition.wait(lock, [&queue, &stop] { return !queue.empty() && !stop; }); | ||||
|  | ||||
|                     if (msg.isNull()) continue; | ||||
|                     if (stop) return; | ||||
|  | ||||
|                     auto ret = sentryClient.send(msg, verbose); | ||||
|                     HttpResponsePtr response = ret.first; | ||||
|  | ||||
|                     if (!response) | ||||
|                     { | ||||
|                         spdlog::warn("Null HTTP Response"); | ||||
|                         continue; | ||||
|                     } | ||||
|  | ||||
|                     if (verbose) | ||||
|                     { | ||||
|                         for (auto it : response->headers) | ||||
|                         { | ||||
|                             spdlog::info("{}: {}", it.first, it.second); | ||||
|                         } | ||||
|  | ||||
|                         spdlog::info("Upload size: {}", response->uploadSize); | ||||
|                         spdlog::info("Download size: {}", response->downloadSize); | ||||
|  | ||||
|                         spdlog::info("Status: {}", response->statusCode); | ||||
|                         if (response->errorCode != HttpErrorCode::Ok) | ||||
|                         { | ||||
|                             spdlog::info("error message: {}", response->errorMsg); | ||||
|                         } | ||||
|  | ||||
|                         if (response->headers["Content-Type"] != "application/octet-stream") | ||||
|                         { | ||||
|                             spdlog::info("payload: {}", response->payload); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     if (response->statusCode != 200) | ||||
|                     { | ||||
|                         spdlog::error("Error sending data to sentry: {}", response->statusCode); | ||||
|                         spdlog::error("Body: {}", ret.second); | ||||
|                         spdlog::error("Response: {}", response->payload); | ||||
|                         errorSending = true; | ||||
|  | ||||
|                         // 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()) | ||||
|                             { | ||||
|                                 seconds = 30; | ||||
|                                 spdlog::warn("Error parsing Retry-After header. " | ||||
|                                              "Using {} for the sleep duration", | ||||
|                                              seconds); | ||||
|                             } | ||||
|  | ||||
|                             spdlog::warn("Error 429 - Too Many Requests. ws will sleep " | ||||
|                                          "and retry after {} seconds", | ||||
|                                          retryAfter); | ||||
|  | ||||
|                             throttled = true; | ||||
|                             auto duration = std::chrono::seconds(seconds); | ||||
|                             std::this_thread::sleep_for(duration); | ||||
|                             throttled = false; | ||||
|                         } | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         ++sentCount; | ||||
|                     } | ||||
|  | ||||
|                     if (stop) return; | ||||
|                     msg = queue.front(); | ||||
|                     queue.pop(); | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|                 auto ret = sentryClient.send(msg, verbose); | ||||
|                 HttpResponsePtr response = ret.first; | ||||
|  | ||||
|                 if (!response) | ||||
|                 { | ||||
|                     spdlog::warn("Null HTTP Response"); | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 if (verbose) | ||||
|                 { | ||||
|                     for (auto it : response->headers) | ||||
|                     { | ||||
|                         spdlog::info("{}: {}", it.first, it.second); | ||||
|                     } | ||||
|  | ||||
|                     spdlog::info("Upload size: {}", response->uploadSize); | ||||
|                     spdlog::info("Download size: {}", response->downloadSize); | ||||
|  | ||||
|                     spdlog::info("Status: {}", response->statusCode); | ||||
|                     if (response->errorCode != HttpErrorCode::Ok) | ||||
|                     { | ||||
|                         spdlog::info("error message: {}", response->errorMsg); | ||||
|                     } | ||||
|  | ||||
|                     if (response->headers["Content-Type"] != "application/octet-stream") | ||||
|                     { | ||||
|                         spdlog::info("payload: {}", response->payload); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 if (response->statusCode != 200) | ||||
|                 { | ||||
|                     spdlog::error("Error sending data to sentry: {}", response->statusCode); | ||||
|                     spdlog::error("Body: {}", ret.second); | ||||
|                     spdlog::error("Response: {}", response->payload); | ||||
|                     errorSending = true; | ||||
|  | ||||
|                     // 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()) | ||||
|                         { | ||||
|                             seconds = 30; | ||||
|                             spdlog::warn("Error parsing Retry-After header. " | ||||
|                                          "Using {} for the sleep duration", | ||||
|                                          seconds); | ||||
|                         } | ||||
|  | ||||
|                         spdlog::warn("Error 429 - Too Many Requests. ws will sleep " | ||||
|                                      "and retry after {} seconds", | ||||
|                                      retryAfter); | ||||
|  | ||||
|                         throttled = true; | ||||
|                         auto duration = std::chrono::seconds(seconds); | ||||
|                         std::this_thread::sleep_for(duration); | ||||
|                         throttled = false; | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     ++sentCount; | ||||
|                 } | ||||
|  | ||||
|                 if (stop) return; | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         // Create a thread pool | ||||
|         spdlog::info("Starting {} sentry sender jobs", jobs); | ||||
|         std::cerr << "Starting " << jobs << " sentry sender jobs" << std::endl; | ||||
|         std::vector<std::thread> pool; | ||||
|         for (int i = 0; i < jobs; i++) | ||||
|         { | ||||
| @@ -237,11 +175,13 @@ namespace ix | ||||
|                                verbose, | ||||
|                                &throttled, | ||||
|                                &receivedCount, | ||||
|                                &queueManager](ix::CobraConnectionEventType eventType, | ||||
|                                               const std::string& errMsg, | ||||
|                                               const ix::WebSocketHttpHeaders& headers, | ||||
|                                               const std::string& subscriptionId, | ||||
|                                               CobraConnection::MsgId msgId) { | ||||
|                                &condition, | ||||
|                                &conditionVariableMutex, | ||||
|                                &queue](ix::CobraConnectionEventType eventType, | ||||
|                                        const std::string& errMsg, | ||||
|                                        const ix::WebSocketHttpHeaders& headers, | ||||
|                                        const std::string& subscriptionId, | ||||
|                                        CobraConnection::MsgId msgId) { | ||||
|             if (eventType == ix::CobraConnection_EventType_Open) | ||||
|             { | ||||
|                 spdlog::info("Subscriber connected"); | ||||
| @@ -257,11 +197,16 @@ namespace ix | ||||
|             } | ||||
|             else if (eventType == ix::CobraConnection_EventType_Authenticated) | ||||
|             { | ||||
|                 spdlog::info("Subscriber authenticated"); | ||||
|                 std::cerr << "Subscriber authenticated" << std::endl; | ||||
|                 conn.subscribe(channel, | ||||
|                                filter, | ||||
|                                [&jsonWriter, verbose, &throttled, &receivedCount, &queueManager]( | ||||
|                                    const Json::Value& msg) { | ||||
|                                [&jsonWriter, | ||||
|                                 verbose, | ||||
|                                 &throttled, | ||||
|                                 &receivedCount, | ||||
|                                 &condition, | ||||
|                                 &conditionVariableMutex, | ||||
|                                 &queue](const Json::Value& msg) { | ||||
|                                    if (verbose) | ||||
|                                    { | ||||
|                                        spdlog::info(jsonWriter.write(msg)); | ||||
| @@ -270,11 +215,18 @@ namespace ix | ||||
|                                    // If we cannot send to sentry fast enough, drop the message | ||||
|                                    if (throttled) | ||||
|                                    { | ||||
|                                        condition.notify_one(); | ||||
|                                        return; | ||||
|                                    } | ||||
|  | ||||
|                                    ++receivedCount; | ||||
|                                    queueManager.add(msg); | ||||
|  | ||||
|                                    { | ||||
|                                        std::unique_lock<std::mutex> lock(conditionVariableMutex); | ||||
|                                        queue.push(msg); | ||||
|                                    } | ||||
|  | ||||
|                                    condition.notify_one(); | ||||
|                                }); | ||||
|             } | ||||
|             else if (eventType == ix::CobraConnection_EventType_Subscribed) | ||||
| @@ -293,10 +245,6 @@ namespace ix | ||||
|             { | ||||
|                 spdlog::error("Published message hacked: {}", msgId); | ||||
|             } | ||||
|             else if (eventType == ix::CobraConnection_EventType_Pong) | ||||
|             { | ||||
|                 spdlog::info("Received websocket pong"); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         while (true) | ||||
|   | ||||
| @@ -6,7 +6,7 @@ | ||||
|  | ||||
| #include <atomic> | ||||
| #include <chrono> | ||||
| #include <condition_variable> | ||||
| #include <iostream> | ||||
| #include <ixcobra/IXCobraConnection.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
| @@ -17,59 +17,6 @@ | ||||
| #include <statsd_client.h> | ||||
| #endif | ||||
|  | ||||
| namespace | ||||
| { | ||||
|     class QueueManager | ||||
|     { | ||||
|     public: | ||||
|         QueueManager(size_t maxQueueSize, std::atomic<bool>& stop) | ||||
|             : _maxQueueSize(maxQueueSize) | ||||
|             , _stop(stop) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         Json::Value pop(); | ||||
|         void add(Json::Value msg); | ||||
|  | ||||
|     private: | ||||
|         std::queue<Json::Value> _queue; | ||||
|         std::mutex _mutex; | ||||
|         std::condition_variable _condition; | ||||
|         size_t _maxQueueSize; | ||||
|         std::atomic<bool>& _stop; | ||||
|     }; | ||||
|  | ||||
|     Json::Value QueueManager::pop() | ||||
|     { | ||||
|         std::unique_lock<std::mutex> lock(_mutex); | ||||
|  | ||||
|         if (_queue.empty()) | ||||
|         { | ||||
|             Json::Value val; | ||||
|             return val; | ||||
|         } | ||||
|  | ||||
|         _condition.wait(lock, [this] { return !_stop; }); | ||||
|  | ||||
|         auto msg = _queue.front(); | ||||
|         _queue.pop(); | ||||
|         return msg; | ||||
|     } | ||||
|  | ||||
|     void QueueManager::add(Json::Value msg) | ||||
|     { | ||||
|         std::unique_lock<std::mutex> lock(_mutex); | ||||
|  | ||||
|         // if the sending is not fast enough there is no point | ||||
|         // in queuing too many events. | ||||
|         if (_queue.size() < _maxQueueSize) | ||||
|         { | ||||
|             _queue.push(msg); | ||||
|             _condition.notify_one(); | ||||
|         } | ||||
|     } | ||||
| } // namespace | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     // fields are command line argument that can be specified multiple times | ||||
| @@ -133,118 +80,87 @@ namespace ix | ||||
|  | ||||
|         auto tokens = parseFields(fields); | ||||
|  | ||||
|         Json::FastWriter jsonWriter; | ||||
|         std::atomic<uint64_t> sentCount(0); | ||||
|         std::atomic<uint64_t> receivedCount(0); | ||||
|         std::atomic<bool> stop(false); | ||||
|  | ||||
|         size_t maxQueueSize = 1000; | ||||
|         QueueManager queueManager(maxQueueSize, stop); | ||||
|  | ||||
|         auto timer = [&sentCount, &receivedCount] { | ||||
|             while (true) | ||||
|             { | ||||
|                 spdlog::info("messages received {} sent {}", receivedCount, sentCount); | ||||
|  | ||||
|                 auto duration = std::chrono::seconds(1); | ||||
|                 std::this_thread::sleep_for(duration); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         std::thread t1(timer); | ||||
|  | ||||
|         auto statsdSender = [&queueManager, &host, &port, &sentCount, &tokens, &prefix, &stop] { | ||||
|             // statsd client | ||||
|             // test with netcat as a server: `nc -ul 8125` | ||||
|             bool statsdBatch = true; | ||||
|         // statsd client | ||||
|         // test with netcat as a server: `nc -ul 8125` | ||||
|         bool statsdBatch = true; | ||||
| #ifndef _WIN32 | ||||
|             statsd::StatsdClient statsdClient(host, port, prefix, statsdBatch); | ||||
|         statsd::StatsdClient statsdClient(host, port, prefix, statsdBatch); | ||||
| #else | ||||
|             int statsdClient; | ||||
|         int statsdClient; | ||||
| #endif | ||||
|             while (true) | ||||
|  | ||||
|         Json::FastWriter jsonWriter; | ||||
|         uint64_t msgCount = 0; | ||||
|  | ||||
|         conn.setEventCallback([&conn, | ||||
|                                &channel, | ||||
|                                &filter, | ||||
|                                &jsonWriter, | ||||
|                                &statsdClient, | ||||
|                                verbose, | ||||
|                                &tokens, | ||||
|                                &prefix, | ||||
|                                &msgCount](ix::CobraConnectionEventType eventType, | ||||
|                                           const std::string& errMsg, | ||||
|                                           const ix::WebSocketHttpHeaders& headers, | ||||
|                                           const std::string& subscriptionId, | ||||
|                                           CobraConnection::MsgId msgId) { | ||||
|             if (eventType == ix::CobraConnection_EventType_Open) | ||||
|             { | ||||
|                 Json::Value msg = queueManager.pop(); | ||||
|                 spdlog::info("Subscriber connected"); | ||||
|  | ||||
|                 if (msg.isNull()) continue; | ||||
|                 if (stop) return; | ||||
|  | ||||
|                 std::string id; | ||||
|                 for (auto&& attr : tokens) | ||||
|                 for (auto it : headers) | ||||
|                 { | ||||
|                     id += "."; | ||||
|                     id += extractAttr(attr, msg); | ||||
|                     spdlog::info("{}: {}", it.first, it.second); | ||||
|                 } | ||||
|             } | ||||
|             if (eventType == ix::CobraConnection_EventType_Closed) | ||||
|             { | ||||
|                 spdlog::info("Subscriber closed"); | ||||
|             } | ||||
|             else if (eventType == ix::CobraConnection_EventType_Authenticated) | ||||
|             { | ||||
|                 spdlog::info("Subscriber authenticated"); | ||||
|                 conn.subscribe(channel, | ||||
|                                filter, | ||||
|                                [&jsonWriter, &statsdClient, verbose, &tokens, &prefix, &msgCount]( | ||||
|                                    const Json::Value& msg) { | ||||
|                                    if (verbose) | ||||
|                                    { | ||||
|                                        spdlog::info(jsonWriter.write(msg)); | ||||
|                                    } | ||||
|  | ||||
|                 sentCount += 1; | ||||
|                                    std::string id; | ||||
|                                    for (auto&& attr : tokens) | ||||
|                                    { | ||||
|                                        id += "."; | ||||
|                                        id += extractAttr(attr, msg); | ||||
|                                    } | ||||
|  | ||||
|                                    spdlog::info("{} {}{}", msgCount++, prefix, id); | ||||
|  | ||||
| #ifndef _WIN32 | ||||
|                 statsdClient.count(id, 1); | ||||
|                                    statsdClient.count(id, 1); | ||||
| #endif | ||||
|                                }); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         std::thread t2(statsdSender); | ||||
|  | ||||
|         conn.setEventCallback( | ||||
|             [&conn, &channel, &filter, &jsonWriter, verbose, &queueManager, &receivedCount]( | ||||
|                 ix::CobraConnectionEventType eventType, | ||||
|                 const std::string& errMsg, | ||||
|                 const ix::WebSocketHttpHeaders& headers, | ||||
|                 const std::string& subscriptionId, | ||||
|                 CobraConnection::MsgId msgId) { | ||||
|                 if (eventType == ix::CobraConnection_EventType_Open) | ||||
|                 { | ||||
|                     spdlog::info("Subscriber connected"); | ||||
|  | ||||
|                     for (auto it : headers) | ||||
|                     { | ||||
|                         spdlog::info("{}: {}", it.first, it.second); | ||||
|                     } | ||||
|                 } | ||||
|                 if (eventType == ix::CobraConnection_EventType_Closed) | ||||
|                 { | ||||
|                     spdlog::info("Subscriber closed"); | ||||
|                 } | ||||
|                 else if (eventType == ix::CobraConnection_EventType_Authenticated) | ||||
|                 { | ||||
|                     spdlog::info("Subscriber authenticated"); | ||||
|                     conn.subscribe(channel, | ||||
|                                    filter, | ||||
|                                    [&jsonWriter, &queueManager, verbose, &receivedCount]( | ||||
|                                        const Json::Value& msg) { | ||||
|                                        if (verbose) | ||||
|                                        { | ||||
|                                            spdlog::info(jsonWriter.write(msg)); | ||||
|                                        } | ||||
|  | ||||
|                                        receivedCount++; | ||||
|  | ||||
|                                        ++receivedCount; | ||||
|                                        queueManager.add(msg); | ||||
|                                    }); | ||||
|                 } | ||||
|                 else if (eventType == ix::CobraConnection_EventType_Subscribed) | ||||
|                 { | ||||
|                     spdlog::info("Subscriber: subscribed to channel {}", subscriptionId); | ||||
|                 } | ||||
|                 else if (eventType == ix::CobraConnection_EventType_UnSubscribed) | ||||
|                 { | ||||
|                     spdlog::info("Subscriber: unsubscribed from channel {}", subscriptionId); | ||||
|                 } | ||||
|                 else if (eventType == ix::CobraConnection_EventType_Error) | ||||
|                 { | ||||
|                     spdlog::error("Subscriber: error {}", errMsg); | ||||
|                 } | ||||
|                 else if (eventType == ix::CobraConnection_EventType_Published) | ||||
|                 { | ||||
|                     spdlog::error("Published message hacked: {}", msgId); | ||||
|                 } | ||||
|                 else if (eventType == ix::CobraConnection_EventType_Pong) | ||||
|                 { | ||||
|                     spdlog::info("Received websocket pong"); | ||||
|                 } | ||||
|             }); | ||||
|             else if (eventType == ix::CobraConnection_EventType_Subscribed) | ||||
|             { | ||||
|                 spdlog::info("Subscriber: subscribed to channel {}", subscriptionId); | ||||
|             } | ||||
|             else if (eventType == ix::CobraConnection_EventType_UnSubscribed) | ||||
|             { | ||||
|                 spdlog::info("Subscriber: unsubscribed from channel {}", subscriptionId); | ||||
|             } | ||||
|             else if (eventType == ix::CobraConnection_EventType_Error) | ||||
|             { | ||||
|                 spdlog::error("Subscriber: error {}", errMsg); | ||||
|             } | ||||
|             else if (eventType == ix::CobraConnection_EventType_Published) | ||||
|             { | ||||
|                 spdlog::error("Published message hacked: {}", msgId); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         while (true) | ||||
|         { | ||||
|   | ||||
| @@ -5,10 +5,10 @@ | ||||
|  */ | ||||
|  | ||||
| #include "linenoise.hpp" | ||||
| #include <iostream> | ||||
| #include <ixwebsocket/IXSocket.h> | ||||
| #include <ixwebsocket/IXSocketTLSOptions.h> | ||||
| #include <ixwebsocket/IXWebSocket.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
|  | ||||
|  | ||||
| @@ -93,7 +93,7 @@ namespace ix | ||||
|             auto key = token.substr(0, pos); | ||||
|             auto val = token.substr(pos + 1); | ||||
|  | ||||
|             spdlog::info("{}: {}", key, val); | ||||
|             std::cerr << key << ": " << val << std::endl; | ||||
|             headers[key] = val; | ||||
|         } | ||||
|  | ||||
| @@ -129,11 +129,11 @@ namespace ix | ||||
|             if (msg->type == ix::WebSocketMessageType::Open) | ||||
|             { | ||||
|                 log("ws_connect: connected"); | ||||
|                 spdlog::info("Uri: {}", msg->openInfo.uri); | ||||
|                 spdlog::info("Headers:"); | ||||
|                 std::cout << "Uri: " << msg->openInfo.uri << std::endl; | ||||
|                 std::cout << "Handshake Headers:" << std::endl; | ||||
|                 for (auto it : msg->openInfo.headers) | ||||
|                 { | ||||
|                     spdlog::info("{}: {}", it.first, it.second); | ||||
|                     std::cout << it.first << ": " << it.second << std::endl; | ||||
|                 } | ||||
|             } | ||||
|             else if (msg->type == ix::WebSocketMessageType::Close) | ||||
| @@ -145,7 +145,7 @@ namespace ix | ||||
|             } | ||||
|             else if (msg->type == ix::WebSocketMessageType::Message) | ||||
|             { | ||||
|                 spdlog::info("Received {} bytes", msg->wireSize); | ||||
|                 std::cerr << "Received " << msg->wireSize << " bytes" << std::endl; | ||||
|  | ||||
|                 ss << "ws_connect: received message: " << msg->str; | ||||
|                 log(ss.str()); | ||||
| @@ -160,15 +160,15 @@ namespace ix | ||||
|             } | ||||
|             else if (msg->type == ix::WebSocketMessageType::Fragment) | ||||
|             { | ||||
|                 spdlog::info("Received message fragment"); | ||||
|                 std::cerr << "Received message fragment" << std::endl; | ||||
|             } | ||||
|             else if (msg->type == ix::WebSocketMessageType::Ping) | ||||
|             { | ||||
|                 spdlog::info("Received ping"); | ||||
|                 std::cerr << "Received ping" << std::endl; | ||||
|             } | ||||
|             else if (msg->type == ix::WebSocketMessageType::Pong) | ||||
|             { | ||||
|                 spdlog::info("Received pong"); | ||||
|                 std::cerr << "Received pong" << std::endl; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
| @@ -225,14 +225,14 @@ namespace ix | ||||
|  | ||||
|             if (line == "/stop") | ||||
|             { | ||||
|                 spdlog::info("Stopping connection..."); | ||||
|                 std::cout << "Stopping connection..." << std::endl; | ||||
|                 webSocketChat.stop(); | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if (line == "/start") | ||||
|             { | ||||
|                 spdlog::info("Starting connection..."); | ||||
|                 std::cout << "Starting connection..." << std::endl; | ||||
|                 webSocketChat.start(); | ||||
|                 continue; | ||||
|             } | ||||
| @@ -243,7 +243,7 @@ namespace ix | ||||
|             linenoise::AddHistory(line.c_str()); | ||||
|         } | ||||
|  | ||||
|         spdlog::info(""); | ||||
|         std::cout << std::endl; | ||||
|         webSocketChat.stop(); | ||||
|  | ||||
|         return 0; | ||||
|   | ||||
| @@ -4,8 +4,8 @@ | ||||
|  *  Copyright (c) 2018 Machine Zone, Inc. All rights reserved. | ||||
|  */ | ||||
|  | ||||
| #include <iostream> | ||||
| #include <ixwebsocket/IXWebSocketServer.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
|  | ||||
| namespace ix | ||||
| @@ -15,7 +15,7 @@ namespace ix | ||||
|                             const std::string& hostname, | ||||
|                             const ix::SocketTLSOptions& tlsOptions) | ||||
|     { | ||||
|         spdlog::info("Listening on {}:{}", hostname, port); | ||||
|         std::cout << "Listening on " << hostname << ":" << port << std::endl; | ||||
|  | ||||
|         ix::WebSocketServer server(port, hostname); | ||||
|         server.setTLSOptions(tlsOptions); | ||||
| @@ -27,13 +27,13 @@ namespace ix | ||||
|                     [webSocket, connectionState, greetings](const WebSocketMessagePtr& msg) { | ||||
|                         if (msg->type == ix::WebSocketMessageType::Open) | ||||
|                         { | ||||
|                             spdlog::info("New connection"); | ||||
|                             spdlog::info("id: {}", connectionState->getId()); | ||||
|                             spdlog::info("Uri: {}", msg->openInfo.uri); | ||||
|                             spdlog::info("Headers:"); | ||||
|                             std::cerr << "New connection" << std::endl; | ||||
|                             std::cerr << "id: " << connectionState->getId() << std::endl; | ||||
|                             std::cerr << "Uri: " << msg->openInfo.uri << std::endl; | ||||
|                             std::cerr << "Headers:" << std::endl; | ||||
|                             for (auto it : msg->openInfo.headers) | ||||
|                             { | ||||
|                                 spdlog::info("{}: {}", it.first, it.second); | ||||
|                                 std::cerr << it.first << ": " << it.second << std::endl; | ||||
|                             } | ||||
|  | ||||
|                             if (greetings) | ||||
| @@ -43,21 +43,22 @@ namespace ix | ||||
|                         } | ||||
|                         else if (msg->type == ix::WebSocketMessageType::Close) | ||||
|                         { | ||||
|                             spdlog::info("Closed connection: client id {} code {} reason {}", | ||||
|                                          connectionState->getId(), | ||||
|                                          msg->closeInfo.code, | ||||
|                                          msg->closeInfo.reason); | ||||
|                             std::cerr << "Closed connection" | ||||
|                                       << " code " << msg->closeInfo.code << " reason " | ||||
|                                       << msg->closeInfo.reason << std::endl; | ||||
|                         } | ||||
|                         else if (msg->type == ix::WebSocketMessageType::Error) | ||||
|                         { | ||||
|                             spdlog::error("Connection error: {}", msg->errorInfo.reason); | ||||
|                             spdlog::error("#retries: {}", msg->errorInfo.retries); | ||||
|                             spdlog::error("Wait time(ms): {}", msg->errorInfo.wait_time); | ||||
|                             spdlog::error("HTTP Status: {}", msg->errorInfo.http_status); | ||||
|                             std::stringstream ss; | ||||
|                             ss << "Connection error: " << msg->errorInfo.reason << std::endl; | ||||
|                             ss << "#retries: " << msg->errorInfo.retries << std::endl; | ||||
|                             ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl; | ||||
|                             ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl; | ||||
|                             std::cerr << ss.str(); | ||||
|                         } | ||||
|                         else if (msg->type == ix::WebSocketMessageType::Message) | ||||
|                         { | ||||
|                             spdlog::info("Received {} bytes", msg->wireSize); | ||||
|                             std::cerr << "Received " << msg->wireSize << " bytes" << std::endl; | ||||
|                             webSocket->send(msg->str, msg->binary); | ||||
|                         } | ||||
|                     }); | ||||
| @@ -66,7 +67,7 @@ namespace ix | ||||
|         auto res = server.listen(); | ||||
|         if (!res.first) | ||||
|         { | ||||
|             spdlog::error(res.second); | ||||
|             std::cerr << res.second << std::endl; | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -5,10 +5,10 @@ | ||||
|  */ | ||||
|  | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| #include <ixwebsocket/IXHttpClient.h> | ||||
| #include <ixwebsocket/IXSocketTLSOptions.h> | ||||
| #include <ixwebsocket/IXWebSocketHttpHeaders.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
|  | ||||
| namespace ix | ||||
| @@ -47,7 +47,7 @@ namespace ix | ||||
|             auto key = token.substr(0, pos); | ||||
|             auto val = token.substr(pos + 1); | ||||
|  | ||||
|             spdlog::info("{}: {}", key, val); | ||||
|             std::cerr << key << ": " << val << std::endl; | ||||
|             headers[key] = val; | ||||
|         } | ||||
|  | ||||
| @@ -76,7 +76,7 @@ namespace ix | ||||
|             auto key = token.substr(0, pos); | ||||
|             auto val = token.substr(pos + 1); | ||||
|  | ||||
|             spdlog::info("{}: {}", key, val); | ||||
|             std::cerr << key << ": " << val << std::endl; | ||||
|             httpParameters[key] = val; | ||||
|         } | ||||
|  | ||||
| @@ -108,9 +108,10 @@ namespace ix | ||||
|         args->maxRedirects = maxRedirects; | ||||
|         args->verbose = verbose; | ||||
|         args->compress = compress; | ||||
|         args->logger = [](const std::string& msg) { spdlog::info(msg); }; | ||||
|         args->logger = [](const std::string& msg) { std::cout << msg; }; | ||||
|         args->onProgressCallback = [](int current, int total) -> bool { | ||||
|             spdlog::info("Downloaded {} bytes out of {}", current, total); | ||||
|             std::cerr << "\r" | ||||
|                       << "Downloaded " << current << " bytes out of " << total; | ||||
|             return true; | ||||
|         }; | ||||
|  | ||||
| @@ -130,20 +131,20 @@ namespace ix | ||||
|             response = httpClient.post(url, httpParameters, args); | ||||
|         } | ||||
|  | ||||
|         spdlog::info(""); | ||||
|         std::cerr << std::endl; | ||||
|  | ||||
|         for (auto it : response->headers) | ||||
|         { | ||||
|             spdlog::info("{}: {}", it.first, it.second); | ||||
|             std::cerr << it.first << ": " << it.second << std::endl; | ||||
|         } | ||||
|  | ||||
|         spdlog::info("Upload size: {}", response->uploadSize); | ||||
|         spdlog::info("Download size: {}", response->downloadSize); | ||||
|         std::cerr << "Upload size: " << response->uploadSize << std::endl; | ||||
|         std::cerr << "Download size: " << response->downloadSize << std::endl; | ||||
|  | ||||
|         spdlog::info("Status: {}", response->statusCode); | ||||
|         std::cerr << "Status: " << response->statusCode << std::endl; | ||||
|         if (response->errorCode != HttpErrorCode::Ok) | ||||
|         { | ||||
|             spdlog::info("error message: ", response->errorMsg); | ||||
|             std::cerr << "error message: " << response->errorMsg << std::endl; | ||||
|         } | ||||
|  | ||||
|         if (!headersOnly && response->errorCode == HttpErrorCode::Ok) | ||||
| @@ -157,7 +158,7 @@ namespace ix | ||||
|                     filename = output; | ||||
|                 } | ||||
|  | ||||
|                 spdlog::info("Writing to disk: {}", filename); | ||||
|                 std::cout << "Writing to disk: " << filename << std::endl; | ||||
|                 std::ofstream out(filename); | ||||
|                 out.write((char*) &response->payload.front(), response->payload.size()); | ||||
|                 out.close(); | ||||
| @@ -166,13 +167,14 @@ namespace ix | ||||
|             { | ||||
|                 if (response->headers["Content-Type"] != "application/octet-stream") | ||||
|                 { | ||||
|                     spdlog::info("payload: {}", response->payload); | ||||
|                     std::cout << "payload: " << response->payload << std::endl; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     spdlog::info("Binary output can mess up your terminal."); | ||||
|                     spdlog::info("Use the -O flag to save the file to disk."); | ||||
|                     spdlog::info("You can also use the --output option to specify a filename."); | ||||
|                     std::cerr << "Binary output can mess up your terminal." << std::endl; | ||||
|                     std::cerr << "Use the -O flag to save the file to disk." << std::endl; | ||||
|                     std::cerr << "You can also use the --output option to specify a filename." | ||||
|                               << std::endl; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
|  */ | ||||
|  | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| #include <ixwebsocket/IXHttpServer.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
| @@ -31,7 +32,7 @@ namespace ix | ||||
|         auto res = server.listen(); | ||||
|         if (!res.first) | ||||
|         { | ||||
|             spdlog::error(res.second); | ||||
|             std::cerr << res.second << std::endl; | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,6 @@ | ||||
| #include <ixwebsocket/IXSocket.h> | ||||
| #include <ixwebsocket/IXSocketTLSOptions.h> | ||||
| #include <ixwebsocket/IXWebSocket.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
|  | ||||
| namespace ix | ||||
| @@ -41,7 +40,7 @@ namespace ix | ||||
|  | ||||
|     void WebSocketPingPong::log(const std::string& msg) | ||||
|     { | ||||
|         spdlog::info(msg); | ||||
|         std::cout << msg << std::endl; | ||||
|     } | ||||
|  | ||||
|     void WebSocketPingPong::stop() | ||||
| @@ -57,18 +56,18 @@ namespace ix | ||||
|         log(std::string("Connecting to url: ") + _url); | ||||
|  | ||||
|         _webSocket.setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) { | ||||
|             spdlog::info("Received {} bytes", msg->wireSize); | ||||
|             std::cerr << "Received " << msg->wireSize << " bytes" << std::endl; | ||||
|  | ||||
|             std::stringstream ss; | ||||
|             if (msg->type == ix::WebSocketMessageType::Open) | ||||
|             { | ||||
|                 log("ping_pong: connected"); | ||||
|  | ||||
|                 spdlog::info("Uri: {}", msg->openInfo.uri); | ||||
|                 spdlog::info("Headers:"); | ||||
|                 std::cout << "Uri: " << msg->openInfo.uri << std::endl; | ||||
|                 std::cout << "Handshake Headers:" << std::endl; | ||||
|                 for (auto it : msg->openInfo.headers) | ||||
|                 { | ||||
|                     spdlog::info("{}: {}", it.first, it.second); | ||||
|                     std::cout << it.first << ": " << it.second << std::endl; | ||||
|                 } | ||||
|             } | ||||
|             else if (msg->type == ix::WebSocketMessageType::Close) | ||||
| @@ -128,7 +127,7 @@ namespace ix | ||||
|  | ||||
|     int ws_ping_pong_main(const std::string& url, const ix::SocketTLSOptions& tlsOptions) | ||||
|     { | ||||
|         spdlog::info("Type Ctrl-D to exit prompt..."); | ||||
|         std::cout << "Type Ctrl-D to exit prompt..." << std::endl; | ||||
|         WebSocketPingPong webSocketPingPong(url, tlsOptions); | ||||
|         webSocketPingPong.start(); | ||||
|  | ||||
|   | ||||
| @@ -4,8 +4,8 @@ | ||||
|  *  Copyright (c) 2018 Machine Zone, Inc. All rights reserved. | ||||
|  */ | ||||
|  | ||||
| #include <iostream> | ||||
| #include <ixwebsocket/IXWebSocketServer.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
|  | ||||
| namespace ix | ||||
| @@ -44,7 +44,7 @@ namespace ix | ||||
|                              const std::string& remoteUrl, | ||||
|                              bool verbose) | ||||
|     { | ||||
|         spdlog::info("Listening on {}:{}", hostname, port); | ||||
|         std::cout << "Listening on " << hostname << ":" << port << std::endl; | ||||
|  | ||||
|         ix::WebSocketServer server(port, hostname); | ||||
|         server.setTLSOptions(tlsOptions); | ||||
| @@ -61,39 +61,41 @@ namespace ix | ||||
|  | ||||
|             // Server connection | ||||
|             state->webSocket().setOnMessageCallback([webSocket, state, verbose]( | ||||
|                                                         const WebSocketMessagePtr& msg) { | ||||
|                                                      const WebSocketMessagePtr& msg) { | ||||
|                 if (msg->type == ix::WebSocketMessageType::Open) | ||||
|                 { | ||||
|                     spdlog::info("New connection to remote server"); | ||||
|                     spdlog::info("id: {}", state->getId()); | ||||
|                     spdlog::info("Uri: {}", msg->openInfo.uri); | ||||
|                     spdlog::info("Headers:"); | ||||
|                     std::cerr << "New connection" << std::endl; | ||||
|                     std::cerr << "server id: " << state->getId() << std::endl; | ||||
|                     std::cerr << "Uri: " << msg->openInfo.uri << std::endl; | ||||
|                     std::cerr << "Headers:" << std::endl; | ||||
|                     for (auto it : msg->openInfo.headers) | ||||
|                     { | ||||
|                         spdlog::info("{}: {}", it.first, it.second); | ||||
|                         std::cerr << it.first << ": " << it.second << std::endl; | ||||
|                     } | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Close) | ||||
|                 { | ||||
|                     spdlog::info("Closed remote server connection: client id {} code {} reason {}", | ||||
|                                  state->getId(), | ||||
|                                  msg->closeInfo.code, | ||||
|                                  msg->closeInfo.reason); | ||||
|                     std::cerr << "Closed connection" | ||||
|                               << " code " << msg->closeInfo.code << " reason " | ||||
|                               << msg->closeInfo.reason << std::endl; | ||||
|                     webSocket->close(msg->closeInfo.code, msg->closeInfo.reason); | ||||
|                     state->setTerminated(); | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Error) | ||||
|                 { | ||||
|                     spdlog::error("Connection error: {}", msg->errorInfo.reason); | ||||
|                     spdlog::error("#retries: {}", msg->errorInfo.retries); | ||||
|                     spdlog::error("Wait time(ms): {}", msg->errorInfo.wait_time); | ||||
|                     spdlog::error("HTTP Status: {}", msg->errorInfo.http_status); | ||||
|                     std::stringstream ss; | ||||
|                     ss << "Connection error: " << msg->errorInfo.reason << std::endl; | ||||
|                     ss << "#retries: " << msg->errorInfo.retries << std::endl; | ||||
|                     ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl; | ||||
|                     ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl; | ||||
|                     std::cerr << ss.str(); | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Message) | ||||
|                 { | ||||
|                     spdlog::info("Received {} bytes from server", msg->wireSize); | ||||
|                     std::cerr << "Received " << msg->wireSize << " bytes from server" << std::endl; | ||||
|                     if (verbose) | ||||
|                     { | ||||
|                         spdlog::info("payload {}", msg->str); | ||||
|                         std::cerr << "payload " << msg->str << std::endl; | ||||
|                     } | ||||
|  | ||||
|                     webSocket->send(msg->str, msg->binary); | ||||
| @@ -101,67 +103,67 @@ namespace ix | ||||
|             }); | ||||
|  | ||||
|             // Client connection | ||||
|             webSocket->setOnMessageCallback( | ||||
|                 [state, remoteUrl, verbose](const WebSocketMessagePtr& msg) { | ||||
|                     if (msg->type == ix::WebSocketMessageType::Open) | ||||
|             webSocket->setOnMessageCallback([state, remoteUrl, verbose]( | ||||
|                                                 const WebSocketMessagePtr& msg) { | ||||
|                 if (msg->type == ix::WebSocketMessageType::Open) | ||||
|                 { | ||||
|                     std::cerr << "New connection" << std::endl; | ||||
|                     std::cerr << "client id: " << state->getId() << std::endl; | ||||
|                     std::cerr << "Uri: " << msg->openInfo.uri << std::endl; | ||||
|                     std::cerr << "Headers:" << std::endl; | ||||
|                     for (auto it : msg->openInfo.headers) | ||||
|                     { | ||||
|                         spdlog::info("New connection from client"); | ||||
|                         spdlog::info("id: {}", state->getId()); | ||||
|                         spdlog::info("Uri: {}", msg->openInfo.uri); | ||||
|                         spdlog::info("Headers:"); | ||||
|                         for (auto it : msg->openInfo.headers) | ||||
|                         { | ||||
|                             spdlog::info("{}: {}", it.first, it.second); | ||||
|                         } | ||||
|                         std::cerr << it.first << ": " << it.second << std::endl; | ||||
|                     } | ||||
|  | ||||
|                         // Connect to the 'real' server | ||||
|                         std::string url(remoteUrl); | ||||
|                         url += msg->openInfo.uri; | ||||
|                         state->webSocket().setUrl(url); | ||||
|                         state->webSocket().disableAutomaticReconnection(); | ||||
|                         state->webSocket().start(); | ||||
|                     // Connect to the 'real' server | ||||
|                     std::string url(remoteUrl); | ||||
|                     url += msg->openInfo.uri; | ||||
|                     state->webSocket().setUrl(url); | ||||
|                     state->webSocket().disableAutomaticReconnection(); | ||||
|                     state->webSocket().start(); | ||||
|  | ||||
|                         // we should sleep here for a bit until we've established the | ||||
|                         // connection with the remote server | ||||
|                         while (state->webSocket().getReadyState() != ReadyState::Open) | ||||
|                         { | ||||
|                             spdlog::info("waiting for server connection establishment"); | ||||
|                             std::this_thread::sleep_for(std::chrono::milliseconds(10)); | ||||
|                         } | ||||
|                         spdlog::info("server connection established"); | ||||
|                     } | ||||
|                     else if (msg->type == ix::WebSocketMessageType::Close) | ||||
|                     // we should sleep here for a bit until we've established the | ||||
|                     // connection with the remote server | ||||
|                     while (state->webSocket().getReadyState() != ReadyState::Open) | ||||
|                     { | ||||
|                         spdlog::info("Closed client connection: client id {} code {} reason {}", | ||||
|                                      state->getId(), | ||||
|                                      msg->closeInfo.code, | ||||
|                                      msg->closeInfo.reason); | ||||
|                         state->webSocket().close(msg->closeInfo.code, msg->closeInfo.reason); | ||||
|                         std::cerr << "waiting for server connection establishment" << std::endl; | ||||
|                         std::this_thread::sleep_for(std::chrono::milliseconds(10)); | ||||
|                     } | ||||
|                     else if (msg->type == ix::WebSocketMessageType::Error) | ||||
|                     std::cerr << "server connection established" << std::endl; | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Close) | ||||
|                 { | ||||
|                     std::cerr << "Closed connection" | ||||
|                               << " code " << msg->closeInfo.code << " reason " | ||||
|                               << msg->closeInfo.reason << std::endl; | ||||
|                     state->webSocket().close(msg->closeInfo.code, msg->closeInfo.reason); | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Error) | ||||
|                 { | ||||
|                     std::stringstream ss; | ||||
|                     ss << "Connection error: " << msg->errorInfo.reason << std::endl; | ||||
|                     ss << "#retries: " << msg->errorInfo.retries << std::endl; | ||||
|                     ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl; | ||||
|                     ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl; | ||||
|                     std::cerr << ss.str(); | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Message) | ||||
|                 { | ||||
|                     std::cerr << "Received " << msg->wireSize << " bytes from client" << std::endl; | ||||
|                     if (verbose) | ||||
|                     { | ||||
|                         spdlog::error("Connection error: {}", msg->errorInfo.reason); | ||||
|                         spdlog::error("#retries: {}", msg->errorInfo.retries); | ||||
|                         spdlog::error("Wait time(ms): {}", msg->errorInfo.wait_time); | ||||
|                         spdlog::error("HTTP Status: {}", msg->errorInfo.http_status); | ||||
|                         std::cerr << "payload " << msg->str << std::endl; | ||||
|                     } | ||||
|                     else if (msg->type == ix::WebSocketMessageType::Message) | ||||
|                     { | ||||
|                         spdlog::info("Received {} bytes from client", msg->wireSize); | ||||
|                         if (verbose) | ||||
|                         { | ||||
|                             spdlog::info("payload {}", msg->str); | ||||
|                         } | ||||
|  | ||||
|                         state->webSocket().send(msg->str, msg->binary); | ||||
|                     } | ||||
|                 }); | ||||
|                     state->webSocket().send(msg->str, msg->binary); | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         auto res = server.listen(); | ||||
|         if (!res.first) | ||||
|         { | ||||
|             spdlog::info(res.second); | ||||
|             std::cerr << res.second << std::endl; | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
| #include <chrono> | ||||
| #include <condition_variable> | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| #include <ixcrypto/IXBase64.h> | ||||
| #include <ixcrypto/IXHash.h> | ||||
| #include <ixcrypto/IXUuid.h> | ||||
| @@ -15,7 +16,6 @@ | ||||
| #include <ixwebsocket/IXWebSocket.h> | ||||
| #include <msgpack11/msgpack11.hpp> | ||||
| #include <mutex> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
| #include <vector> | ||||
|  | ||||
| @@ -75,12 +75,12 @@ namespace ix | ||||
|  | ||||
|     void WebSocketReceiver::log(const std::string& msg) | ||||
|     { | ||||
|         spdlog::info(msg); | ||||
|         std::cout << msg << std::endl; | ||||
|     } | ||||
|  | ||||
|     void WebSocketReceiver::waitForConnection() | ||||
|     { | ||||
|         spdlog::info("{}: Connecting...", "ws_receive"); | ||||
|         std::cout << "ws_receive: Connecting..." << std::endl; | ||||
|  | ||||
|         std::unique_lock<std::mutex> lock(_conditionVariableMutex); | ||||
|         _condition.wait(lock); | ||||
| @@ -88,7 +88,7 @@ namespace ix | ||||
|  | ||||
|     void WebSocketReceiver::waitForMessage() | ||||
|     { | ||||
|         spdlog::info("{}: Waiting for message...", "ws_receive"); | ||||
|         std::cout << "ws_receive: Waiting for message..." << std::endl; | ||||
|  | ||||
|         std::unique_lock<std::mutex> lock(_conditionVariableMutex); | ||||
|         _condition.wait(lock); | ||||
| @@ -124,7 +124,7 @@ namespace ix | ||||
|  | ||||
|     void WebSocketReceiver::handleMessage(const std::string& str) | ||||
|     { | ||||
|         spdlog::info("ws_receive: Received message: {}", str.size()); | ||||
|         std::cerr << "ws_receive: Received message: " << str.size() << std::endl; | ||||
|  | ||||
|         std::string errMsg; | ||||
|         MsgPack data = MsgPack::parse(str, errMsg); | ||||
| @@ -134,17 +134,17 @@ namespace ix | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         spdlog::info("id: {}", data["id"].string_value()); | ||||
|         std::cout << "id: " << data["id"].string_value() << std::endl; | ||||
|  | ||||
|         std::vector<uint8_t> content = data["content"].binary_items(); | ||||
|         spdlog::info("ws_receive: Content size: {}", content.size()); | ||||
|         std::cout << "ws_receive: Content size: " << content.size() << std::endl; | ||||
|  | ||||
|         // Validate checksum | ||||
|         uint64_t cksum = ix::djb2Hash(content); | ||||
|         auto cksumRef = data["djb2_hash"].string_value(); | ||||
|  | ||||
|         spdlog::info("ws_receive: Computed hash: {}", cksum); | ||||
|         spdlog::info("ws_receive: Reference hash: {}", cksumRef); | ||||
|         std::cout << "ws_receive: Computed hash: " << cksum << std::endl; | ||||
|         std::cout << "ws_receive: Reference hash: " << cksumRef << std::endl; | ||||
|  | ||||
|         if (std::to_string(cksum) != cksumRef) | ||||
|         { | ||||
| @@ -157,12 +157,12 @@ namespace ix | ||||
|  | ||||
|         std::string filenameTmp = filename + ".tmp"; | ||||
|  | ||||
|         spdlog::info("ws_receive: Writing to disk: {}", filenameTmp); | ||||
|         std::cout << "ws_receive: Writing to disk: " << filenameTmp << std::endl; | ||||
|         std::ofstream out(filenameTmp); | ||||
|         out.write((char*) &content.front(), content.size()); | ||||
|         out.close(); | ||||
|  | ||||
|         spdlog::info("ws_receive: Renaming {} to {}", filenameTmp, filename); | ||||
|         std::cout << "ws_receive: Renaming " << filenameTmp << " to " << filename << std::endl; | ||||
|         rename(filenameTmp.c_str(), filename.c_str()); | ||||
|  | ||||
|         std::map<MsgPack, MsgPack> pdu; | ||||
| @@ -170,7 +170,7 @@ namespace ix | ||||
|         pdu["id"] = data["id"]; | ||||
|         pdu["filename"] = data["filename"]; | ||||
|  | ||||
|         spdlog::info("Sending ack to sender"); | ||||
|         std::cout << "Sending ack to sender" << std::endl; | ||||
|         MsgPack msg(pdu); | ||||
|         _webSocket.sendBinary(msg.dump()); | ||||
|     } | ||||
| @@ -192,11 +192,11 @@ namespace ix | ||||
|                 _condition.notify_one(); | ||||
|  | ||||
|                 log("ws_receive: connected"); | ||||
|                 spdlog::info("Uri: {}", msg->openInfo.uri); | ||||
|                 spdlog::info("Headers:"); | ||||
|                 std::cout << "Uri: " << msg->openInfo.uri << std::endl; | ||||
|                 std::cout << "Handshake Headers:" << std::endl; | ||||
|                 for (auto it : msg->openInfo.headers) | ||||
|                 { | ||||
|                     spdlog::info("{}: {}", it.first, it.second); | ||||
|                     std::cout << it.first << ": " << it.second << std::endl; | ||||
|                 } | ||||
|             } | ||||
|             else if (msg->type == ix::WebSocketMessageType::Close) | ||||
| @@ -259,7 +259,7 @@ namespace ix | ||||
|         std::chrono::duration<double, std::milli> duration(1000); | ||||
|         std::this_thread::sleep_for(duration); | ||||
|  | ||||
|         spdlog::info("ws_receive: Done !"); | ||||
|         std::cout << "ws_receive: Done !" << std::endl; | ||||
|         webSocketReceiver.stop(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -4,8 +4,8 @@ | ||||
|  *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved. | ||||
|  */ | ||||
|  | ||||
| #include <iostream> | ||||
| #include <ixsnake/IXRedisClient.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
|  | ||||
| namespace ix | ||||
| @@ -20,7 +20,7 @@ namespace ix | ||||
|         RedisClient redisClient; | ||||
|         if (!redisClient.connect(hostname, port)) | ||||
|         { | ||||
|             spdlog::info("Cannot connect to redis host"); | ||||
|             std::cerr << "Cannot connect to redis host" << std::endl; | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
| @@ -30,10 +30,10 @@ namespace ix | ||||
|             if (!redisClient.auth(password, authResponse)) | ||||
|             { | ||||
|                 std::stringstream ss; | ||||
|                 spdlog::info("Cannot authenticated to redis"); | ||||
|                 std::cerr << "Cannot authenticated to redis" << std::endl; | ||||
|                 return 1; | ||||
|             } | ||||
|             spdlog::info("Auth response: {}", authResponse); | ||||
|             std::cout << "Auth response: " << authResponse << ":" << port << std::endl; | ||||
|         } | ||||
|  | ||||
|         std::string errMsg; | ||||
| @@ -41,7 +41,8 @@ namespace ix | ||||
|         { | ||||
|             if (!redisClient.publish(channel, message, errMsg)) | ||||
|             { | ||||
|                 spdlog::error("Error publishing to channel {} error {}", channel, errMsg); | ||||
|                 std::cerr << "Error publishing to channel " << channel << "error: " << errMsg | ||||
|                           << std::endl; | ||||
|                 return 1; | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|  *  Copyright (c) 2019 Machine Zone, Inc. All rights reserved. | ||||
|  */ | ||||
|  | ||||
| #include <iostream> | ||||
| #include <ixsnake/IXRedisServer.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
| @@ -19,7 +20,7 @@ namespace ix | ||||
|         auto res = server.listen(); | ||||
|         if (!res.first) | ||||
|         { | ||||
|             spdlog::info(res.second); | ||||
|             std::cerr << res.second << std::endl; | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -6,8 +6,8 @@ | ||||
|  | ||||
| #include <atomic> | ||||
| #include <chrono> | ||||
| #include <iostream> | ||||
| #include <ixsnake/IXRedisClient.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
| #include <thread> | ||||
|  | ||||
| @@ -22,7 +22,7 @@ namespace ix | ||||
|         RedisClient redisClient; | ||||
|         if (!redisClient.connect(hostname, port)) | ||||
|         { | ||||
|             spdlog::info("Cannot connect to redis host"); | ||||
|             std::cerr << "Cannot connect to redis host" << std::endl; | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
| @@ -32,10 +32,10 @@ namespace ix | ||||
|             if (!redisClient.auth(password, authResponse)) | ||||
|             { | ||||
|                 std::stringstream ss; | ||||
|                 spdlog::info("Cannot authenticated to redis"); | ||||
|                 std::cerr << "Cannot authenticated to redis" << std::endl; | ||||
|                 return 1; | ||||
|             } | ||||
|             spdlog::info("Auth response: {}", authResponse); | ||||
|             std::cout << "Auth response: " << authResponse << ":" << port << std::endl; | ||||
|         } | ||||
|  | ||||
|         std::atomic<int> msgPerSeconds(0); | ||||
| @@ -44,7 +44,7 @@ namespace ix | ||||
|         auto callback = [&msgPerSeconds, &msgCount, verbose](const std::string& message) { | ||||
|             if (verbose) | ||||
|             { | ||||
|                 spdlog::info("recived: {}", message); | ||||
|                 std::cout << "received: " << message << std::endl; | ||||
|             } | ||||
|  | ||||
|             msgPerSeconds++; | ||||
| @@ -52,13 +52,14 @@ namespace ix | ||||
|         }; | ||||
|  | ||||
|         auto responseCallback = [](const std::string& redisResponse) { | ||||
|             spdlog::info("Redis subscribe response: {}", redisResponse); | ||||
|             std::cout << "Redis subscribe response: " << redisResponse << std::endl; | ||||
|         }; | ||||
|  | ||||
|         auto timer = [&msgPerSeconds, &msgCount] { | ||||
|             while (true) | ||||
|             { | ||||
|                 spdlog::info("#messages {} msg/s {}", msgCount, msgPerSeconds); | ||||
|                 std::cout << "#messages " << msgCount << " " | ||||
|                           << "msg/s " << msgPerSeconds << std::endl; | ||||
|  | ||||
|                 msgPerSeconds = 0; | ||||
|                 auto duration = std::chrono::seconds(1); | ||||
| @@ -68,10 +69,10 @@ namespace ix | ||||
|  | ||||
|         std::thread t(timer); | ||||
|  | ||||
|         spdlog::info("Subscribing to {} ...", channel); | ||||
|         std::cerr << "Subscribing to " << channel << "..." << std::endl; | ||||
|         if (!redisClient.subscribe(channel, responseCallback, callback)) | ||||
|         { | ||||
|             spdlog::info("Error subscribing to channel {}", channel); | ||||
|             std::cerr << "Error subscribing to channel " << channel << std::endl; | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
| #include <chrono> | ||||
| #include <condition_variable> | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| #include <ixcrypto/IXBase64.h> | ||||
| #include <ixcrypto/IXHash.h> | ||||
| #include <ixcrypto/IXUuid.h> | ||||
| @@ -15,7 +16,6 @@ | ||||
| #include <ixwebsocket/IXWebSocket.h> | ||||
| #include <msgpack11/msgpack11.hpp> | ||||
| #include <mutex> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
| #include <vector> | ||||
|  | ||||
| @@ -68,12 +68,12 @@ namespace ix | ||||
|  | ||||
|     void WebSocketSender::log(const std::string& msg) | ||||
|     { | ||||
|         spdlog::info(msg); | ||||
|         std::cout << msg << std::endl; | ||||
|     } | ||||
|  | ||||
|     void WebSocketSender::waitForConnection() | ||||
|     { | ||||
|         spdlog::info("{}: Connecting...", "ws_send"); | ||||
|         std::cout << "ws_send: Connecting..." << std::endl; | ||||
|  | ||||
|         std::unique_lock<std::mutex> lock(_conditionVariableMutex); | ||||
|         _condition.wait(lock); | ||||
| @@ -81,7 +81,7 @@ namespace ix | ||||
|  | ||||
|     void WebSocketSender::waitForAck() | ||||
|     { | ||||
|         spdlog::info("{}: Waiting for ack...", "ws_send"); | ||||
|         std::cout << "ws_send: Waiting for ack..." << std::endl; | ||||
|  | ||||
|         std::unique_lock<std::mutex> lock(_conditionVariableMutex); | ||||
|         _condition.wait(lock); | ||||
| @@ -122,11 +122,11 @@ namespace ix | ||||
|                 _condition.notify_one(); | ||||
|  | ||||
|                 log("ws_send: connected"); | ||||
|                 spdlog::info("Uri: {}", msg->openInfo.uri); | ||||
|                 spdlog::info("Headers:"); | ||||
|                 std::cout << "Uri: " << msg->openInfo.uri << std::endl; | ||||
|                 std::cout << "Handshake Headers:" << std::endl; | ||||
|                 for (auto it : msg->openInfo.headers) | ||||
|                 { | ||||
|                     spdlog::info("{}: {}", it.first, it.second); | ||||
|                     std::cout << it.first << ": " << it.second << std::endl; | ||||
|                 } | ||||
|             } | ||||
|             else if (msg->type == ix::WebSocketMessageType::Close) | ||||
| @@ -147,14 +147,14 @@ namespace ix | ||||
|                 MsgPack data = MsgPack::parse(msg->str, errMsg); | ||||
|                 if (!errMsg.empty()) | ||||
|                 { | ||||
|                     spdlog::info("Invalid MsgPack response"); | ||||
|                     std::cerr << "Invalid MsgPack response" << std::endl; | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 std::string id = data["id"].string_value(); | ||||
|                 if (_id != id) | ||||
|                 { | ||||
|                     spdlog::info("Invalid id"); | ||||
|                     std::cerr << "Invalid id" << std::endl; | ||||
|                 } | ||||
|             } | ||||
|             else if (msg->type == ix::WebSocketMessageType::Error) | ||||
| @@ -201,7 +201,7 @@ namespace ix | ||||
|             auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now - _start); | ||||
|  | ||||
|             _ms = milliseconds.count(); | ||||
|             spdlog::info("{} completed in {}", _description, _ms); | ||||
|             std::cout << _description << " completed in " << _ms << "ms" << std::endl; | ||||
|  | ||||
|             _reported = true; | ||||
|         } | ||||
| @@ -240,7 +240,7 @@ namespace ix | ||||
|  | ||||
|         Bench bench("Sending file through websocket"); | ||||
|         _webSocket.sendBinary(msg.dump(), [throttle](int current, int total) -> bool { | ||||
|             spdlog::info("ws_send: Step {} out of {}", current, total); | ||||
|             std::cout << "ws_send: Step " << current << " out of " << total << std::endl; | ||||
|  | ||||
|             if (throttle) | ||||
|             { | ||||
| @@ -254,7 +254,7 @@ namespace ix | ||||
|         do | ||||
|         { | ||||
|             size_t bufferedAmount = _webSocket.bufferedAmount(); | ||||
|             spdlog::info("ws_send: {} bytes left to be sent", bufferedAmount); | ||||
|             std::cout << "ws_send: " << bufferedAmount << " bytes left to be sent" << std::endl; | ||||
|  | ||||
|             std::chrono::duration<double, std::milli> duration(10); | ||||
|             std::this_thread::sleep_for(duration); | ||||
| @@ -264,7 +264,7 @@ namespace ix | ||||
|         auto duration = bench.getDuration(); | ||||
|         auto transferRate = 1000 * content.size() / duration; | ||||
|         transferRate /= (1024 * 1024); | ||||
|         spdlog::info("ws_send: Send transfer rate: {} MB/s", transferRate); | ||||
|         std::cout << "ws_send: Send transfer rate: " << transferRate << "MB/s" << std::endl; | ||||
|     } | ||||
|  | ||||
|     void wsSend(const std::string& url, | ||||
| @@ -278,12 +278,12 @@ namespace ix | ||||
|  | ||||
|         webSocketSender.waitForConnection(); | ||||
|  | ||||
|         spdlog::info("ws_send: Sending..."); | ||||
|         std::cout << "ws_send: Sending..." << std::endl; | ||||
|         webSocketSender.sendMessage(path, throttle); | ||||
|  | ||||
|         webSocketSender.waitForAck(); | ||||
|  | ||||
|         spdlog::info("ws_send: Done !"); | ||||
|         std::cout << "ws_send: Done !" << std::endl; | ||||
|         webSocketSender.stop(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -5,8 +5,8 @@ | ||||
|  */ | ||||
|  | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| #include <ixsnake/IXSnakeServer.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
|  | ||||
| namespace | ||||
| @@ -58,11 +58,11 @@ namespace ix | ||||
|         auto str = readAsString(appsConfigPath); | ||||
|         if (str.empty()) | ||||
|         { | ||||
|             spdlog::error("Cannot read content of {}", appsConfigPath); | ||||
|             std::cout << "Cannot read content of " << appsConfigPath << std::endl; | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|         spdlog::error(str); | ||||
|         std::cout << str << std::endl; | ||||
|         auto apps = nlohmann::json::parse(str); | ||||
|         appConfig.apps = apps["apps"]; | ||||
|  | ||||
|   | ||||
| @@ -4,8 +4,8 @@ | ||||
|  *  Copyright (c) 2018 Machine Zone, Inc. All rights reserved. | ||||
|  */ | ||||
|  | ||||
| #include <iostream> | ||||
| #include <ixwebsocket/IXWebSocketServer.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sstream> | ||||
|  | ||||
| namespace ix | ||||
| @@ -14,7 +14,7 @@ namespace ix | ||||
|                          const std::string& hostname, | ||||
|                          const ix::SocketTLSOptions& tlsOptions) | ||||
|     { | ||||
|         spdlog::info("Listening on {}:{}", hostname, port); | ||||
|         std::cout << "ws_transfer: Listening on " << hostname << ":" << port << std::endl; | ||||
|  | ||||
|         ix::WebSocketServer server(port, hostname); | ||||
|         server.setTLSOptions(tlsOptions); | ||||
| @@ -25,23 +25,22 @@ namespace ix | ||||
|                                                 const WebSocketMessagePtr& msg) { | ||||
|                 if (msg->type == ix::WebSocketMessageType::Open) | ||||
|                 { | ||||
|                     spdlog::info("ws_transfer: New connection"); | ||||
|                     spdlog::info("id: {}", connectionState->getId()); | ||||
|                     spdlog::info("Uri: {}", msg->openInfo.uri); | ||||
|                     spdlog::info("Headers:"); | ||||
|                     std::cerr << "ws_transfer: New connection" << std::endl; | ||||
|                     std::cerr << "id: " << connectionState->getId() << std::endl; | ||||
|                     std::cerr << "Uri: " << msg->openInfo.uri << std::endl; | ||||
|                     std::cerr << "Headers:" << std::endl; | ||||
|                     for (auto it : msg->openInfo.headers) | ||||
|                     { | ||||
|                         spdlog::info("{}: {}", it.first, it.second); | ||||
|                         std::cerr << it.first << ": " << it.second << std::endl; | ||||
|                     } | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Close) | ||||
|                 { | ||||
|                     spdlog::info("ws_transfer: Closed connection: client id {} code {} reason {}", | ||||
|                                  connectionState->getId(), | ||||
|                                  msg->closeInfo.code, | ||||
|                                  msg->closeInfo.reason); | ||||
|                     std::cerr << "ws_transfer: [client " << connectionState->getId() | ||||
|                               << "]: Closed connection, code " << msg->closeInfo.code << " reason " | ||||
|                               << msg->closeInfo.reason << std::endl; | ||||
|                     auto remaining = server.getClients().erase(webSocket); | ||||
|                     spdlog::info("ws_transfer: {} remaining clients", remaining); | ||||
|                     std::cerr << "ws_transfer: " << remaining << " remaining clients " << std::endl; | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Error) | ||||
|                 { | ||||
| @@ -50,43 +49,40 @@ namespace ix | ||||
|                     ss << "#retries: " << msg->errorInfo.retries << std::endl; | ||||
|                     ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl; | ||||
|                     ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl; | ||||
|                     spdlog::info(ss.str()); | ||||
|                     std::cerr << ss.str(); | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Fragment) | ||||
|                 { | ||||
|                     spdlog::info("ws_transfer: Received message fragment "); | ||||
|                     std::cerr << "ws_transfer: Received message fragment " << std::endl; | ||||
|                 } | ||||
|                 else if (msg->type == ix::WebSocketMessageType::Message) | ||||
|                 { | ||||
|                     spdlog::info("ws_transfer: Received {} bytes", msg->wireSize); | ||||
|                     std::cerr << "ws_transfer: Received " << msg->wireSize << " bytes" << std::endl; | ||||
|                     size_t receivers = 0; | ||||
|                     for (auto&& client : server.getClients()) | ||||
|                     { | ||||
|                         if (client != webSocket) | ||||
|                         { | ||||
|                             auto readyState = client->getReadyState(); | ||||
|                             auto id = connectionState->getId(); | ||||
|  | ||||
|                             if (readyState == ReadyState::Open) | ||||
|                             { | ||||
|                                 ++receivers; | ||||
|                                 client->send( | ||||
|                                     msg->str, msg->binary, [&id](int current, int total) -> bool { | ||||
|                                         spdlog::info("{}: [client {}]: Step {} out of {}", | ||||
|                                                      "ws_transfer", | ||||
|                                                      id, | ||||
|                                                      current, | ||||
|                                                      total); | ||||
|                                         return true; | ||||
|                                     }); | ||||
|                                 client->send(msg->str, | ||||
|                                              msg->binary, | ||||
|                                              [id = connectionState->getId()](int current, | ||||
|                                                                              int total) -> bool { | ||||
|                                                  std::cerr << "ws_transfer: [client " << id | ||||
|                                                            << "]: Step " << current << " out of " | ||||
|                                                            << total << std::endl; | ||||
|                                                  return true; | ||||
|                                              }); | ||||
|  | ||||
|                                 do | ||||
|                                 { | ||||
|                                     size_t bufferedAmount = client->bufferedAmount(); | ||||
|  | ||||
|                                     spdlog::info("{}: [client {}]: {} bytes left to send", | ||||
|                                                  "ws_transfer", | ||||
|                                                  id, | ||||
|                                                  bufferedAmount); | ||||
|                                     std::cerr << "ws_transfer: [client " << connectionState->getId() | ||||
|                                               << "]: " << bufferedAmount | ||||
|                                               << " bytes left to be sent, " << std::endl; | ||||
|  | ||||
|                                     std::this_thread::sleep_for(std::chrono::milliseconds(500)); | ||||
|  | ||||
| @@ -100,19 +96,16 @@ namespace ix | ||||
|                                         ? "Connecting" | ||||
|                                         : readyState == ReadyState::Closing ? "Closing" : "Closed"; | ||||
|                                 size_t bufferedAmount = client->bufferedAmount(); | ||||
|  | ||||
|                                 spdlog::info( | ||||
|                                     "{}: [client {}]: has readystate {} bytes left to be sent", | ||||
|                                     "ws_transfer", | ||||
|                                     id, | ||||
|                                     readyStateString, | ||||
|                                     bufferedAmount); | ||||
|                                 std::cerr << "ws_transfer: [client " << connectionState->getId() | ||||
|                                           << "]: has readystate '" << readyStateString << "' and " | ||||
|                                           << bufferedAmount << " bytes left to be sent, " | ||||
|                                           << std::endl; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     if (!receivers) | ||||
|                     { | ||||
|                         spdlog::info("ws_transfer: no remaining receivers"); | ||||
|                         std::cerr << "ws_transfer: no remaining receivers" << std::endl; | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
| @@ -121,7 +114,7 @@ namespace ix | ||||
|         auto res = server.listen(); | ||||
|         if (!res.first) | ||||
|         { | ||||
|             spdlog::info(res.second); | ||||
|             std::cerr << res.second << std::endl; | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user