diff --git a/CMakeLists.txt b/CMakeLists.txt index 8404182..da703d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ message(STATUS "Project description: ${PROJECT_DESCRIPTION}") # ---------------------------------------------------------------------------------------------------------------------- set(INSTALL_AS_ROOT ON CACHE BOOL "Install as root") set(WITH_POSTGRESQL OFF CACHE BOOL "Build with PostgreSQL") +set(WITH_SSL ON CACHE BOOL "Build with SSL") set(WITH_SQLITE3 OFF CACHE BOOL "Build with Sqlite3") set(WITH_CURL OFF CACHE BOOL "Build with cURL") set(WITH_BITCOIN_CLIENT ON CACHE BOOL "Build with libbitcoin-client") @@ -256,7 +257,7 @@ target_compile_definitions(${CORE_LIB_NAME} PUBLIC APP_DOC_ROOT="www/" ) -target_link_libraries(${CORE_LIB_NAME} pthread ${PQ_LIB_NAME} ${SQLITE3_LIB_NAME} ${CURL_LIB_NAME} yaml-cpp ssl crypto) +target_link_libraries(${CORE_LIB_NAME} pthread ${PQ_LIB_NAME} ${SQLITE3_LIB_NAME} ${CURL_LIB_NAME} ${SSL_LIB_NAME} yaml-cpp crypto) # Apostol modules # ---------------------------------------------------------------------------------------------------------------------- diff --git a/conf/default.conf b/conf/default.conf index cc9b709..c43708e 100644 --- a/conf/default.conf +++ b/conf/default.conf @@ -22,6 +22,16 @@ workers=1 ## default: true master=true +## Module: Web Service +[module/WebService] +## default: true +enable=true + +## Module: Web Socket +[module/WebSocket] +## default: false +enable=false + [daemon] ## Run as daemon ## default: true diff --git a/conf/oauth2/default.json b/conf/oauth2/default.json index 5e63e64..1a4fb15 100644 --- a/conf/oauth2/default.json +++ b/conf/oauth2/default.json @@ -1,50 +1,9 @@ { - "web": { - "issuers": ["accounts.bitdeals.org"], - "scopes": ["bitdeals"], - "client_id": "web-bitdeals.org", - "client_secret": "4aJEJi3dsSypeUSRCah4gIIs", - "algorithm": "HS256", - "auth_uri": "/oauth2/authorize", - "token_uri": "/oauth2/token", - "redirect_uris": [ - "http://localhost:4977/oauth2/code", - "http://localhost:4977/dashboard/", - "http://localhost:4999/oauth2/code", - "http://localhost:4999/dashboard/", - "http://65.21.101.151/oauth2/code", - "http://65.21.101.151/dashboard", - "https://oauthdebugger.com/debug" - ], - "javascript_origins": [ - "http://localhost:4977", - "http://localhost:4999", - "http://65.21.101.151" - ] - }, - "service": { - "issuers": ["accounts.bitdeals.org"], - "scopes": ["bitdeals"], - "client_id": "service-bitdeals.org", - "client_secret": "TjcILDtLa06YABJnepcVM32O", - "algorithm": "HS256", - "auth_uri": "/oauth2/authorize", - "token_uri": "/oauth2/token", - "redirect_uris": [ - "http://localhost:4977/dashboard", - "http://65.21.101.151/dashboard", - "https://oauthdebugger.com/debug" - ], - "javascript_origins": [ - "http://localhost:4977", - "http://65.21.101.151" - ] - }, "module": { "issuers": ["accounts.bitdeals.org"], "scopes": ["bitdeals"], "client_id": "dm-bitdeals.org", - "client_secret": "TypQHP4TK44khO3cvOyuHYg3", + "client_secret": "", "algorithm": "HS256", "auth_uri": "/oauth2/authorize", "token_uri": "/oauth2/token", @@ -54,33 +13,8 @@ "https://oauthdebugger.com/debug" ], "javascript_origins": [ - "http://localhost:4999" - ] - }, - "android": { - "issuers": ["accounts.bitdeals.org"], - "scopes": ["bitdeals"], - "client_id": "android-bitdeals.org", - "client_secret": "HaBAde09xWKb29NizXZfIMpl", - "algorithm": "HS256", - "auth_uri": "/oauth2/authorize", - "token_uri": "/oauth2/token", - "redirect_uris": [ - "http://127.0.0.1/oauth2/code", - "http://127.0.0.1/oauth2/callback" - ] - }, - "ios": { - "issuers": ["accounts.bitdeals.org"], - "scopes": ["bitdeals"], - "client_id": "ios-bitdeals.org", - "client_secret": "kWqJivDfaR7vbzkZz07zi7DO", - "algorithm": "HS256", - "auth_uri": "/oauth2/authorize", - "token_uri": "/oauth2/token", - "redirect_uris": [ - "http://127.0.0.1/oauth2/code", - "http://127.0.0.1/oauth2/callback" + "http://localhost:4999", + "http://95.217.251.153:4999" ] } } diff --git a/src/app/Deal.cpp b/src/app/Deal.cpp index 4e678cf..8427092 100644 --- a/src/app/Deal.cpp +++ b/src/app/Deal.cpp @@ -65,7 +65,7 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - CString DateToString(const CDateTime &Value, const CString &Format) { + CString DateToString(CDateTime Value, const CString &Format) { TCHAR Buffer[25] = {0}; DateTimeToStr(Value, Buffer, sizeof(Buffer), Format.c_str()); return Buffer; @@ -226,9 +226,9 @@ namespace Apostol { CDealType CDeal::StringToType(const CString &Value) { const auto &status = Value.Lower(); - if (status.Find("prepaid") != CString::npos || status.Find("prepayment") != CString::npos) { + if (status.Find("prepayment") != CString::npos || status.Find("prepaid") != CString::npos) { return dtPrepaid; - } else if (status.Find("postpaid") != CString::npos || status.Find("postpayment") != CString::npos) { + } else if (status.Find("postpayment") != CString::npos || status.Find("postpaid") != CString::npos) { return dtPostpaid; } else { throw ExceptionFrm(R"(Invalid order type value: "%s".)", status.c_str()); @@ -239,9 +239,9 @@ namespace Apostol { CString CDeal::TypeToString(CDealType Type) { switch (Type) { case dtPrepaid: - return "Prepaid"; + return "Prepayment"; case dtPostpaid: - return "Postpaid"; + return "Postpayment"; default: return "Unknown"; } @@ -250,9 +250,9 @@ namespace Apostol { CString CDeal::TypeCodeToString(const CString &Code) { if (Code == "prepaid.deal") { - return CString("Prepaid"); + return {"Prepayment"}; } else if (Code == "postpaid.deal") { - return CString("Postpaid"); + return {"Postpayment"}; } else { throw ExceptionFrm(R"(Invalid type code value: "%s".)", Code.c_str()); } @@ -526,7 +526,6 @@ namespace Apostol { } } -using namespace Apostol::Deal; #ifdef __cplusplus } #endif // __cplusplus diff --git a/src/app/Deal.hpp b/src/app/Deal.hpp index a1aa776..4b679c3 100644 --- a/src/app/Deal.hpp +++ b/src/app/Deal.hpp @@ -43,7 +43,7 @@ namespace Apostol { CString DoubleToBTC(const double &Value, const CString &Format = _T("%f BTC")); CDateTime StringToDate(const CString &Value, const CString &Format = _T("%04d-%02d-%02d %02d:%02d:%02d")); - CString DateToString(const CDateTime &Value, const CString &Format = _T("%Y-%m-%d %H:%M:%S UTC")); + CString DateToString(CDateTime Value, const CString &Format = _T("%Y-%m-%d %H:%M:%S UTC")); //-------------------------------------------------------------------------------------------------------------- diff --git a/src/app/Header.hpp b/src/app/Header.hpp index 31c70c9..faa4801 100644 --- a/src/app/Header.hpp +++ b/src/app/Header.hpp @@ -2,7 +2,7 @@ Program name: - ship-safety + dm Module Name: @@ -10,7 +10,7 @@ Module Name: Notices: - Ship Safety Service + Deal Module Author: @@ -21,8 +21,8 @@ Author: --*/ -#ifndef APOSTOL_HEADER_HPP -#define APOSTOL_HEADER_HPP +#ifndef APOSTOL_DM_HEADER_HPP +#define APOSTOL_DM_HEADER_HPP //---------------------------------------------------------------------------------------------------------------------- #include @@ -38,9 +38,10 @@ Author: #include "PGP.hpp" #include "Bitcoin.hpp" #include "Deal.hpp" +#include "Context.hpp" //---------------------------------------------------------------------------------------------------------------------- #include "Core.hpp" //---------------------------------------------------------------------------------------------------------------------- -#endif //APOSTOL_HEADER_HPP +#endif //APOSTOL_DM_HEADER_HPP diff --git a/src/modules/Workers/WebService/WebService.cpp b/src/modules/Workers/WebService/WebService.cpp index 1c48f0d..4376efe 100644 --- a/src/modules/Workers/WebService/WebService.cpp +++ b/src/modules/Workers/WebService/WebService.cpp @@ -1,8 +1,8 @@ /*++ -Library name: +Program name: - apostol-module + dm Module Name: @@ -27,12 +27,6 @@ Author: #include "WebService.hpp" //---------------------------------------------------------------------------------------------------------------------- -#include "jwt.h" -//---------------------------------------------------------------------------------------------------------------------- - -#include -//---------------------------------------------------------------------------------------------------------------------- - #define BPS_PGP_HASH "SHA512" #define BM_PREFIX "BM-" //---------------------------------------------------------------------------------------------------------------------- @@ -46,13 +40,15 @@ extern "C++" { namespace Apostol { - namespace Workers { + namespace Module { CString to_string(unsigned long Value) { TCHAR szString[_INT_T_LEN + 1] = {0}; sprintf(szString, "%lu", Value); return {szString}; } + //-------------------------------------------------------------------------------------------------------------- + //-------------------------------------------------------------------------------------------------------------- @@ -60,21 +56,16 @@ namespace Apostol { //-------------------------------------------------------------------------------------------------------------- - CWebService::CWebService(CModuleProcess *AProcess): CApostolModule(AProcess, "web service") { + CWebService::CWebService(CModuleProcess *AProcess): CApostolModule(AProcess, "web service", "module/WebService") { + m_NexServerTime = 0; + m_ServerIndex = -1; m_SyncPeriod = BPS_DEFAULT_SYNC_PERIOD; - m_ActiveIndex = -1; - - m_FixedDate = 0; - m_Status = psStopped; - m_DefaultServer.Name() = BPS_BM_SERVER_ADDRESS; - m_DefaultServer.Value().URI = BPS_SERVER_URL; - m_DefaultServer.Value().PGP.Name = BPS_BM_SERVER_ADDRESS; - - m_CurrentServer = m_DefaultServer; - CWebService::InitMethods(); + + //InitServerList(); + Reload(); } //-------------------------------------------------------------------------------------------------------------- @@ -103,18 +94,62 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - CDateTime CWebService::GetRandomDate(int a, int b, CDateTime Date) { - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<> time(a, b); - CDateTime delta = time(gen); - return Date + (CDateTime) (delta / SecsPerDay); + void CWebService::InitServerList() { + m_DefaultServer.Value().Name() = m_DefaultServer.Name(); + m_DefaultServer.Value().PGP().Name = "PUBLIC"; + + if (m_Servers.Count() == 0) { +#ifdef _DEBUG + int index = m_Servers.AddPair(BPS_BM_DEBUG_ADDRESS, CContext(CLocation(BPS_SERVER_URL))); + m_Servers[index].Value().Name() = m_Servers[index].Name(); + m_Servers[index].Value().PGP().Name = "PUBLIC"; +#else + m_Servers.Add(m_DefaultServer); +#endif + } } //-------------------------------------------------------------------------------------------------------------- - void CWebService::LoadOAuth2(const CString &FileName, const CString &ProviderName, const CString &ApplicationName, - CProviders &Providers) { + void CWebService::UpdateServerList(const CString &Key) { + CStringPairs ServerList; + CStringList Keys; + ParsePGPKey(Key, ServerList, Keys); + + if (ServerList.Count() != 0) { + CStringPairs::ConstEnumerator em(ServerList); + while (em.MoveNext()) { + const auto ¤t = em.Current(); + if (m_Servers.IndexOfName(current.Name()) == -1 && !current.Value().IsEmpty()) { + m_Servers.AddPair(current.Name(), CContext(CLocation(current.Value()))); + auto &Context = m_Servers.Last().Value(); + Context.Name() = current.Name(); + Context.PGP().Name = "PUBLIC"; + Context.PGP().Key = Key; + Context.BTCKeys() = Keys; + } + } + } + } + //-------------------------------------------------------------------------------------------------------------- + + void CWebService::UpdateOAuth2() { + const auto &oauth2 = Config()->IniFile().ReadString(CONFIG_SECTION_NAME, "oauth2", "oauth2/service.json"); + const auto &provider = CString(SYSTEM_PROVIDER_NAME); + const auto &application = CString(SERVICE_APPLICATION_NAME); + + for (int i = 0; i < m_Servers.Count(); i++) { + auto &Context = m_Servers[i].Value(); + if (!oauth2.empty() && Context.Status() == Context::csInitialization) { + LoadOAuth2(oauth2, provider, application, Context.Providers()); + Context.SetStatus(Context::csInitialized); + } + Context.SetCheckDate(0); + } + } + //-------------------------------------------------------------------------------------------------------------- + + void CWebService::LoadOAuth2(const CString &FileName, const CString &ProviderName, const CString &ApplicationName, CProviders &Providers) { CString ConfigFile(FileName); if (!path_separator(ConfigFile.front())) { @@ -136,6 +171,12 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- + void CWebService::CheckKeyForNull(LPCTSTR Key, LPCTSTR Value) { + if (Value == nullptr) + throw ExceptionFrm("Invalid format: key \"%s\" cannot be empty.", Key); + } + //-------------------------------------------------------------------------------------------------------------- + bool CWebService::FindURLInLine(const CString &Line, CStringList &List) { CString URL; @@ -196,12 +237,6 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void CWebService::CheckKeyForNull(LPCTSTR Key, LPCTSTR Value) { - if (Value == nullptr) - throw ExceptionFrm("Invalid format: key \"%s\" cannot be empty.", Key); - } - //-------------------------------------------------------------------------------------------------------------- - int CWebService::CheckFee(const CString &Fee) { if (!Fee.IsEmpty()) { @@ -236,186 +271,59 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void CWebService::ExceptionToJson(int ErrorCode, const std::exception &E, CString& Json) { - Json.Format(R"({"error": {"code": %u, "message": "%s"}})", ErrorCode, Delphi::Json::EncodeJsonString(E.what()).c_str()); - } - //-------------------------------------------------------------------------------------------------------------- + void CWebService::CreateAccessToken(const CProvider &Provider, const CString &Application, CContext &Context) { - CString CWebService::CreateToken(const CProvider &Provider, const CString &Application) { - auto token = jwt::create() - .set_issuer(Provider.Issuer(Application)) - .set_audience(Provider.ClientId(Application)) - .set_issued_at(std::chrono::system_clock::now()) - .set_expires_at(std::chrono::system_clock::now() + std::chrono::seconds{3600}) - .sign(jwt::algorithm::hs256{std::string(Provider.Secret(Application))}); - - return token; - } - //-------------------------------------------------------------------------------------------------------------- - - void CWebService::FetchAccessToken(const CString &URI, const CString &Assertion, COnSocketExecuteEvent &&OnDone, - COnSocketExceptionEvent &&OnFailed) { - - auto OnRequest = [](CHTTPClient *Sender, CHTTPRequest *ARequest) { - - const auto &token_uri = Sender->Data()["token_uri"]; - const auto &grant_type = Sender->Data()["grant_type"]; - const auto &assertion = Sender->Data()["assertion"]; - - ARequest->Content = _T("grant_type="); - ARequest->Content << CHTTPServer::URLEncode(grant_type); - - ARequest->Content << _T("&assertion="); - ARequest->Content << CHTTPServer::URLEncode(assertion); - - CHTTPRequest::Prepare(ARequest, _T("POST"), token_uri.c_str(), _T("application/x-www-form-urlencoded")); - - DebugRequest(ARequest); - }; - - auto OnException = [this](CTCPConnection *Sender, const Delphi::Exception::Exception &E) { - - auto pConnection = dynamic_cast (Sender); - auto pClient = dynamic_cast (pConnection->Client()); - - DebugReply(pConnection->Reply()); - - m_FixedDate = Now() + (CDateTime) 30 / SecsPerDay; - - Log()->Error(APP_LOG_ERR, 0, "[%s:%d] %s", pClient->Host().c_str(), pClient->Port(), E.what()); - }; - - CLocation token_uri(URI); - - auto pClient = GetClient(token_uri.hostname, token_uri.port); - - pClient->Data().Values("token_uri", token_uri.pathname); - pClient->Data().Values("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"); - pClient->Data().Values("assertion", Assertion); - - pClient->OnRequest(OnRequest); - pClient->OnExecute(static_cast(OnDone)); - pClient->OnException(OnFailed == nullptr ? OnException : static_cast(OnFailed)); - - pClient->Active(true); - } - //-------------------------------------------------------------------------------------------------------------- - - void CWebService::CreateAccessToken(const CProvider &Provider, const CString &Application, CStringList &Tokens) { - - auto OnDone = [this, &Tokens](CTCPConnection *Sender) { + auto OnDone = [&Context](CTCPConnection *Sender) { auto pConnection = dynamic_cast (Sender); auto pReply = pConnection->Reply(); DebugReply(pReply); - const CJSON Json(pReply->Content); + if (pReply->Status == CHTTPReply::ok) { + const CJSON Json(pReply->Content); - Tokens.Values("access_token", Json["access_token"].AsString()); + Context.SetStatus(csAuthorized); - m_Status = psRunning; + Context.Session() = Json["session"].AsString(); + Context.Secret() = Json["secret"].AsString(); - return true; - }; + Context.Tokens().Values("access_token", Json["access_token"].AsString()); - CString server_uri("http://localhost:4977"); - - const auto &token_uri = Provider.TokenURI(Application); - const auto &service_token = CreateToken(Provider, Application); - - Tokens.Values("service_token", service_token); - - if (!token_uri.IsEmpty()) { - FetchAccessToken(token_uri.front() == '/' ? server_uri + token_uri : token_uri, service_token, OnDone); - } - } - //-------------------------------------------------------------------------------------------------------------- - - void CWebService::FetchCerts(CProvider &Provider, const CString &Application) { - - const auto& URI = Provider.CertURI(Application); - - if (URI.IsEmpty()) { - Log()->Error(APP_LOG_INFO, 0, _T("Certificate URI in provider \"%s\" is empty."), Provider.Name().c_str()); - return; - } - - Log()->Error(APP_LOG_INFO, 0, _T("Trying to fetch public keys from: %s"), URI.c_str()); - - auto OnRequest = [&Provider, &Application](CHTTPClient *Sender, CHTTPRequest *ARequest) { - const auto& client_x509_cert_url = std::string(Provider.Applications()[Application]["client_x509_cert_url"].AsString()); - - Provider.KeyStatusTime(Now()); - Provider.KeyStatus(ksFetching); - - CLocation Location(client_x509_cert_url); - CHTTPRequest::Prepare(ARequest, "GET", Location.pathname.c_str()); - }; - - auto OnExecute = [this, &Provider, &Application](CTCPConnection *AConnection) { - - auto pConnection = dynamic_cast (AConnection); - auto pReply = pConnection->Reply(); - - try { - DebugRequest(pConnection->Request()); - DebugReply(pReply); - - Provider.KeyStatusTime(Now()); - - Provider.Keys().Clear(); - Provider.Keys() << pReply->Content; - - Provider.KeyStatus(ksSuccess); - - CreateAccessToken(Provider, Application, m_Tokens[Provider.Name()]); - } catch (Delphi::Exception::Exception &E) { - Provider.KeyStatus(ksFailed); - Log()->Error(APP_LOG_ERR, 0, "[Certificate] Message: %s", E.what()); + Context.SetFixedDate(0); + Context.SetCheckDate(Now() + (CDateTime) 55 / MinsPerDay); // 55 min } - pConnection->CloseConnection(true); return true; }; - auto OnException = [&Provider](CTCPConnection *AConnection, const Delphi::Exception::Exception &E) { - auto pConnection = dynamic_cast (AConnection); - auto pClient = dynamic_cast (pConnection->Client()); - - Provider.KeyStatusTime(Now()); - Provider.KeyStatus(ksFailed); - - Log()->Error(APP_LOG_ERR, 0, "[%s:%d] %s", pClient->Host().c_str(), pClient->Port(), E.what()); + auto OnHTTPClient = [this](const CLocation &URI) { + return GetClient(URI.hostname, URI.port); }; - CLocation Location(URI); - auto pClient = GetClient(Location.hostname, Location.port); + CString server_uri(Context.URL().Origin()); - pClient->OnRequest(OnRequest); - pClient->OnExecute(OnExecute); - pClient->OnException(OnException); + const auto &token_uri = Provider.TokenURI(Application); + const auto &service_token = CToken::CreateToken(Provider, Application); - pClient->Active(true); + Context.Tokens().Values("service_token", service_token); + + if (!token_uri.IsEmpty()) { + CToken::FetchAccessToken(token_uri.front() == '/' ? server_uri + token_uri : token_uri, service_token, OnHTTPClient, OnDone); + } } //-------------------------------------------------------------------------------------------------------------- - void CWebService::FetchProviders() { - for (int i = 0; i < m_Providers.Count(); i++) { - auto& Provider = m_Providers[i].Value(); + void CWebService::FetchProviders(CDateTime Now, CContext &Context) { + for (int i = 0; i < Context.Providers().Count(); i++) { + auto &Provider = Context.Providers()[i].Value(); for (int j = 0; j < Provider.Applications().Count(); ++j) { const auto &app = Provider.Applications().Members(j); if (app["type"].AsString() == "service_account") { - if (!app["auth_provider_x509_cert_url"].AsString().IsEmpty()) { - if (Provider.KeyStatus() == ksUnknown) { - FetchCerts(Provider, app.String()); - } - } else { - if (Provider.KeyStatus() == ksUnknown) { - Provider.KeyStatusTime(Now()); - CreateAccessToken(Provider, app.String(), m_Tokens[Provider.Name()]); - Provider.KeyStatus(ksSuccess); - } + if (Provider.KeyStatus() == ksUnknown) { + CreateAccessToken(Provider, app.String(), Context); + Provider.KeyStatusTime(Now); + Provider.KeyStatus(ksSuccess); } } } @@ -423,19 +331,22 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void CWebService::CheckProviders() { - for (int i = 0; i < m_Providers.Count(); i++) { - auto& Provider = m_Providers[i].Value(); + void CWebService::CheckProviders(CDateTime Now, CContext &Context) { + for (int i = 0; i < Context.Providers().Count(); i++) { + auto& Provider = Context.Providers()[i].Value(); if (Provider.KeyStatus() != ksUnknown) { - Provider.KeyStatusTime(Now()); + Provider.KeyStatusTime(Now); Provider.KeyStatus(ksUnknown); } } } //-------------------------------------------------------------------------------------------------------------- - void CWebService::DoVerbose(CSocketEvent *Sender, CTCPConnection *AConnection, LPCTSTR AFormat, va_list args) { - Log()->Debug(0, AFormat, args); + int CWebService::NextServerIndex() { + m_ServerIndex++; + if (m_ServerIndex >= m_Servers.Count()) + m_ServerIndex = -1; + return m_ServerIndex; } //-------------------------------------------------------------------------------------------------------------- @@ -574,13 +485,13 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void CWebService::RouteUser(CHTTPServerConnection *AConnection, const CString& Method, const CString& URI) { + void CWebService::DoUser(CHTTPServerConnection *AConnection, const CString& Method, const CString& URI) { auto pProxy = GetProxy(AConnection); auto pServerRequest = AConnection->Request(); auto pProxyRequest = pProxy->Request(); - const auto& caModuleAddress = Config()->IniFile().ReadString("module", "address", ""); + const auto& caModuleAddress = m_Module["address"]; const auto& caOrigin = pServerRequest->Headers["origin"]; const auto& caUserAddress = pServerRequest->Params["address"]; @@ -588,7 +499,7 @@ namespace Apostol { const auto& pgpValue = pServerRequest->Params["pgp"]; const auto& caServerParam = pServerRequest->Params["server"]; - const auto& caServer = caServerParam.IsEmpty() ? CurrentServer().Value().URI : caServerParam; + const auto& caServer = caServerParam.IsEmpty() ? m_CurrentServer.URL().Origin() : caServerParam; CLocation Location(caServer); @@ -766,8 +677,8 @@ namespace Apostol { } } - //DebugMessage("[RouteUser] Server request:\n%s\n", pServerRequest->Content.c_str()); - //DebugMessage("[RouteUser] sPayload:\n%s\n", sPayload.c_str()); + //DebugMessage("[DoUser] Server request:\n%s\n", pServerRequest->Content.c_str()); + //DebugMessage("[DoUser] sPayload:\n%s\n", sPayload.c_str()); CJSON Json(jvtObject); @@ -786,7 +697,7 @@ namespace Apostol { CHTTPRequest::Prepare(pProxyRequest, Method.c_str(), URI.c_str()); - pProxyRequest->AddHeader("Authorization", "Bearer " + m_Tokens[SYSTEM_PROVIDER_NAME]["access_token"]); + pProxyRequest->AddHeader("Authorization", "Bearer " + m_CurrentServer.Tokens()["access_token"]); if (!caModuleAddress.IsEmpty()) pProxyRequest->AddHeader("Module-Address", caModuleAddress); @@ -860,14 +771,14 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void CWebService::RouteDeal(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI, const CString &Action) { + void CWebService::DoDeal(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI, const CString &Action) { auto pProxy = GetProxy(AConnection); auto pServerRequest = AConnection->Request(); auto pProxyRequest = pProxy->Request(); - const auto& caModuleAddress = Config()->IniFile().ReadString("module", "address", ""); - const auto& caModuleFee = Config()->IniFile().ReadString("module", "fee", "0.1%"); + const auto& caModuleAddress = m_Module["address"]; + const auto& caModuleFee = m_Module["fee"]; const auto checkFee = CheckFee(caModuleFee); if (checkFee == -1) @@ -879,7 +790,7 @@ namespace Apostol { const auto& pgpValue = pServerRequest->Params["pgp"]; const auto& caServerParam = pServerRequest->Params["server"]; - const auto& caServer = caServerParam.IsEmpty() ? CurrentServer().Value().URI : caServerParam; + const auto& caServer = caServerParam.IsEmpty() ? m_CurrentServer.URL().Origin() : caServerParam; CLocation Location(caServer); @@ -1167,7 +1078,7 @@ namespace Apostol { Node = YAML::Load(pServerRequest->Content.c_str()); } - const auto &BTCKeys = CurrentServer().Value().BTCKeys; + const auto &BTCKeys = m_CurrentServer.BTCKeys(); if (BTCKeys.Count() < 2) throw ExceptionFrm("Bitcoin keys cannot be empty."); @@ -1222,8 +1133,8 @@ namespace Apostol { } } - //DebugMessage("[RouteDeal] Server request:\n%s\n", pServerRequest->Content.c_str()); - //DebugMessage("[RouteDeal] sPayload:\n%s\n", sPayload.c_str()); + //DebugMessage("[DoDeal] Server request:\n%s\n", pServerRequest->Content.c_str()); + //DebugMessage("[DoDeal] sPayload:\n%s\n", sPayload.c_str()); CJSON Json(jvtObject); @@ -1243,7 +1154,7 @@ namespace Apostol { CHTTPRequest::Prepare(pProxyRequest, Method.c_str(), URI.c_str()); - pProxyRequest->AddHeader("Authorization", "Bearer " + m_Tokens[SYSTEM_PROVIDER_NAME]["access_token"]); + pProxyRequest->AddHeader("Authorization", "Bearer " + m_CurrentServer.Tokens()["access_token"]); if (!caModuleAddress.IsEmpty()) pProxyRequest->AddHeader("Module-Address", caModuleAddress); @@ -1259,7 +1170,7 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void CWebService::RouteSignature(CHTTPServerConnection *AConnection) { + void CWebService::DoSignature(CHTTPServerConnection *AConnection) { auto pRequest = AConnection->Request(); auto pReply = AConnection->Reply(); @@ -1269,7 +1180,7 @@ namespace Apostol { return; } - const auto& caServerKey = CurrentServer().Value().PGP.Key; + const auto& caServerKey = m_CurrentServer.PGP().Key; if (caServerKey.IsEmpty()) throw ExceptionFrm("Server PGP key not added."); @@ -1350,9 +1261,9 @@ namespace Apostol { } CString sRoute; - for (int I = 0; I < slRouts.Count(); ++I) { + for (int i = 0; i < slRouts.Count(); ++i) { sRoute.Append('/'); - sRoute.Append(slRouts[I]); + sRoute.Append(slRouts[i]); } try { @@ -1370,19 +1281,19 @@ namespace Apostol { pRequest->Content.Clear(); - RouteUser(AConnection, "GET", sRoute); + DoUser(AConnection, "GET", sRoute); } else if (caCommand == "account" && caAction == "status") { pRequest->Content.Clear(); - RouteUser(AConnection, "GET", sRoute); + DoUser(AConnection, "GET", sRoute); } else if (caCommand == "deal" && caAction == "status") { pRequest->Content.Clear(); - RouteDeal(AConnection, "GET", sRoute, caAction); + DoDeal(AConnection, "GET", sRoute, caAction); } else if (caCommand == "bc" && caAction == "history") { @@ -1409,10 +1320,10 @@ namespace Apostol { } else if (caCommand == "bc" && caAction == "header") { - const auto& LHeight = pRequest->Params["height"]; - const auto& LHash = pRequest->Params["hash"]; + const auto& caHeight = pRequest->Params["height"]; + const auto& caHash = pRequest->Params["hash"]; - if (LHeight.IsEmpty() && LHash.IsEmpty()) { + if (caHeight.IsEmpty() && caHash.IsEmpty()) { AConnection->SendStockReply(CHTTPReply::bad_request); return; } @@ -1420,10 +1331,10 @@ namespace Apostol { try { CJSON header; - if (!LHash.IsEmpty()) { - fetch_header(hash256(std::string(LHash.c_str())), header); + if (!caHash.IsEmpty()) { + fetch_header(hash256(std::string(caHash.c_str())), header); } else { - uint32_t height = StrToInt(LHeight.c_str()); + uint32_t height = StrToInt(caHeight.c_str()); fetch_header(height, header); } @@ -1504,24 +1415,24 @@ namespace Apostol { } CString sRoute; - for (int I = 0; I < slRouts.Count(); ++I) { + for (int i = 0; i < slRouts.Count(); ++i) { sRoute.Append('/'); - sRoute.Append(slRouts[I]); + sRoute.Append(slRouts[i]); } try { if (caCommand == "account") { - RouteUser(AConnection, "POST", sRoute); + DoUser(AConnection, "POST", sRoute); } else if (caCommand == "deal") { - RouteDeal(AConnection, "POST", sRoute, caAction); + DoDeal(AConnection, "POST", sRoute, caAction); } else if (caCommand == "signature") { - RouteSignature(AConnection); + DoSignature(AConnection); } else { @@ -1538,37 +1449,11 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - const CServer &CWebService::CurrentServer() const { + const CContext &CWebService::CurrentServer() const { return m_CurrentServer; } //-------------------------------------------------------------------------------------------------------------- - 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_ActiveIndex == -1) - return m_Servers[0]; - 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]; - } - //-------------------------------------------------------------------------------------------------------------- - bool CWebService::CheckVerifyPGPSignature(int VerifyPGPSignature, CString &Message) { if (VerifyPGPSignature == -2) { Message = "PGP public key is not meaningful."; @@ -1617,29 +1502,22 @@ namespace Apostol { for (int i = 0; i < List.Count(); i++) { const auto& uid = List[i]; + + DebugMessage("%s (%s)\n", uid.Name.c_str(), uid.Desc.c_str()); + const auto& name = uid.Name.Lower(); const auto& data = uid.Desc.Lower(); if (name == "technical_data") { SplitColumns(data, Data, ';'); - DebugMessage("Technical data: "); if (Data.Count() == 3) { m_SyncPeriod = StrToIntDef(Data[1].Trim().c_str(), BPS_DEFAULT_SYNC_PERIOD); - DebugMessage("\n - Fee : %s", Data[0].Trim().c_str()); - DebugMessage("\n - Period: %s", Data[1].Trim().c_str()); - DebugMessage("\n - Keys : %s", Data[2].Trim().c_str()); } else if (Data.Count() == 2) { m_SyncPeriod = StrToIntDef(Data[0].Trim().c_str(), BPS_DEFAULT_SYNC_PERIOD); - DebugMessage("\n - Period: %s", Data[0].Trim().c_str()); - DebugMessage("\n - Keys : %s", Data[1].Trim().c_str()); } else if (Data.Count() == 1) { m_SyncPeriod = StrToIntDef(Data[0].Trim().c_str(), BPS_DEFAULT_SYNC_PERIOD); - DebugMessage("\n - Period: %s", Data[0].Trim().c_str()); - } else { - DebugMessage("Unknown error."); } - } if (uid.Name.Length() >= 35 && uid.Name.SubString(0, 3) == BM_PREFIX) { CStringList urlList; if (FindURLInLine(uid.Desc, urlList)) { @@ -1659,8 +1537,9 @@ namespace Apostol { Name = "bitcoin_key"; Name << i; const auto& key = KeyList[Name]; - if (!key.IsEmpty()) + if (!key.IsEmpty()) { BTCKeys.Add(key); + } } } //-------------------------------------------------------------------------------------------------------------- @@ -1681,25 +1560,30 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void CWebService::FetchPGP(CServer &Server) { + void CWebService::FetchPGP(CContext &Context) { - Log()->Debug(0, "Trying to fetch a PGP key \"%s\" from: %s", Server.Name().c_str(), Server.Value().URI.c_str()); + Log()->Debug(APP_LOG_DEBUG_CORE, "Trying to fetch a PGP key \"%s\" from: %s", Context.Name().c_str(), Context.URL().Origin().c_str()); - auto OnRequest = [this, &Server](CHTTPClient *Sender, CHTTPRequest *ARequest) { - auto &PGP = Server.Value().PGP; + auto OnRequest = [&Context](CHTTPClient *Sender, CHTTPRequest *ARequest) { - PGP.StatusTime = Now(); - PGP.Status = CKeyContext::ksFetching; - PGP.RunTime = PGP.StatusTime + (CDateTime) 30 / SecsPerDay; + Context.PGP().Status = CKeyContext::ksFetching; + Context.PGP().StatusTime = Now(); - CHTTPRequest::Prepare(ARequest, "GET", CString().Format("/api/v1/key/public?account=%s&type=pgp", PGP.Name.c_str()).c_str()); + ARequest->ContentType = CHTTPRequest::json; + ARequest->Content = CString().Format(R"({"type": "pgp", "account": "%s", "code": "%s", "fields": ["data"]})", Context.Name().c_str(), Context.PGP().Name.c_str()); - ARequest->AddHeader("Authorization", "Bearer " + m_Tokens[SYSTEM_PROVIDER_NAME]["access_token"]); + CHTTPRequest::Prepare(ARequest, "POST", "/api/v1/key/public"); + + const auto &access_token = Context.Tokens()["access_token"]; + + if (!access_token.empty()) { + ARequest->AddHeader("Authorization", "Bearer " + access_token); + } DebugRequest(ARequest); }; - auto OnExecute = [this, &Server](CTCPConnection *AConnection) { + auto OnExecute = [this, &Context](CTCPConnection *AConnection) { auto pConnection = dynamic_cast (AConnection); @@ -1708,47 +1592,24 @@ namespace Apostol { DebugReply(pReply); - auto &PGP = Server.Value().PGP; - - PGP.StatusTime = Now(); - PGP.Status = CKeyContext::ksError; - PGP.RunTime = PGP.StatusTime + (CDateTime) 30 / SecsPerDay; + CString Key; try { - JsonStringToKey(pReply->Content, PGP.Key); + JsonStringToKey(pReply->Content, Key); - if (PGP.Key.IsEmpty()) + if (Key.IsEmpty()) throw Delphi::Exception::Exception("Not found."); - CStringPairs ServerList; + Context.PGP().Status = CKeyContext::ksSuccess; + Context.PGP().StatusTime = Now(); - ParsePGPKey(PGP.Key, ServerList, Server.Value().BTCKeys); + Context.PGP().Key = Key; - 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())); - } - } - } + UpdateServerList(Key); - 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()); - - const auto &key = m_CurrentServer.Value().PGP.Key; - Log()->Debug(APP_LOG_DEBUG_CORE, "[PGP]\n%s", key.IsEmpty() ? "" : key.c_str()); - - const auto &keys = m_CurrentServer.Value().BTCKeys.Text(); - Log()->Debug(APP_LOG_DEBUG_CORE, "[BTCKeys]\n%s", keys.IsEmpty() ? "" : keys.c_str()); + Context.SetStatus(csRunning); } catch (Delphi::Exception::Exception &e) { - Log()->Error(APP_LOG_INFO, 0, "[CurrentServer] Message: %s", e.what()); + Log()->Error(APP_LOG_INFO, 0, "[FetchPGP] %s", e.what()); } pConnection->CloseConnection(true); @@ -1757,28 +1618,27 @@ namespace Apostol { return true; }; - auto OnException = [&Server](CTCPConnection *AConnection, const Delphi::Exception::Exception &E) { + auto OnException = [&Context](CTCPConnection *AConnection, const Delphi::Exception::Exception &E) { auto pConnection = dynamic_cast (AConnection); - if (pConnection != nullptr) { auto pClient = dynamic_cast (pConnection->Client()); - 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; - PGP.RunTime = PGP.StatusTime + (CDateTime) 30 / SecsPerDay; } - DebugReply(pConnection->Reply()); } + + Context.SetStatus(Context::csAuthorized); + + Context.PGP().Status = CKeyContext::ksError; + Context.PGP().StatusTime = Now(); }; - CLocation Location(Server.Value().URI); - auto pClient = GetClient(Location.hostname, Location.port == 0 ? BPS_SERVER_PORT : Location.port); + Context.PGP().Status = CKeyContext::ksUnknown; + Context.PGP().StatusTime = Now(); + Context.PGP().RunTime = Context.PGP().StatusTime; + + auto pClient = GetClient(Context.URL().hostname, Context.URL().port == 0 ? BPS_SERVER_PORT : Context.URL().port); pClient->OnRequest(OnRequest); pClient->OnExecute(OnExecute); @@ -1788,143 +1648,59 @@ namespace Apostol { } //-------------------------------------------------------------------------------------------------------------- - void CWebService::FetchBTC(CServer &Server) { - - Log()->Debug(0, "Trying to fetch a BTC key \"%s\" from: %s", Server.Name().c_str(), Server.Value().URI.c_str()); - - auto OnRequest = [this, &Server](CHTTPClient *Sender, CHTTPRequest *ARequest) { - - auto &BTC = Server.Value().BTC; - - 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, &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()) { - Server.Value().BTCKeys.Add(Key); - } - } catch (Delphi::Exception::Exception &e) { - Log()->Error(APP_LOG_INFO, 0, "[BTC] Message: %s", e.what()); - - 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 - } - } - - pConnection->CloseConnection(true); - - return true; - }; - - 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(Server.Value().URI); - auto pClient = GetClient(Location.hostname, Location.port == 0 ? BPS_SERVER_PORT : Location.port); - - pClient->OnRequest(OnRequest); - pClient->OnExecute(OnExecute); - pClient->OnException(OnException); - - pClient->Active(true); - } - //-------------------------------------------------------------------------------------------------------------- - - 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); - } - } - } - //-------------------------------------------------------------------------------------------------------------- - void CWebService::Reload() { + Config()->IniFile().ReadSectionValues("module", &m_Module); - m_Providers.Clear(); - m_Tokens.Clear(); + const auto& caPublicKey = Config()->IniFile().ReadString("pgp", "public", "dm.pub"); - const auto &oauth2 = Config()->IniFile().ReadString(CONFIG_SECTION_NAME, "oauth2", "oauth2/service.json"); - const auto &provider = CString(SYSTEM_PROVIDER_NAME); - const auto &application = CString(SERVICE_APPLICATION_NAME); + if (FileExists(caPublicKey.c_str())) { + CString Key; + Key.LoadFromFile(caPublicKey.c_str()); - if (!oauth2.empty()) { - m_Tokens.AddPair(provider, CStringList()); - LoadOAuth2(oauth2, provider, application, m_Providers); + UpdateServerList(Key); + UpdateOAuth2(); + } else { + Log()->Error(APP_LOG_WARN, 0, APP_FILE_NOT_FOUND, caPublicKey.c_str()); } - - m_FixedDate = 0; } //-------------------------------------------------------------------------------------------------------------- - void CWebService::Initialization(CModuleProcess *AProcess) { - CApostolModule::Initialization(AProcess); - Reload(); - } - //-------------------------------------------------------------------------------------------------------------- + void CWebService::Heartbeat(CDateTime Now) { + for (int i = 0; i < m_Servers.Count(); i++) { + auto &Context = m_Servers[i].Value(); - void CWebService::Heartbeat() { - const auto now = Now(); + if (Now >= Context.CheckDate()) { + Context.SetCheckDate(Now + (CDateTime) 30 / SecsPerDay); // 30 sec + if ((Context.Status() == Context::csInitialized) || (Context.Status() == Context::csRunning)) { + Context.SetStatus(Context::csAuthorization); - if ((now >= m_FixedDate)) { - m_FixedDate = now + (CDateTime) 55 / MinsPerDay; // 55 min - CheckProviders(); - FetchProviders(); - } + CheckProviders(Now, Context); + FetchProviders(Now, Context); + } + } - if (m_Servers.Count() == 0) { -#ifdef _DEBUG - int Index = m_Servers.AddPair(BPS_BM_DEBUG_ADDRESS, CServerContext(BPS_SERVER_URL)); - m_Servers[Index].Value().PGP.Name = m_Servers[Index].Name(); -#else - m_Servers.Add(m_DefaultServer); -#endif - } + if (Context.Status() == Context::csAuthorized) { + if (Now >= Context.FixedDate()) { + Context.SetFixedDate(Now + (CDateTime) 30 / SecsPerDay); // 30 sec + Context.SetStatus(Context::csInProgress); - if (m_Status == psRunning) { - FetchKeys(now); + FetchPGP(Context); + } + } + + if (Context.Status() >= Context::csAuthorized) { + if (Now >= m_NexServerTime) { + m_NexServerTime = GetRandomDate(10 * 60, m_SyncPeriod * 60, Now); + m_CurrentServer = Context; + } + } } } //-------------------------------------------------------------------------------------------------------------- bool CWebService::Enabled() { if (m_ModuleStatus == msUnknown) - m_ModuleStatus = msEnabled; + m_ModuleStatus = Config()->IniFile().ReadBool(SectionName().c_str(), "enable", true) ? msEnabled : msDisabled; return m_ModuleStatus == msEnabled; } //-------------------------------------------------------------------------------------------------------------- diff --git a/src/modules/Workers/WebService/WebService.hpp b/src/modules/Workers/WebService/WebService.hpp index 15eb1ec..ce0f531 100644 --- a/src/modules/Workers/WebService/WebService.hpp +++ b/src/modules/Workers/WebService/WebService.hpp @@ -1,8 +1,8 @@ /*++ -Library name: +Program name: - apostol-module + dm Module Name: @@ -21,104 +21,15 @@ Author: --*/ -#ifndef APOSTOL_WEBSERVICE_HPP -#define APOSTOL_WEBSERVICE_HPP -//---------------------------------------------------------------------------------------------------------------------- -#define BPS_DEFAULT_SYNC_PERIOD 30 -#define BPS_SERVER_PORT 4988 -#define BPS_SERVER_URL "http://localhost:4988" -#define BPS_BM_SERVER_ADDRESS "BM-2cX8y9u9yEi3fdqQfndx9F6NdR5Hv79add" -#define BPS_BM_DEBUG_ADDRESS "BM-2cXtL92m3CavBKx8qsV2LbZtAU3eQxW2rB" +#ifndef DM_WEB_SERVICE_MODULE_HPP +#define DM_WEB_SERVICE_MODULE_HPP //---------------------------------------------------------------------------------------------------------------------- extern "C++" { namespace Apostol { - namespace Workers { - - struct CKeyContext { - - CString Name; - CString Key; - - enum CKeyStatus { - ksUnknown = -1, - ksFetching, - ksSuccess, - ksError, - } Status; - - CDateTime StatusTime; - CDateTime RunTime; - - CKeyContext(): Status(ksUnknown), StatusTime(Now()), RunTime(0) { - Name = BPS_BM_SERVER_ADDRESS; - } - - 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 {}; - CKeyContext BTC {}; - - CStringList BTCKeys; - - CServerContext() = default; - - explicit CServerContext(const CString& URI) { - 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; - typedef TPairs CServerList; + namespace Module { //-------------------------------------------------------------------------------------------------------------- @@ -129,68 +40,62 @@ namespace Apostol { class CWebService: public CApostolModule { private: + CStringList m_Module; + + int m_ServerIndex; + CProcessStatus m_Status; - CServer m_DefaultServer {}; - CServer m_CurrentServer {}; + CContextPair m_DefaultServer { BPS_BM_SERVER_ADDRESS, CContext(CLocation(BPS_SERVER_URL)) }; + CContextList m_Servers {}; + + CContext m_CurrentServer {}; int m_SyncPeriod; - int m_ActiveIndex; - CDateTime m_FixedDate; - - CServerList m_Servers; - - CProviders m_Providers; - CStringListPairs m_Tokens; + CDateTime m_NexServerTime; CHTTPProxyManager m_ProxyManager; - CHTTPProxy *GetProxy(CHTTPServerConnection *AConnection); - void InitMethods() override; - void FetchCerts(CProvider &Provider, const CString &Application); + void InitServerList(); + void UpdateServerList(const CString &Key); + void UpdateOAuth2(); - void FetchProviders(); - void CheckProviders(); + void FetchProviders(CDateTime Now, CContext &Context); + void CheckProviders(CDateTime Now, CContext &Context); - void RouteUser(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI); - void RouteDeal(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI, const CString &Action); + void CreateAccessToken(const CProvider &Provider, const CString &Application, CContext &Context); + void ParsePGPKey(const CString& Key, CStringPairs& ServerList, CStringList& BTCKeys); - void RouteSignature(CHTTPServerConnection *AConnection); - - void FetchAccessToken(const CString &URI, const CString &Assertion, - COnSocketExecuteEvent && OnDone, COnSocketExceptionEvent && OnFailed = nullptr); - void CreateAccessToken(const CProvider &Provider, const CString &Application, CStringList &Tokens); - - static CString CreateToken(const CProvider& Provider, const CString &Application); + void FetchPGP(CContext &Context); protected: int NextServerIndex(); - const CServer &CurrentServer() const; + CHTTPProxy *GetProxy(CHTTPServerConnection *AConnection); - CServer &ActiveServer(); - const CServer &ActiveServer() const; - - void FetchPGP(CServer& Server); - void FetchBTC(CServer& Server); + const CContext &CurrentServer() const; static int CheckFee(const CString& Fee); static void CheckKeyForNull(LPCTSTR Key, LPCTSTR Value); + void DoUser(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI); + void DoDeal(CHTTPServerConnection *AConnection, const CString &Method, const CString &URI, const CString &Action); + + void DoSignature(CHTTPServerConnection *AConnection); + void DoAPI(CHTTPServerConnection *AConnection); void DoGet(CHTTPServerConnection *AConnection) override; void DoPost(CHTTPServerConnection *AConnection); - void DoVerbose(CSocketEvent *Sender, CTCPConnection *AConnection, LPCTSTR AFormat, va_list args); bool DoProxyExecute(CTCPConnection *AConnection); void DoProxyException(CTCPConnection *AConnection, const Delphi::Exception::Exception &E); - void DoEventHandlerException(CPollEventHandler *AHandler, const Delphi::Exception::Exception &E); + void DoEventHandlerException(CPollEventHandler *AHandler, const Delphi::Exception::Exception &E) override; void DoProxyConnected(CObject *Sender); void DoProxyDisconnected(CObject *Sender); @@ -205,36 +110,25 @@ namespace Apostol { return new CWebService(AProcess); } - void Initialization(CModuleProcess *AProcess) override; - - void Heartbeat() override; + void Heartbeat(CDateTime Now) override; bool Enabled() override; - void FetchKeys(CDateTime Now); - void Reload(); static void JsonStringToKey(const CString& jsonString, CString& Key); - void ParsePGPKey(const CString& Key, CStringPairs& ServerList, CStringList& BTCKeys); - static void CheckDeal(const CDeal& Deal); static bool CheckVerifyPGPSignature(int VerifyPGPSignature, CString &Message); static int VerifyPGPSignature(const CString &ClearText, const CString &Key, CString &Message); static bool FindURLInLine(const CString &Line, CStringList &List); - static void ExceptionToJson(int ErrorCode, const std::exception &AException, CString& Json); - - static CDateTime GetRandomDate(int a, int b, CDateTime Date = Now()); - - static void LoadOAuth2(const CString &FileName, const CString &ProviderName, const CString &ApplicationName, - CProviders &Providers); + static void LoadOAuth2(const CString &FileName, const CString &ProviderName, const CString &ApplicationName, CProviders &Providers); }; } } -using namespace Apostol::Workers; +using namespace Apostol::Module; } -#endif //APOSTOL_WEBSERVICE_HPP +#endif //DM_WEB_SERVICE_MODULE_HPP diff --git a/src/modules/Workers/Workers.hpp b/src/modules/Workers/Workers.hpp index 73ae3f0..a77f8ef 100644 --- a/src/modules/Workers/Workers.hpp +++ b/src/modules/Workers/Workers.hpp @@ -25,10 +25,13 @@ Author: #define APOSTOL_WORKERS_HPP //---------------------------------------------------------------------------------------------------------------------- +#include "WebSocket/WebSocketClient.hpp" +#include "WebSocket/WebSocket.hpp" #include "WebService/WebService.hpp" //---------------------------------------------------------------------------------------------------------------------- static inline void CreateWorkers(CModuleProcess *AProcess) { + CWebSocketModule::CreateModule(AProcess); CWebService::CreateModule(AProcess); } diff --git a/www/dashboard/index.html b/www/dashboard/index.html index 037917a..6fe4548 100644 --- a/www/dashboard/index.html +++ b/www/dashboard/index.html @@ -582,7 +582,7 @@
- + BPS server URL.
@@ -1287,7 +1287,7 @@ let execute = $("button[id='btnDealForm']"); execute.prop('disabled', true); - AsyncFetch(api + '/deal/' + formOrder.val() + settings, 'POST', formData, {'Content-Type': 'multipart/form-data'}) + AsyncFetch(api + '/deal/' + formOrder.val().toLowerCase() + settings, 'POST', formData, {'Content-Type': 'multipart/form-data'}) .then(function(json) { let html; let payload;