diff --git a/C/plugins/common/include/http_sender.h b/C/plugins/common/include/http_sender.h index 1ffc90f17..20273071d 100644 --- a/C/plugins/common/include/http_sender.h +++ b/C/plugins/common/include/http_sender.h @@ -45,9 +45,11 @@ class HttpSender virtual std::string getHostPort() = 0; virtual std::string getHTTPResponse() = 0; + virtual unsigned int getMaxRetries() = 0; virtual void setAuthMethod (std::string& authMethod) = 0; virtual void setAuthBasicCredentials(std::string& authBasicCredentials) = 0; + virtual void setMaxRetries (unsigned int retries) = 0; // OCS configurations virtual void setOCSNamespace (std::string& OCSNamespace) = 0; diff --git a/C/plugins/common/include/libcurl_https.h b/C/plugins/common/include/libcurl_https.h index 9f454d6db..3e9f41199 100644 --- a/C/plugins/common/include/libcurl_https.h +++ b/C/plugins/common/include/libcurl_https.h @@ -51,6 +51,7 @@ class LibcurlHttps: public HttpSender void setAuthMethod (std::string& authMethod) {m_authMethod = authMethod; } void setAuthBasicCredentials(std::string& authBasicCredentials) {m_authBasicCredentials = authBasicCredentials; } + void setMaxRetries (unsigned int retries) {m_max_retry = retries; }; // OCS configurations void setOCSNamespace (std::string& OCSNamespace) {m_OCSNamespace = OCSNamespace; } @@ -61,6 +62,7 @@ class LibcurlHttps: public HttpSender std::string getHostPort() { return m_host_port; }; std::string getHTTPResponse() { return m_HTTPResponse; }; + unsigned int getMaxRetries() { return m_max_retry; }; private: // Make private the copy constructor and operator= diff --git a/C/plugins/common/include/piwebapi.h b/C/plugins/common/include/piwebapi.h index fa5e87d32..181d857b1 100644 --- a/C/plugins/common/include/piwebapi.h +++ b/C/plugins/common/include/piwebapi.h @@ -37,10 +37,10 @@ class PIWebAPI void setAuthBasicCredentials(std::string& authBasicCredentials) {m_authBasicCredentials = authBasicCredentials; } int GetVersion(const string& host, string &version, bool logMessage = true); + string ExtractVersion(const string& response); string errorMessageHandler(const string& msg); private: - string ExtractVersion(const string& response); string extractSection(const string& msg, const string& toSearch); string extractMessageFromJSon(const string& json); diff --git a/C/plugins/common/include/simple_http.h b/C/plugins/common/include/simple_http.h index 9fa997168..61b5c4367 100644 --- a/C/plugins/common/include/simple_http.h +++ b/C/plugins/common/include/simple_http.h @@ -54,6 +54,7 @@ class SimpleHttp: public HttpSender std::string getHostPort() { return m_host_port; }; std::string getHTTPResponse() { return m_HTTPResponse; }; + unsigned int getMaxRetries() { return m_max_retry; }; // OCS configurations void setOCSNamespace (std::string& OCSNamespace) {m_OCSNamespace = OCSNamespace; } @@ -61,7 +62,7 @@ class SimpleHttp: public HttpSender void setOCSClientId (std::string& OCSClientId) {m_OCSClientId = OCSClientId; } void setOCSClientSecret (std::string& OCSClientSecret) {m_OCSClientSecret = OCSClientSecret; } void setOCSToken (std::string& OCSToken) {m_OCSToken = OCSToken; } - + void setMaxRetries (unsigned int retries) {m_max_retry = retries; }; private: // Make private the copy constructor and operator= diff --git a/C/plugins/common/include/simple_https.h b/C/plugins/common/include/simple_https.h index 3c2f6018f..3be662647 100644 --- a/C/plugins/common/include/simple_https.h +++ b/C/plugins/common/include/simple_https.h @@ -51,6 +51,7 @@ class SimpleHttps: public HttpSender void setAuthMethod (std::string& authMethod) {m_authMethod = authMethod; } void setAuthBasicCredentials(std::string& authBasicCredentials) {m_authBasicCredentials = authBasicCredentials; } + void setMaxRetries (unsigned int retries) {m_max_retry = retries; }; // OCS configurations void setOCSNamespace (std::string& OCSNamespace) {m_OCSNamespace = OCSNamespace; } @@ -61,6 +62,7 @@ class SimpleHttps: public HttpSender std::string getHTTPResponse() { return m_HTTPResponse; }; std::string getHostPort() { return m_host_port; }; + unsigned int getMaxRetries() { return m_max_retry; }; private: // Make private the copy constructor and operator= diff --git a/C/plugins/north/OMF/include/ocs.h b/C/plugins/north/OMF/include/ocs.h index 3070fe782..8a424202c 100644 --- a/C/plugins/north/OMF/include/ocs.h +++ b/C/plugins/north/OMF/include/ocs.h @@ -37,7 +37,7 @@ class OCS // Destructor ~OCS(); - string retrieveToken(const string& clientId, const string& clientSecret); + string retrieveToken(const string& clientId, const string& clientSecret, bool logMessage = true); string extractToken(const string& response); private: bool m_adh; diff --git a/C/plugins/north/OMF/include/omfinfo.h b/C/plugins/north/OMF/include/omfinfo.h index 25db35c85..0246c0529 100644 --- a/C/plugins/north/OMF/include/omfinfo.h +++ b/C/plugins/north/OMF/include/omfinfo.h @@ -112,10 +112,11 @@ class OMFInformation { void loadSentDataTypes(rapidjson::Document& JSONData); long getMaxTypeId(); int PIWebAPIGetVersion(bool logMessage = true); - int EDSGetVersion(); + int EDSGetVersion(bool logMessage = true); + int IsADHConnected(bool logMessage = true); void SetOMFVersion(); void CheckDataActionCode(); - std::string OCSRetrieveAuthToken(); + std::string OCSRetrieveAuthToken(bool logMessage = true); OMF_ENDPOINT identifyPIServerEndpoint(); std::string saveSentDataTypes(); unsigned long calcTypeShort(const std::string& dataTypes); @@ -124,7 +125,7 @@ class OMFInformation { std::string AuthBasicCredentialsGenerate(std::string& userId, std::string& password); void AuthKerberosSetup(std::string& keytabEnv, std::string& keytabFileName); double GetElapsedTime(struct timeval *startTime); - bool IsPIWebAPIConnected(); + bool IsDataArchiveConnected(); void handleOMFTracing(); private: diff --git a/C/plugins/north/OMF/ocs.cpp b/C/plugins/north/OMF/ocs.cpp index 7dc900263..6ee3fa28a 100644 --- a/C/plugins/north/OMF/ocs.cpp +++ b/C/plugins/north/OMF/ocs.cpp @@ -65,14 +65,15 @@ std::string OCS::extractToken(const string& response) } /** - * Calls the OCS API to retrieve the authentication token related to the the clientId and clientSecret + * Calls the OCS/ADH API to retrieve the authentication token related to the the clientId and clientSecret * - * @param clientId Client Id code assigned by OCS using its GUI to the specific connection - * @param clientSecret Client Secret code assigned by OCS using its gui to the specific connection - * @return The OCS token to be used for authentication in API calls + * @param clientId Client Id code assigned by OCS/ADH using its GUI to the specific connection + * @param clientSecret Client Secret code assigned by OCS/ADH using its GUI to the specific connection + * @param logMessage If true, log error messages (default: true) + * @return The OCS/ADH token to be used for authentication in API calls * */ -std::string OCS::retrieveToken(const string& clientId, const string& clientSecret) +std::string OCS::retrieveToken(const string& clientId, const string& clientSecret, bool logMessage) { string token; string response; @@ -86,7 +87,7 @@ std::string OCS::retrieveToken(const string& clientId, const string& clientSecre TIMEOUT_CONNECT, TIMEOUT_REQUEST, RETRY_SLEEP_TIME, - MAX_RETRY); + 0); header.push_back( std::make_pair("Content-Type", "application/x-www-form-urlencoded")); header.push_back( std::make_pair("Accept", " text/plain")); @@ -112,17 +113,24 @@ std::string OCS::retrieveToken(const string& clientId, const string& clientSecre if (httpCode >= 200 && httpCode <= 399) { token = extractToken(response); - Logger::getLogger()->debug("OCS authentication token :%s:" ,token.c_str() ); + Logger::getLogger()->debug("ADH authentication token :%s:" ,token.c_str() ); } - else + else if (logMessage) { - Logger::getLogger()->warn("Error in retrieving the authentication token from OCS - http :%d: :%s: ", httpCode, response.c_str()); + Logger::getLogger()->warn("Error in retrieving the authentication token from ADH - http :%d: :%s: ", httpCode, response.c_str()); } - + } + catch (const Unauthorized &e) + { + // Log authentication failures regardless of 'logMessage' + Logger::getLogger()->error("Unable to authenticate with AVEVA Data Hub"); } catch (exception &ex) { - Logger::getLogger()->warn("Error in retrieving the authentication token from OCS - error :%s: ", ex.what()); + if (logMessage) + { + Logger::getLogger()->warn("Error in retrieving the authentication token from ADH - error :%s: ", ex.what()); + } } delete endPoint; diff --git a/C/plugins/north/OMF/omfinfo.cpp b/C/plugins/north/OMF/omfinfo.cpp index 04f767200..93ba3b4a7 100644 --- a/C/plugins/north/OMF/omfinfo.cpp +++ b/C/plugins/north/OMF/omfinfo.cpp @@ -395,7 +395,6 @@ OMFInformation::~OMFInformation() */ void OMFInformation::start(const string& storedData) { - m_logger->info("Host: %s", m_hostAndPort.c_str()); if ((m_PIServerEndpoint == ENDPOINT_OCS) || (m_PIServerEndpoint == ENDPOINT_ADH)) { @@ -461,76 +460,7 @@ void OMFInformation::start(const string& storedData) getMaxTypeId()); } - // Retrieve the PI Web API Version - m_connected = true; - if (m_PIServerEndpoint == ENDPOINT_PIWEB_API) - { - int httpCode = PIWebAPIGetVersion(); - if (httpCode >= 200 && httpCode < 400) - { - SetOMFVersion(); - CheckDataActionCode(); - Logger::getLogger()->info("%s connected to %s OMF Version: %s", - m_RestServerVersion.c_str(), m_hostAndPort.c_str(), m_omfversion.c_str()); - m_connected = true; - } - else - { - Logger::getLogger()->error("The PI Web API service %s is not available. HTTP Code: %d", - m_hostAndPort.c_str(), httpCode); - m_connected = false; - } - } - else if (m_PIServerEndpoint == ENDPOINT_EDS) - { - EDSGetVersion(); - SetOMFVersion(); - CheckDataActionCode(); - Logger::getLogger()->info("Edge Data Store %s OMF Version: %s", m_RestServerVersion.c_str(), m_omfversion.c_str()); - } - else - { - SetOMFVersion(); - CheckDataActionCode(); - Logger::getLogger()->info("OMF Version: %s", m_omfversion.c_str()); - } -} - -/** - * Send data to the OMF endpoint - * - * @param readings The block of readings to send - * @return uint32_t The number of readings sent - */ -uint32_t OMFInformation::send(const vector& readings) -{ -#if INSTRUMENT - struct timeval startTime; - gettimeofday(&startTime, NULL); -#endif - string version; - - // Check if the endpoint is PI Web API and if the PI Web API server is available - if (!IsPIWebAPIConnected()) - { - // Error already reported by IsPIWebAPIConnected - return 0; - } - - if (m_sender && m_connected == false) - { - // TODO Make the info when reconnection has been proved to work - Logger::getLogger()->warn("Connection failed creating a new sender"); - delete m_sender; - m_sender = NULL; - } - - // Exit immediately if the plugin is not stable due to PI Server errors - if (m_omf && !m_omf->isPIstable()) - { - return 0; - } - + // Allocate an HttpSender subclass to communicate with PI Web API with selected authorization if (!m_sender) { /** @@ -581,20 +511,66 @@ uint32_t OMFInformation::send(const vector& readings) m_sender->setOCSTenantId (m_OCSTenantId); m_sender->setOCSClientId (m_OCSClientId); m_sender->setOCSClientSecret (m_OCSClientSecret); - - if (m_omf) - { - // Created a new sender after a connection failure - m_omf->setSender(*m_sender); - } } - // OCS or ADH - retrieves the authentication token - // It is retrieved at every send as it can expire and the configuration is only in OCS and ADH - if (m_PIServerEndpoint == ENDPOINT_OCS || m_PIServerEndpoint == ENDPOINT_ADH) + // Retrieve the destination data archive version + m_connected = true; + int httpCode = 200; + switch (m_PIServerEndpoint) { - m_OCSToken = OCSRetrieveAuthToken(); - m_sender->setOCSToken (m_OCSToken); + case ENDPOINT_PIWEB_API: + httpCode = PIWebAPIGetVersion(); + if (httpCode >= 200 && httpCode < 400) + { + SetOMFVersion(); + CheckDataActionCode(); + Logger::getLogger()->info("%s connected to %s OMF Version: %s", + m_RestServerVersion.c_str(), m_hostAndPort.c_str(), m_omfversion.c_str()); + m_connected = true; + } + else + { + Logger::getLogger()->error("The PI Web API service %s is not available. HTTP Code: %d", + m_hostAndPort.c_str(), httpCode); + m_connected = false; + } + break; + case ENDPOINT_EDS: + httpCode = EDSGetVersion(); + if (httpCode >= 200 && httpCode < 400) + { + SetOMFVersion(); + CheckDataActionCode(); + Logger::getLogger()->info("Edge Data Store %s OMF Version: %s", m_RestServerVersion.c_str(), m_omfversion.c_str()); + m_connected = true; + } + else + { + Logger::getLogger()->error("Edge Data Store %s is not available. HTTP Code: %d", + m_hostAndPort.c_str(), httpCode); + m_connected = false; + } + break; + case ENDPOINT_OCS: + SetOMFVersion(); + CheckDataActionCode(); + Logger::getLogger()->info("OSIsoft Cloud Services OMF Version: %s", m_omfversion.c_str()); + break; + case ENDPOINT_ADH: + SetOMFVersion(); + CheckDataActionCode(); + Logger::getLogger()->info("AVEVA Data Hub OMF Version: %s", m_omfversion.c_str()); + break; + case ENDPOINT_CR: + SetOMFVersion(); + CheckDataActionCode(); + Logger::getLogger()->info("Connector Relay OMF Version: %s", m_omfversion.c_str()); + break; + default: + SetOMFVersion(); + CheckDataActionCode(); + Logger::getLogger()->info("OMF Version: %s", m_omfversion.c_str()); + break; } // Allocate the OMF class that implements the PI Server data protocol @@ -605,7 +581,6 @@ uint32_t OMFInformation::send(const vector& readings) m_omf->setSendFullStructure(m_sendFullStructure); m_omf->setDelimiter(m_delimiter); - m_omf->setDataActionCode(m_dataActionCode); // Set PIServerEndpoint configuration m_omf->setNamingScheme(m_NamingScheme); @@ -613,8 +588,6 @@ uint32_t OMFInformation::send(const vector& readings) m_omf->setDefaultAFLocation(m_DefaultAFLocation); m_omf->setAFMap(m_AFMap); - m_omf->setOMFVersion(m_omfversion); - // Generates the prefix to have unique asset_id across different levels of hierarchies string AFHierarchyLevel; m_omf->generateAFHierarchyPrefixLevel(m_DefaultAFLocation, m_prefixAFAsset, AFHierarchyLevel); @@ -640,10 +613,53 @@ uint32_t OMFInformation::send(const vector& readings) m_omf->setLegacyMode(m_legacy); } } +} + +/** + * Send data to the OMF endpoint + * + * @param readings The block of readings to send + * @return uint32_t The number of readings sent + */ +uint32_t OMFInformation::send(const vector& readings) +{ +#if INSTRUMENT + struct timeval startTime; + gettimeofday(&startTime, NULL); +#endif + // Check if the destination data archive is available + if (!IsDataArchiveConnected()) + { + // Error already reported by IsDataArchiveConnected + return 0; + } + + // OCS or ADH - retrieves the authentication token + // It is retrieved at every send as it can expire and the configuration is only in OCS and ADH + if (m_PIServerEndpoint == ENDPOINT_OCS || m_PIServerEndpoint == ENDPOINT_ADH) + { + std::string token = OCSRetrieveAuthToken(); + if (!token.empty()) + { + m_OCSToken = token; + m_sender->setOCSToken(token); + } + } + + // Exit immediately if the plugin is not stable due to PI Server errors + if (!m_omf->isPIstable()) + { + return 0; + } + // Send the readings data to the PI Server + m_omf->setOMFVersion(m_omfversion); + m_omf->setDataActionCode(m_dataActionCode); m_omf->setPIconnected(m_connected); m_omf->setNumBlocks(m_numBlocks); + uint32_t ret = m_omf->sendToServer(readings, m_compression); + m_connected = m_omf->isPIconnected(); m_numBlocks = m_omf->getNumBlocks(); @@ -965,73 +981,201 @@ long OMFInformation::getMaxTypeId() } /** - * Calls the PI Web API to retrieve the version + * Calls the PI Web API system information endpoint to get the product version * * @param logMessage If true, log error messages (default: true) - * @return httpCode HTTP response code + * @return HttpCode REST response code */ int OMFInformation::PIWebAPIGetVersion(bool logMessage) { - PIWebAPI *_PIWebAPI; - - _PIWebAPI = new PIWebAPI(); + int res = 400; + unsigned int retries = m_sender->getMaxRetries(); + m_sender->setMaxRetries(0); - // Set requested authentication - _PIWebAPI->setAuthMethod (m_PIWebAPIAuthMethod); - _PIWebAPI->setAuthBasicCredentials(m_PIWebAPICredentials); + try + { + string path = "https://" + m_hostAndPort + "/piwebapi/system"; - int httpCode = _PIWebAPI->GetVersion(m_hostAndPort, m_RestServerVersion, logMessage); - delete _PIWebAPI; + vector> headers; + headers.push_back( std::make_pair("Accept", "application/json")); - return httpCode; -} + m_RestServerVersion.clear(); + res = m_sender->sendRequest("GET", path, headers, std::string("")); + if (res >= 200 && res <= 299) + { + PIWebAPI piwebapi; + m_RestServerVersion = piwebapi.ExtractVersion(m_sender->getHTTPResponse()); + } + } + catch (const BadRequest &ex) + { + if (logMessage) + { + Logger::getLogger()->error("PI Web API system information BadRequest exception: %s", ex.what()); + } + res = 400; + } + catch (const Unauthorized &e) + { + if (logMessage) + { + Logger::getLogger()->error(MESSAGE_UNAUTHORIZED); + } + res = 401; + } + catch (const std::exception &ex) + { + if (logMessage) + { + Logger::getLogger()->error("PI Web API system information exception: %s", ex.what()); + } + res = 400; + } + catch (...) + { + if (logMessage) + { + Logger::getLogger()->error("PI Web API system information generic exception"); + } + res = 400; + } + m_sender->setMaxRetries(retries); + return res; +} /** * Calls the Edge Data Store product information endpoint to get the EDS version * + * @param logMessage If true, log error messages (default: true) * @return HttpCode REST response code */ -int OMFInformation::EDSGetVersion() +int OMFInformation::EDSGetVersion(bool logMessage) { - int res; - - HttpSender *endPoint = new SimpleHttp(m_hostAndPort, - m_timeout, - m_timeout, - m_retrySleepTime, - m_maxRetry); + int res = 400; + unsigned int retries = m_sender->getMaxRetries(); + m_sender->setMaxRetries(0); try { string path = "http://" + m_hostAndPort + "/api/v1/diagnostics/productinformation"; + vector> headers; + headers.push_back( std::make_pair("Accept", "application/json")); + m_RestServerVersion.clear(); - res = endPoint->sendRequest("GET", path, headers, std::string("")); + res = m_sender->sendRequest("GET", path, headers, std::string("")); if (res >= 200 && res <= 299) { - m_RestServerVersion = ParseEDSProductInformation(endPoint->getHTTPResponse()); + m_RestServerVersion = ParseEDSProductInformation(m_sender->getHTTPResponse()); } } catch (const BadRequest &ex) { - Logger::getLogger()->error("Edge Data Store productinformation BadRequest exception: %s", ex.what()); + if (logMessage) + { + Logger::getLogger()->error("Edge Data Store productinformation BadRequest exception: %s", ex.what()); + } res = 400; } + catch (const Unauthorized &e) + { + if (logMessage) + { + Logger::getLogger()->error(MESSAGE_UNAUTHORIZED); + } + res = 401; + } catch (const std::exception &ex) { - Logger::getLogger()->error("Edge Data Store productinformation exception: %s", ex.what()); + if (logMessage) + { + Logger::getLogger()->error("Edge Data Store productinformation exception: %s", ex.what()); + } res = 400; } catch (...) { - Logger::getLogger()->error("Edge Data Store productinformation generic exception"); + if (logMessage) + { + Logger::getLogger()->error("Edge Data Store productinformation generic exception"); + } res = 400; } - delete endPoint; + m_sender->setMaxRetries(retries); + return res; +} + +/** + * Calls the ADH Namespace identity endpoint to check the connection to ADH + * + * @param logMessage If true, log error messages (default: true) + * @return HttpCode REST response code + */ +int OMFInformation::IsADHConnected(bool logMessage) +{ + if (m_OCSToken.empty()) + { + std::string token = OCSRetrieveAuthToken(false); + if (!token.empty()) + { + m_OCSToken = token; + m_sender->setOCSToken(token); + } + } + + int res = 400; + unsigned int retries = m_sender->getMaxRetries(); + m_sender->setMaxRetries(0); + + try + { + string path = m_path; + path.resize(path.size() - 4); // remove trailing "/omf" + + vector> headers; + headers.push_back( std::make_pair("Accept", "application/json")); + + res = m_sender->sendRequest("GET", path, headers, std::string("")); + } + catch (const BadRequest &ex) + { + if (logMessage) + { + Logger::getLogger()->error("AVEVA Data Hub health check BadRequest exception: %s", ex.what()); + } + res = 400; + } + catch (const Unauthorized &e) + { + // HTTP 401: Land here if the ADH or OCS Token has expired + if (logMessage) + { + Logger::getLogger()->error(MESSAGE_UNAUTHORIZED); + } + res = 401; + } + catch (const std::exception &ex) + { + if (logMessage) + { + Logger::getLogger()->error("AVEVA Data Hub health check exception: %s", ex.what()); + } + res = 400; + } + catch (...) + { + if (logMessage) + { + Logger::getLogger()->error("AVEVA Data Hub health check generic exception"); + } + res = 400; + } + + m_sender->setMaxRetries(retries); return res; } @@ -1109,9 +1253,10 @@ void OMFInformation::CheckDataActionCode() /** * Calls the OCS API to retrieve the authentication token * + * @param logMessage If true, log error messages (default: true) * @return token Authorization token */ -string OMFInformation::OCSRetrieveAuthToken() +string OMFInformation::OCSRetrieveAuthToken(bool logMessage) { string token; OCS *ocs; @@ -1121,7 +1266,7 @@ string OMFInformation::OCSRetrieveAuthToken() else if (m_PIServerEndpoint == ENDPOINT_ADH) ocs = new OCS(true); - token = ocs->retrieveToken(m_OCSClientId , m_OCSClientSecret); + token = ocs->retrieveToken(m_OCSClientId , m_OCSClientSecret, logMessage); delete ocs; @@ -1475,60 +1620,119 @@ double OMFInformation::GetElapsedTime(struct timeval *startTime) } /** - * Check if the PI Web API server is available by reading the product version every 60 seconds. + * Check if the destination data archive is available by making a lightweight REST GET call every 60 seconds. * Log a message if the connection state changes. + * First call to this method will make a REST call. + * This method can check connectivity with PI Web API, Edge Data Store and AVEVA Data Hub. * * @return Connection status */ -bool OMFInformation::IsPIWebAPIConnected() +bool OMFInformation::IsDataArchiveConnected() { static std::chrono::steady_clock::time_point nextCheck(std::chrono::steady_clock::time_point::duration::zero()); - static bool lastConnected = m_connected; // Previous value of m_connected + static bool lastConnected = m_connected; // Previous value of m_connected - if (m_PIServerEndpoint == ENDPOINT_PIWEB_API) + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + + if (now >= nextCheck) { - std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + int httpCode; - if (now >= nextCheck) + switch (m_PIServerEndpoint) { - int httpCode = PIWebAPIGetVersion(false); - Logger::getLogger()->debug("PIWebAPIGetVersion: %s HTTP Code: %d Connected: %s LastConnected: %s", - m_hostAndPort.c_str(), - httpCode, - m_connected ? "true" : "false", - lastConnected ? "true" : "false"); - - if ((httpCode < 200) || (httpCode >= 400)) + case ENDPOINT_PIWEB_API: + httpCode = PIWebAPIGetVersion(false); + break; + case ENDPOINT_EDS: + httpCode = EDSGetVersion(false); + break; + case ENDPOINT_ADH: + case ENDPOINT_OCS: + httpCode = IsADHConnected(false); + break; + default: + httpCode = 200; // assume all other endpoint types are connected + break; + } + + m_connected = ((httpCode < 200) || (httpCode >= 400)) ? false : true; + + Logger::getLogger()->debug("%s: Check %s HTTP Code: %d Connected: %s LastConnected: %s", + __FUNCTION__, + m_hostAndPort.c_str(), + httpCode, + m_connected ? "true" : "false", + lastConnected ? "true" : "false"); + + // See if the connection status has changed since the last check. + // If so, write a disconnection or reconnection message. + if (m_connected == true) + { + SetOMFVersion(); + CheckDataActionCode(); + + if (lastConnected == false) { - m_connected = false; - if (lastConnected == true) - { - Logger::getLogger()->error("The PI Web API service %s is not available. HTTP Code: %d", - m_hostAndPort.c_str(), httpCode); - lastConnected = false; + switch (m_PIServerEndpoint) + { + case ENDPOINT_PIWEB_API: + Logger::getLogger()->warn("%s reconnected to %s OMF Version: %s", + m_RestServerVersion.c_str(), m_hostAndPort.c_str(), m_omfversion.c_str()); + break; + case ENDPOINT_EDS: + Logger::getLogger()->warn("Edge Data Store %s reconnected to %s OMF Version: %s", + m_RestServerVersion.c_str(), m_hostAndPort.c_str(), m_omfversion.c_str()); + break; + case ENDPOINT_ADH: + Logger::getLogger()->warn("AVEVA Data Hub %s reconnected. OMF Version: %s", + m_hostAndPort.c_str(), m_omfversion.c_str()); + break; + case ENDPOINT_OCS: + Logger::getLogger()->warn("OSIsoft Cloud Services %s reconnected. OMF Version: %s", + m_hostAndPort.c_str(), m_omfversion.c_str()); + break; + default: + Logger::getLogger()->warn("Destination Data Archive %s reconnected. OMF Version: %s", + m_hostAndPort.c_str(), m_omfversion.c_str()); + break; } + + lastConnected = true; } - else + } + else + { + if (lastConnected == true) { - m_connected = true; - SetOMFVersion(); - CheckDataActionCode(); - if (lastConnected == false) + switch (m_PIServerEndpoint) { - Logger::getLogger()->warn("%s reconnected to %s OMF Version: %s", - m_RestServerVersion.c_str(), m_hostAndPort.c_str(), m_omfversion.c_str()); - lastConnected = true; + case ENDPOINT_PIWEB_API: + Logger::getLogger()->error("The PI Web API service %s is not available. HTTP Code: %d", + m_hostAndPort.c_str(), httpCode); + break; + case ENDPOINT_EDS: + Logger::getLogger()->error("Edge Data Store %s is not available. HTTP Code: %d", + m_hostAndPort.c_str(), httpCode); + break; + case ENDPOINT_ADH: + Logger::getLogger()->error("AVEVA Data Hub %s is not available. HTTP Code: %d", + m_hostAndPort.c_str(), httpCode); + break; + case ENDPOINT_OCS: + Logger::getLogger()->error("OSIsoft Cloud Services %s is not available. HTTP Code: %d", + m_hostAndPort.c_str(), httpCode); + break; + default: + Logger::getLogger()->warn("Destination Data Archive %s is not available. HTTP Code: %d", + m_hostAndPort.c_str(), httpCode); + break; } - } - nextCheck = now + std::chrono::seconds(60); + lastConnected = false; + } } - } - else - { - // Endpoints other than PI Web API fail quickly when they are unavailable - // so there is no need to check their status in advance. - m_connected = true; + + nextCheck = now + std::chrono::seconds(60); } return m_connected;