EndpointProvider.cc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*
  2. * Copyright 1999-2019 Alibaba Cloud All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <algorithm>
  17. #include <alibabacloud/core/EndpointProvider.h>
  18. #include <condition_variable>
  19. #include <iomanip>
  20. #include <json/json.h>
  21. #include <mutex>
  22. #include <sstream>
  23. #include <thread>
  24. #ifndef WIN32
  25. #include "LocalEndpoints.h"
  26. #include <alibabacloud/core/Utils.h>
  27. #else
  28. #include "LocalEndpointsForWindows.h"
  29. #endif
  30. namespace AlibabaCloud {
  31. namespace {
  32. #if defined(WIN32) && defined(_MSC_VER)
  33. #define strcasecmp _stricmp
  34. #define strncasecmp _strnicmp
  35. #else
  36. #include <strings.h>
  37. #endif
  38. std::mutex mutex;
  39. std::condition_variable cv;
  40. bool local_endpoints_loaded = false;
  41. bool local_endpoints_loading = false;
  42. typedef std::string productType;
  43. typedef std::string regionType;
  44. typedef std::string endpointType;
  45. typedef std::string mappingType;
  46. typedef std::vector<regionType> regionsType;
  47. typedef std::map<productType, endpointType> regionalType;
  48. typedef struct {
  49. regionsType regions;
  50. regionalType regional;
  51. } productInfoType;
  52. static std::vector<regionType> allRegions;
  53. static std::vector<productType> allProductsInLocalEndpoints;
  54. static std::map<productType, productInfoType> allLocalEndpoints;
  55. static void LoadLocalEndpoints() {
  56. Json::Reader reader;
  57. Json::Value value;
  58. std::unique_lock<std::mutex> lock(mutex);
  59. if (local_endpoints_loaded) {
  60. return;
  61. }
  62. #ifdef WIN32
  63. std::string LOCAL_ENDPOINTS_CONFIG = WIN_LOCAL_ENDPOINTS_CONFIG_1 +
  64. WIN_LOCAL_ENDPOINTS_CONFIG_2 +
  65. WIN_LOCAL_ENDPOINTS_CONFIG_3;
  66. #endif
  67. if (!reader.parse(LOCAL_ENDPOINTS_CONFIG, value)) {
  68. return;
  69. }
  70. cv.wait(lock, [] {
  71. return !local_endpoints_loading;
  72. }); // continue if loading completed
  73. local_endpoints_loading = true;
  74. auto regions = value["regions"];
  75. for (const auto &region : regions) {
  76. allRegions.push_back(region.asString());
  77. }
  78. auto products = value["products"];
  79. for (const auto &product : products) {
  80. allProductsInLocalEndpoints.push_back(product.asString());
  81. }
  82. auto endpoints = value["endpoints"];
  83. for (auto &product : allProductsInLocalEndpoints) {
  84. auto endpoint_per_product = endpoints[product];
  85. productInfoType p;
  86. auto regions = endpoint_per_product["regions"];
  87. auto regional = endpoint_per_product["regional"];
  88. for (auto &r : regions) {
  89. const std::string region = r.asString();
  90. p.regions.push_back(region);
  91. p.regional[region] = endpoint_per_product["regional"][region].asString();
  92. }
  93. allLocalEndpoints[product] = p;
  94. }
  95. local_endpoints_loaded = true;
  96. local_endpoints_loading = false;
  97. lock.unlock();
  98. cv.notify_one();
  99. }
  100. } // namespace
  101. EndpointProvider::EndpointProvider(
  102. const std::shared_ptr<Location::LocationClient> &locationClient,
  103. const std::string regionId, const std::string product,
  104. const std::string serviceCode, int durationSeconds)
  105. : LocationClient(locationClient), regionId_(regionId), product_(product),
  106. serviceCode_(serviceCode), durationSeconds_(durationSeconds),
  107. cachedMutex_(), cachedEndpoint_(), expiry_() {
  108. transform(product_.begin(), product_.end(), product_.begin(), ::tolower);
  109. loadLocalProductsInfo();
  110. }
  111. EndpointProvider::EndpointProvider(const Credentials &credentials,
  112. const ClientConfiguration &configuration,
  113. const std::string &regionId,
  114. const std::string &product,
  115. const std::string &serviceCode,
  116. int durationSeconds)
  117. : LocationClient(credentials, configuration), regionId_(regionId),
  118. product_(product), serviceCode_(serviceCode),
  119. durationSeconds_(durationSeconds), cachedMutex_(), cachedEndpoint_(),
  120. expiry_() {
  121. transform(product_.begin(), product_.end(), product_.begin(), ::tolower);
  122. loadLocalProductsInfo();
  123. }
  124. EndpointProvider::~EndpointProvider() {}
  125. bool EndpointProvider::loadLocalProductsInfo() {
  126. LoadLocalEndpoints();
  127. return true;
  128. }
  129. std::string EndpointProvider::localEndpoint(const std::string regionId,
  130. const std::string product) {
  131. if (!local_endpoints_loaded) {
  132. // impossible
  133. return std::string();
  134. }
  135. std::vector<regionType>::iterator allRegionsit;
  136. allRegionsit = std::find(allRegions.begin(), allRegions.end(), regionId);
  137. if (allRegionsit == allRegions.end()) {
  138. return std::string();
  139. }
  140. std::vector<productType>::iterator allProductsInLocalEndpointsit;
  141. allProductsInLocalEndpointsit =
  142. std::find(allProductsInLocalEndpoints.begin(),
  143. allProductsInLocalEndpoints.end(), product);
  144. if (allProductsInLocalEndpointsit == allProductsInLocalEndpoints.end()) {
  145. return std::string();
  146. }
  147. std::vector<regionType> vec = allLocalEndpoints[product].regions;
  148. std::vector<regionType>::iterator it;
  149. it = std::find(vec.begin(), vec.end(), regionId);
  150. if (it == vec.end()) {
  151. return std::string();
  152. }
  153. return allLocalEndpoints[product].regional[regionId];
  154. }
  155. bool EndpointProvider::checkExpiry() const {
  156. auto now = std::chrono::system_clock::now();
  157. auto diff =
  158. std::chrono::duration_cast<std::chrono::seconds>(now - expiry_).count();
  159. return (diff > 0 - 60);
  160. }
  161. EndpointProvider::EndpointOutcome EndpointProvider::getEndpoint() {
  162. // 1st priority: user specified via configuration
  163. if (!configuration().endpoint().empty()) {
  164. return EndpointOutcome(configuration().endpoint());
  165. }
  166. // 2nd priority: local configuration
  167. std::string endpoint = localEndpoint(regionId_, product_);
  168. if (!endpoint.empty()) {
  169. return EndpointOutcome(endpoint);
  170. }
  171. // service code is mandatory for location service.
  172. if (serviceCode_.empty()) {
  173. return EndpointOutcome(
  174. Error("InvalidRegionId", "Product[" + product_ + "] at region[" +
  175. regionId_ + "] does not exist."));
  176. }
  177. // 3rd priority: request from location service
  178. EndpointOutcome outcome = loadRemoteEndpoint();
  179. if (outcome.isSuccess()) {
  180. return outcome;
  181. }
  182. if (outcome.error().errorCode() == "Illegal Parameter") {
  183. return EndpointOutcome(Error("InvalidProduct", "Prodcut[" + serviceCode_ +
  184. "] does not exist."));
  185. }
  186. return outcome;
  187. }
  188. EndpointProvider::EndpointOutcome EndpointProvider::loadRemoteEndpoint() {
  189. if (checkExpiry()) {
  190. std::lock_guard<std::mutex> locker(cachedMutex_);
  191. if (checkExpiry()) {
  192. Location::Model::DescribeEndpointsRequest request;
  193. request.setId(regionId_);
  194. request.setServiceCode(serviceCode_);
  195. request.setType("openAPI");
  196. auto outcome = describeEndpoints(request);
  197. if (!outcome.isSuccess())
  198. return EndpointOutcome(outcome.error());
  199. auto all = outcome.result().endpoints();
  200. if (all.size() > 0)
  201. cachedEndpoint_ = all.front().endpoint;
  202. std::time_t t = std::time(nullptr) + durationSeconds_;
  203. expiry_ = std::chrono::system_clock::from_time_t(t);
  204. }
  205. }
  206. return EndpointOutcome(cachedEndpoint_);
  207. }
  208. } // namespace AlibabaCloud