diff --git a/src/modules/Workers/WebService/WebService.cpp b/src/modules/Workers/WebService/WebService.cpp index cad2128..17f531c 100644 --- a/src/modules/Workers/WebService/WebService.cpp +++ b/src/modules/Workers/WebService/WebService.cpp @@ -51,7 +51,7 @@ namespace Apostol { CString to_string(unsigned long Value) { TCHAR szString[_INT_T_LEN + 1] = {0}; sprintf(szString, "%lu", Value); - return CString(szString); + return {szString}; } //-------------------------------------------------------------------------------------------------------------- @@ -62,11 +62,9 @@ namespace Apostol { CWebService::CWebService(CModuleProcess *AProcess): CApostolModule(AProcess, "web service") { m_SyncPeriod = BPS_DEFAULT_SYNC_PERIOD; - m_ServerIndex = -1; - m_KeyIndex = 0; + m_ActiveIndex = -1; m_FixedDate = 0; - m_RandomDate = 0; m_Status = psStopped; @@ -74,6 +72,8 @@ namespace Apostol { m_DefaultServer.Value().URI = BPS_SERVER_URL; m_DefaultServer.Value().PGP.Name = BPS_BM_SERVER_ADDRESS; + m_CurrentServer = m_DefaultServer; + CWebService::InitMethods(); } //-------------------------------------------------------------------------------------------------------------- @@ -113,7 +113,7 @@ namespace Apostol { //-------------------------------------------------------------------------------------------------------------- void CWebService::LoadOAuth2(const CString &FileName, const CString &ProviderName, const CString &ApplicationName, - CProviders &Providers) { + CProviders &Providers) { CString ConfigFile(FileName); @@ -1166,12 +1166,14 @@ namespace Apostol { } else { Node = YAML::Load(pServerRequest->Content.c_str()); } + + const auto &BTCKeys = CurrentServer().Value().BTCKeys; - if (m_BTCKeys.Count() < 2) + if (BTCKeys.Count() < 2) throw ExceptionFrm("Bitcoin keys cannot be empty."); - for (int i = 0; i < m_BTCKeys.Count(); ++i) { - if (m_BTCKeys[i].IsEmpty()) + for (int i = 0; i < BTCKeys.Count(); ++i) { + if (BTCKeys[i].IsEmpty()) throw ExceptionFrm("Bitcoin KEY%d cannot be empty.", i); } @@ -1180,7 +1182,7 @@ namespace Apostol { auto& Data = Deal.Data(); if (Data.Order == doCreate) { - Data.Payment.Address = Deal.GetPaymentHD(m_BTCKeys.Names(0), m_BTCKeys.Names(1), + Data.Payment.Address = Deal.GetPaymentHD(BTCKeys.Names(0), BTCKeys.Names(1), Deal.Data().Transaction.Key, BitcoinConfig.version_hd, BitcoinConfig.version_script); Node["deal"]["date"] = Data.Date.c_str(); @@ -1485,20 +1487,34 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - int CWebService::NextServerIndex() { - m_ServerIndex++; - if (m_ServerIndex >= m_Servers.Count()) - m_ServerIndex = -1; - return m_ServerIndex; + const CServer &CWebService::CurrentServer() const { + return m_CurrentServer; } //-------------------------------------------------------------------------------------------------------------- - const CServer &CWebService::CurrentServer() const { - if (m_Servers.Count() == 0 && m_ServerIndex == -1) + int CWebService::NextServerIndex() { + m_ActiveIndex++; + if (m_ActiveIndex >= m_Servers.Count()) + m_ActiveIndex = -1; + return m_ActiveIndex; + } + //-------------------------------------------------------------------------------------------------------------- + + CServer &CWebService::ActiveServer() { + if (m_Servers.Count() == 0 && m_ActiveIndex == -1) return m_DefaultServer; - if (m_ServerIndex == -1) + if (m_ActiveIndex == -1) return m_Servers[0]; - return m_Servers[m_ServerIndex]; + return m_Servers[m_ActiveIndex]; + } + //-------------------------------------------------------------------------------------------------------------- + + const CServer &CWebService::ActiveServer() const { + if (m_Servers.Count() == 0 && m_ActiveIndex == -1) + return m_DefaultServer; + if (m_ActiveIndex == -1) + return m_Servers[0]; + return m_Servers[m_ActiveIndex]; } //-------------------------------------------------------------------------------------------------------------- @@ -1614,15 +1630,16 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void CWebService::FetchPGP(CKeyContext &PGP) { + void CWebService::FetchPGP(CServer &Server) { - const auto& caServerContext = CurrentServer().Value(); + Log()->Debug(0, "Trying to fetch a PGP key \"%s\" from: %s", Server.Name().c_str(), Server.Value().URI.c_str()); - Log()->Debug(0, "Trying to fetch a PGP key \"%s\" from: %s", PGP.Name.c_str(), caServerContext.URI.c_str()); + auto OnRequest = [this, &Server](CHTTPClient *Sender, CHTTPRequest *ARequest) { + auto &PGP = Server.Value().PGP; - auto OnRequest = [this, &PGP](CHTTPClient *Sender, CHTTPRequest *ARequest) { PGP.StatusTime = Now(); PGP.Status = CKeyContext::ksFetching; + PGP.RunTime = PGP.StatusTime + (CDateTime) 30 / SecsPerDay; CHTTPRequest::Prepare(ARequest, "GET", CString().Format("/api/v1/key/public?account=%s&type=pgp", PGP.Name.c_str()).c_str()); @@ -1631,58 +1648,61 @@ namespace Apostol { DebugRequest(ARequest); }; - auto OnExecute = [this, &PGP](CTCPConnection *AConnection) { + auto OnExecute = [this, &Server](CTCPConnection *AConnection) { auto pConnection = dynamic_cast (AConnection); - if (pConnection == nullptr) - return true; + if (pConnection != nullptr) { + auto pReply = pConnection->Reply(); - auto pReply = pConnection->Reply(); + DebugReply(pReply); - DebugReply(pReply); + auto &PGP = Server.Value().PGP; - try { PGP.StatusTime = Now(); PGP.Status = CKeyContext::ksError; + PGP.RunTime = PGP.StatusTime + (CDateTime) 30 / SecsPerDay; - JsonStringToKey(pReply->Content, PGP.Key); + try { + JsonStringToKey(pReply->Content, PGP.Key); - if (PGP.Key.IsEmpty()) - throw Delphi::Exception::Exception("Not found."); + if (PGP.Key.IsEmpty()) + throw Delphi::Exception::Exception("Not found."); - DebugMessage("[PGP] Key:\n%s\n", PGP.Key.c_str()); + CStringPairs ServerList; - CStringPairs ServerList; - CStringList BTCKeys; + ParsePGPKey(PGP.Key, ServerList, Server.Value().BTCKeys); - ParsePGPKey(PGP.Key, ServerList, BTCKeys); - - if (ServerList.Count() != 0) { - CStringPairs::ConstEnumerator em(ServerList); - while (em.MoveNext()) { - const auto ¤t = em.Current(); - if (m_Servers.IndexOfName(current.Name()) == -1) { - m_Servers.AddPair(current.Name(), CServerContext(current.Value())); + if (ServerList.Count() != 0) { + CStringPairs::ConstEnumerator em(ServerList); + while (em.MoveNext()) { + const auto ¤t = em.Current(); + if (m_Servers.IndexOfName(current.Name()) == -1) { + m_Servers.AddPair(current.Name(), CServerContext(current.Value())); + } } } + + PGP.Status = CKeyContext::ksSuccess; + PGP.RunTime = GetRandomDate(10 * 60, m_SyncPeriod * 60, PGP.StatusTime); // 10..m_SyncPeriod min + + m_CurrentServer = Server; + + Log()->Debug(APP_LOG_DEBUG_CORE, "[CurrentServer]\n"); + Log()->Debug(APP_LOG_DEBUG_CORE, "[Name]\n%s", m_CurrentServer.Name().c_str()); + Log()->Debug(APP_LOG_DEBUG_CORE, "[PGP]\n%s", m_CurrentServer.Value().PGP.Key.c_str()); + Log()->Debug(APP_LOG_DEBUG_CORE, "[BTCKeys]\n%s", m_CurrentServer.Value().BTCKeys.Text().c_str()); + } catch (Delphi::Exception::Exception &e) { + Log()->Error(APP_LOG_INFO, 0, "[CurrentServer] Message: %s", e.what()); } - m_BTCKeys = BTCKeys; - PGP.Status = CKeyContext::ksSuccess; - m_RandomDate = GetRandomDate(10 * 60, m_SyncPeriod * 60, Now()); // 10..m_SyncPeriod min - } catch (Delphi::Exception::Exception &e) { - Log()->Error(APP_LOG_INFO, 0, "[PGP] Message: %s", e.what()); - PGP.Status = CKeyContext::ksError; - m_RandomDate = Now() + (CDateTime) 30 / SecsPerDay; + pConnection->CloseConnection(true); } - pConnection->CloseConnection(true); - return true; }; - auto OnException = [this, &PGP](CTCPConnection *AConnection, const Delphi::Exception::Exception &E) { + auto OnException = [&Server](CTCPConnection *AConnection, const Delphi::Exception::Exception &E) { auto pConnection = dynamic_cast (AConnection); if (pConnection != nullptr) { @@ -1691,15 +1711,18 @@ namespace Apostol { if (pClient != nullptr) { Log()->Error(APP_LOG_EMERG, 0, "[%s:%d] %s", pClient->Host().c_str(), pClient->Port(), E.what()); + auto &PGP = Server.Value().PGP; + + PGP.StatusTime = Now(); PGP.Status = CKeyContext::ksError; - m_RandomDate = Now() + (CDateTime) 5 / SecsPerDay; + PGP.RunTime = PGP.StatusTime + (CDateTime) 30 / SecsPerDay; } DebugReply(pConnection->Reply()); } }; - CLocation Location(caServerContext.URI); + CLocation Location(Server.Value().URI); auto pClient = GetClient(Location.hostname, Location.port == 0 ? BPS_SERVER_PORT : Location.port); pClient->OnRequest(OnRequest); @@ -1710,40 +1733,48 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void CWebService::FetchBTC(CKeyContext &BTC) { + void CWebService::FetchBTC(CServer &Server) { - const auto& caServerContext = CurrentServer().Value(); + Log()->Debug(0, "Trying to fetch a BTC key \"%s\" from: %s", Server.Name().c_str(), Server.Value().URI.c_str()); - Log()->Debug(0, "Trying to fetch a BTC key \"%s\" from: %s", BTC.Name.c_str(), caServerContext.URI.c_str()); + auto OnRequest = [this, &Server](CHTTPClient *Sender, CHTTPRequest *ARequest) { + + auto &BTC = Server.Value().BTC; - auto OnRequest = [this, &BTC](CHTTPClient *Sender, CHTTPRequest *ARequest) { - const auto& caServerContext = CurrentServer().Value(); BTC.StatusTime = Now(); BTC.Status = CKeyContext::ksFetching; + BTC.RunTime = BTC.StatusTime + (CDateTime) 30 / SecsPerDay; CHTTPRequest::Prepare(ARequest, "GET", CString().Format("/api/v1/key/public?account=%s&type=btc", BTC.Name.c_str()).c_str()); ARequest->AddHeader("Authorization", "Bearer " + m_Tokens[SYSTEM_PROVIDER_NAME]["access_token"]); }; - auto OnExecute = [this, &BTC](CTCPConnection *AConnection) { + auto OnExecute = [this, &Server](CTCPConnection *AConnection) { + auto pConnection = dynamic_cast (AConnection); auto pReply = pConnection->Reply(); + auto &BTC = Server.Value().BTC; + + BTC.StatusTime = Now(); + BTC.Status = CKeyContext::ksError; + BTC.RunTime = BTC.StatusTime + (CDateTime) 30 / SecsPerDay; + try { CString Key; JsonStringToKey(pReply->Content, Key); if (!Key.IsEmpty()) { - m_BTCKeys.Add(Key); - m_KeyIndex++; - //FetchBTC(); + Server.Value().BTCKeys.Add(Key); } } catch (Delphi::Exception::Exception &e) { Log()->Error(APP_LOG_INFO, 0, "[BTC] Message: %s", e.what()); - if (m_BTCKeys.Count() == 0) { + + if (Server.Value().BTCKeys.Count() == 0) { BTC.Status = CKeyContext::ksError; } else { BTC.Status = CKeyContext::ksSuccess; + BTC.RunTime = GetRandomDate(10 * 60, m_SyncPeriod * 60, BTC.StatusTime); // 10..m_SyncPeriod min } } @@ -1752,15 +1783,20 @@ namespace Apostol { return true; }; - auto OnException = [&BTC](CTCPConnection *AConnection, const Delphi::Exception::Exception &E) { + auto OnException = [&Server](CTCPConnection *AConnection, const Delphi::Exception::Exception &E) { auto pConnection = dynamic_cast (AConnection); auto pClient = dynamic_cast (pConnection->Client()); Log()->Error(APP_LOG_EMERG, 0, "[%s:%d] %s", pClient->Host().c_str(), pClient->Port(), E.what()); + + auto &BTC = Server.Value().BTC; + + BTC.StatusTime = Now(); BTC.Status = CKeyContext::ksError; + BTC.RunTime = BTC.StatusTime + (CDateTime) 30 / SecsPerDay; }; - CLocation Location(caServerContext.URI); + CLocation Location(Server.Value().URI); auto pClient = GetClient(Location.hostname, Location.port == 0 ? BPS_SERVER_PORT : Location.port); pClient->OnRequest(OnRequest); @@ -1771,12 +1807,14 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void CWebService::FetchKeys() { - m_KeyIndex = 0; - if (NextServerIndex() != -1) { - m_PGP.Status = CKeyContext::ksUnknown; - FetchPGP(m_PGP); - FetchPGP(m_Servers[m_ServerIndex].Value().PGP); + void CWebService::FetchKeys(CDateTime Now) { + while (NextServerIndex() != -1) { + auto& Server = ActiveServer(); + auto& PGP = Server.Value().PGP; + if (Now >= PGP.RunTime) { + PGP.Status = CKeyContext::ksUnknown; + FetchPGP(Server); + } } } //-------------------------------------------------------------------------------------------------------------- @@ -1824,9 +1862,7 @@ namespace Apostol { } if (m_Status == psRunning) { - if (now >= m_RandomDate) { - FetchKeys(); - } + FetchKeys(now); } } //-------------------------------------------------------------------------------------------------------------- diff --git a/src/modules/Workers/WebService/WebService.hpp b/src/modules/Workers/WebService/WebService.hpp index f545ecb..15eb1ec 100644 --- a/src/modules/Workers/WebService/WebService.hpp +++ b/src/modules/Workers/WebService/WebService.hpp @@ -50,22 +50,46 @@ namespace Apostol { } Status; CDateTime StatusTime; + CDateTime RunTime; - CKeyContext(): Status(ksUnknown), StatusTime(Now()) { + CKeyContext(): Status(ksUnknown), StatusTime(Now()), RunTime(0) { Name = BPS_BM_SERVER_ADDRESS; } - CKeyContext(const CString& Name, const CString& Key): CKeyContext() { + CKeyContext(const CString &Name, const CString &Key): CKeyContext() { this->Name = Name; this->Key = Key; } + CKeyContext(const CKeyContext &KeyContext): CKeyContext() { + Assign(KeyContext); + } + + void Assign(const CKeyContext &KeyContext) { + this->Name = KeyContext.Name; + this->Key = KeyContext.Key; + this->Status = KeyContext.Status; + this->StatusTime = KeyContext.StatusTime; + this->RunTime = KeyContext.RunTime; + } + + CKeyContext& operator= (const CKeyContext &KeyContext) { + if (this != &KeyContext) { + Assign(KeyContext); + } + return *this; + }; + }; struct CServerContext { - CString URI; - CKeyContext PGP; + CString URI {}; + + CKeyContext PGP {}; + CKeyContext BTC {}; + + CStringList BTCKeys; CServerContext() = default; @@ -73,6 +97,24 @@ namespace Apostol { this->URI = URI; } + CServerContext(const CServerContext &ServerContext): CServerContext() { + Assign(ServerContext); + } + + void Assign(const CServerContext &ServerContext) { + this->URI = ServerContext.URI; + this->PGP = ServerContext.PGP; + this->BTC = ServerContext.BTC; + this->BTCKeys = ServerContext.BTCKeys; + } + + CServerContext& operator= (const CServerContext &ServerContext) { + if (this != &ServerContext) { + Assign(ServerContext); + } + return *this; + }; + }; typedef TPair CServer; @@ -89,21 +131,16 @@ namespace Apostol { CProcessStatus m_Status; - CServer m_DefaultServer; + CServer m_DefaultServer {}; + CServer m_CurrentServer {}; int m_SyncPeriod; - int m_ServerIndex; - int m_KeyIndex; + int m_ActiveIndex; CDateTime m_FixedDate; - CDateTime m_RandomDate; - - CKeyContext m_PGP; CServerList m_Servers; - CStringList m_BTCKeys; - CProviders m_Providers; CStringListPairs m_Tokens; @@ -135,8 +172,11 @@ namespace Apostol { const CServer &CurrentServer() const; - void FetchPGP(CKeyContext& PGP); - void FetchBTC(CKeyContext& BTC); + CServer &ActiveServer(); + const CServer &ActiveServer() const; + + void FetchPGP(CServer& Server); + void FetchBTC(CServer& Server); static int CheckFee(const CString& Fee); @@ -171,7 +211,7 @@ namespace Apostol { bool Enabled() override; - void FetchKeys(); + void FetchKeys(CDateTime Now); void Reload();