/* * Copyright 1999-2019 Alibaba Cloud All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #ifndef WIN32 #include "LocalEndpoints.h" #include #else #include "LocalEndpointsForWindows.h" #endif namespace AlibabaCloud { namespace { #if defined(WIN32) && defined(_MSC_VER) #define strcasecmp _stricmp #define strncasecmp _strnicmp #else #include #endif std::mutex mutex; std::condition_variable cv; bool local_endpoints_loaded = false; bool local_endpoints_loading = false; typedef std::string productType; typedef std::string regionType; typedef std::string endpointType; typedef std::string mappingType; typedef std::vector regionsType; typedef std::map regionalType; typedef struct { regionsType regions; regionalType regional; } productInfoType; static std::vector allRegions; static std::vector allProductsInLocalEndpoints; static std::map allLocalEndpoints; static void LoadLocalEndpoints() { Json::Reader reader; Json::Value value; std::unique_lock lock(mutex); if (local_endpoints_loaded) { return; } #ifdef WIN32 std::string LOCAL_ENDPOINTS_CONFIG = WIN_LOCAL_ENDPOINTS_CONFIG_1 + WIN_LOCAL_ENDPOINTS_CONFIG_2 + WIN_LOCAL_ENDPOINTS_CONFIG_3; #endif if (!reader.parse(LOCAL_ENDPOINTS_CONFIG, value)) { return; } cv.wait(lock, [] { return !local_endpoints_loading; }); // continue if loading completed local_endpoints_loading = true; auto regions = value["regions"]; for (const auto ®ion : regions) { allRegions.push_back(region.asString()); } auto products = value["products"]; for (const auto &product : products) { allProductsInLocalEndpoints.push_back(product.asString()); } auto endpoints = value["endpoints"]; for (auto &product : allProductsInLocalEndpoints) { auto endpoint_per_product = endpoints[product]; productInfoType p; auto regions = endpoint_per_product["regions"]; auto regional = endpoint_per_product["regional"]; for (auto &r : regions) { const std::string region = r.asString(); p.regions.push_back(region); p.regional[region] = endpoint_per_product["regional"][region].asString(); } allLocalEndpoints[product] = p; } local_endpoints_loaded = true; local_endpoints_loading = false; lock.unlock(); cv.notify_one(); } } // namespace EndpointProvider::EndpointProvider( const std::shared_ptr &locationClient, const std::string regionId, const std::string product, const std::string serviceCode, int durationSeconds) : LocationClient(locationClient), regionId_(regionId), product_(product), serviceCode_(serviceCode), durationSeconds_(durationSeconds), cachedMutex_(), cachedEndpoint_(), expiry_() { transform(product_.begin(), product_.end(), product_.begin(), ::tolower); loadLocalProductsInfo(); } EndpointProvider::EndpointProvider(const Credentials &credentials, const ClientConfiguration &configuration, const std::string ®ionId, const std::string &product, const std::string &serviceCode, int durationSeconds) : LocationClient(credentials, configuration), regionId_(regionId), product_(product), serviceCode_(serviceCode), durationSeconds_(durationSeconds), cachedMutex_(), cachedEndpoint_(), expiry_() { transform(product_.begin(), product_.end(), product_.begin(), ::tolower); loadLocalProductsInfo(); } EndpointProvider::~EndpointProvider() {} bool EndpointProvider::loadLocalProductsInfo() { LoadLocalEndpoints(); return true; } std::string EndpointProvider::localEndpoint(const std::string regionId, const std::string product) { if (!local_endpoints_loaded) { // impossible return std::string(); } std::vector::iterator allRegionsit; allRegionsit = std::find(allRegions.begin(), allRegions.end(), regionId); if (allRegionsit == allRegions.end()) { return std::string(); } std::vector::iterator allProductsInLocalEndpointsit; allProductsInLocalEndpointsit = std::find(allProductsInLocalEndpoints.begin(), allProductsInLocalEndpoints.end(), product); if (allProductsInLocalEndpointsit == allProductsInLocalEndpoints.end()) { return std::string(); } std::vector vec = allLocalEndpoints[product].regions; std::vector::iterator it; it = std::find(vec.begin(), vec.end(), regionId); if (it == vec.end()) { return std::string(); } return allLocalEndpoints[product].regional[regionId]; } bool EndpointProvider::checkExpiry() const { auto now = std::chrono::system_clock::now(); auto diff = std::chrono::duration_cast(now - expiry_).count(); return (diff > 0 - 60); } EndpointProvider::EndpointOutcome EndpointProvider::getEndpoint() { // 1st priority: user specified via configuration if (!configuration().endpoint().empty()) { return EndpointOutcome(configuration().endpoint()); } // 2nd priority: local configuration std::string endpoint = localEndpoint(regionId_, product_); if (!endpoint.empty()) { return EndpointOutcome(endpoint); } // service code is mandatory for location service. if (serviceCode_.empty()) { return EndpointOutcome( Error("InvalidRegionId", "Product[" + product_ + "] at region[" + regionId_ + "] does not exist.")); } // 3rd priority: request from location service EndpointOutcome outcome = loadRemoteEndpoint(); if (outcome.isSuccess()) { return outcome; } if (outcome.error().errorCode() == "Illegal Parameter") { return EndpointOutcome(Error("InvalidProduct", "Prodcut[" + serviceCode_ + "] does not exist.")); } return outcome; } EndpointProvider::EndpointOutcome EndpointProvider::loadRemoteEndpoint() { if (checkExpiry()) { std::lock_guard locker(cachedMutex_); if (checkExpiry()) { Location::Model::DescribeEndpointsRequest request; request.setId(regionId_); request.setServiceCode(serviceCode_); request.setType("openAPI"); auto outcome = describeEndpoints(request); if (!outcome.isSuccess()) return EndpointOutcome(outcome.error()); auto all = outcome.result().endpoints(); if (all.size() > 0) cachedEndpoint_ = all.front().endpoint; std::time_t t = std::time(nullptr) + durationSeconds_; expiry_ = std::chrono::system_clock::from_time_t(t); } } return EndpointOutcome(cachedEndpoint_); } } // namespace AlibabaCloud