EndpointProvider.cc 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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 <iomanip>
  19. #include <json/json.h>
  20. #include <sstream>
  21. #include <thread>
  22. #include <mutex>
  23. #include <condition_variable>
  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. {
  32. namespace
  33. {
  34. #if defined(WIN32) && defined(_MSC_VER)
  35. #define strcasecmp _stricmp
  36. #define strncasecmp _strnicmp
  37. #else
  38. #include <strings.h>
  39. #endif
  40. std::mutex mutex;
  41. std::condition_variable cv;
  42. bool local_endpoints_loaded = false;
  43. bool local_endpoints_loading = false;
  44. typedef std::string productType;
  45. typedef std::string regionType;
  46. typedef std::string endpointType;
  47. typedef std::string mappingType;
  48. typedef std::vector<regionType> regionsType;
  49. typedef std::map<productType, endpointType> regionalType;
  50. typedef struct
  51. {
  52. regionsType regions;
  53. regionalType regional;
  54. } productInfoType;
  55. static std::vector<regionType> allRegions;
  56. static std::vector<productType> allProductsInLocalEndpoints;
  57. static std::map<productType, productInfoType> allLocalEndpoints;
  58. static void LoadLocalEndpoints()
  59. {
  60. Json::Reader reader;
  61. Json::Value value;
  62. std::unique_lock<std::mutex> lock(mutex);
  63. if (local_endpoints_loaded)
  64. {
  65. return;
  66. }
  67. #ifdef WIN32
  68. std::string LOCAL_ENDPOINTS_CONFIG = WIN_LOCAL_ENDPOINTS_CONFIG_1 +
  69. WIN_LOCAL_ENDPOINTS_CONFIG_2 +
  70. WIN_LOCAL_ENDPOINTS_CONFIG_3;
  71. #endif
  72. if (!reader.parse(LOCAL_ENDPOINTS_CONFIG, value))
  73. {
  74. return;
  75. }
  76. cv.wait(lock, [] { return !local_endpoints_loading; });// continue if loading completed
  77. local_endpoints_loading = true;
  78. auto regions = value["regions"];
  79. for (const auto &region : regions)
  80. {
  81. allRegions.push_back(region.asString());
  82. }
  83. auto products = value["products"];
  84. for (const auto &product : products)
  85. {
  86. allProductsInLocalEndpoints.push_back(product.asString());
  87. }
  88. auto endpoints = value["endpoints"];
  89. for (auto &product : allProductsInLocalEndpoints)
  90. {
  91. auto endpoint_per_product = endpoints[product];
  92. productInfoType p;
  93. auto regions = endpoint_per_product["regions"];
  94. auto regional = endpoint_per_product["regional"];
  95. for (auto &r : regions)
  96. {
  97. const std::string region = r.asString();
  98. p.regions.push_back(region);
  99. p.regional[region] =
  100. endpoint_per_product["regional"][region].asString();
  101. }
  102. allLocalEndpoints[product] = p;
  103. }
  104. local_endpoints_loaded = true;
  105. local_endpoints_loading = false;
  106. lock.unlock();
  107. cv.notify_one();
  108. }
  109. } // namespace
  110. EndpointProvider::EndpointProvider(
  111. const std::shared_ptr<Location::LocationClient> &locationClient,
  112. const std::string regionId, const std::string product,
  113. const std::string serviceCode, int durationSeconds)
  114. : LocationClient(locationClient), regionId_(regionId), product_(product),
  115. serviceCode_(serviceCode), durationSeconds_(durationSeconds),
  116. cachedMutex_(), cachedEndpoint_(), expiry_()
  117. {
  118. transform(product_.begin(), product_.end(), product_.begin(), ::tolower);
  119. loadLocalProductsInfo();
  120. }
  121. EndpointProvider::EndpointProvider(const Credentials &credentials,
  122. const ClientConfiguration &configuration,
  123. const std::string &regionId,
  124. const std::string &product,
  125. const std::string &serviceCode,
  126. int durationSeconds)
  127. : LocationClient(credentials, configuration), regionId_(regionId),
  128. product_(product), serviceCode_(serviceCode),
  129. durationSeconds_(durationSeconds), cachedMutex_(), cachedEndpoint_(),
  130. expiry_()
  131. {
  132. transform(product_.begin(), product_.end(), product_.begin(), ::tolower);
  133. loadLocalProductsInfo();
  134. }
  135. EndpointProvider::~EndpointProvider() {}
  136. bool EndpointProvider::loadLocalProductsInfo()
  137. {
  138. LoadLocalEndpoints();
  139. return true;
  140. }
  141. std::string EndpointProvider::localEndpoint(const std::string regionId,
  142. const std::string product)
  143. {
  144. if (!local_endpoints_loaded)
  145. {
  146. // impossible
  147. return std::string();
  148. }
  149. std::vector<regionType>::iterator allRegionsit;
  150. allRegionsit = std::find(allRegions.begin(), allRegions.end(), regionId);
  151. if (allRegionsit == allRegions.end())
  152. {
  153. return std::string();
  154. }
  155. std::vector<productType>::iterator allProductsInLocalEndpointsit;
  156. allProductsInLocalEndpointsit =
  157. std::find(allProductsInLocalEndpoints.begin(),
  158. allProductsInLocalEndpoints.end(), product);
  159. if (allProductsInLocalEndpointsit == allProductsInLocalEndpoints.end())
  160. {
  161. return std::string();
  162. }
  163. std::vector<regionType> vec = allLocalEndpoints[product].regions;
  164. std::vector<regionType>::iterator it;
  165. it = std::find(vec.begin(), vec.end(), regionId);
  166. if (it == vec.end())
  167. {
  168. return std::string();
  169. }
  170. return allLocalEndpoints[product].regional[regionId];
  171. }
  172. bool EndpointProvider::checkExpiry() const
  173. {
  174. auto now = std::chrono::system_clock::now();
  175. auto diff =
  176. std::chrono::duration_cast<std::chrono::seconds>(now - expiry_).count();
  177. return (diff > 0 - 60);
  178. }
  179. EndpointProvider::EndpointOutcome EndpointProvider::getEndpoint()
  180. {
  181. // 1st priority: user specified via configuration
  182. if (!configuration().endpoint().empty())
  183. {
  184. return EndpointOutcome(configuration().endpoint());
  185. }
  186. // 2nd priority: local configuration
  187. std::string endpoint = localEndpoint(regionId_, product_);
  188. if (!endpoint.empty())
  189. {
  190. return EndpointOutcome(endpoint);
  191. }
  192. // service code is mandatory for location service.
  193. if (serviceCode_.empty())
  194. {
  195. return EndpointOutcome(
  196. Error("InvalidRegionId", "Product[" + product_ + "] at region[" +
  197. regionId_ + "] does not exist."));
  198. }
  199. // 3rd priority: request from location service
  200. EndpointOutcome outcome = loadRemoteEndpoint();
  201. if (outcome.isSuccess())
  202. {
  203. return outcome;
  204. }
  205. if (outcome.error().errorCode() == "Illegal Parameter")
  206. {
  207. return EndpointOutcome(Error("InvalidProduct", "Prodcut[" + serviceCode_ +
  208. "] does not exist."));
  209. }
  210. return outcome;
  211. }
  212. EndpointProvider::EndpointOutcome EndpointProvider::loadRemoteEndpoint()
  213. {
  214. if (checkExpiry())
  215. {
  216. std::lock_guard<std::mutex> locker(cachedMutex_);
  217. if (checkExpiry())
  218. {
  219. Location::Model::DescribeEndpointsRequest request;
  220. request.setId(regionId_);
  221. request.setServiceCode(serviceCode_);
  222. request.setType("openAPI");
  223. auto outcome = describeEndpoints(request);
  224. if (!outcome.isSuccess())
  225. return EndpointOutcome(outcome.error());
  226. auto all = outcome.result().endpoints();
  227. if (all.size() > 0)
  228. cachedEndpoint_ = all.front().endpoint;
  229. std::time_t t = std::time(nullptr) + durationSeconds_;
  230. expiry_ = std::chrono::system_clock::from_time_t(t);
  231. }
  232. }
  233. return EndpointOutcome(cachedEndpoint_);
  234. }
  235. } // namespace AlibabaCloud