Files
aliyun-openapi-cpp-sdk/core/src/EndpointProvider.cc
2019-03-12 12:18:57 +08:00

240 lines
6.7 KiB
C++

/*
* 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 <alibabacloud/core/EndpointProvider.h>
#include <json/json.h>
#include <iomanip>
#include <sstream>
#include <algorithm>
#ifndef WIN32
#include "LocalEndpoints.h"
#else
#include "LocalEndpointsForWindows.h"
#endif
namespace AlibabaCloud {
namespace {
#if defined(WIN32) && defined(_MSC_VER)
# define strcasecmp _stricmp
# define strncasecmp _strnicmp
#else
# include <strings.h>
#endif
bool local_endpoints_loaded = false;
typedef std::string productType;
typedef std::string regionType;
typedef std::string endpointType;
typedef std::string mappingType;
typedef std::vector<regionType> regionsType;
typedef std::map<productType, endpointType> regionalType;
typedef struct {
regionsType regions;
regionalType regional;
} productInfoType;
static std::vector<regionType> allRegions;
static std::vector<productType> allProductsInLocalEndpoints;
static std::map<productType, productInfoType> allLocalEndpoints;
static void LoadLocalEndpoints() {
Json::Reader reader;
Json::Value value;
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;
}
auto regions = value["regions"];
for (const auto &region : 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;
}
} // namespace
EndpointProvider::EndpointProvider(
const std::shared_ptr<Location::LocationClient>& 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 &regionId,
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<regionType>::iterator allRegionsit;
allRegionsit = std::find(allRegions.begin(), allRegions.end(), regionId);
if (allRegionsit == allRegions.end()) {
return std::string();
}
std::vector<productType>::iterator allProductsInLocalEndpointsit;
allProductsInLocalEndpointsit = std::find(allProductsInLocalEndpoints.begin(), allProductsInLocalEndpoints.end(), product);
if (allProductsInLocalEndpointsit == allProductsInLocalEndpoints.end()) {
return std::string();
}
std::vector<regionType> vec = allLocalEndpoints[product].regions;
std::vector<regionType>::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<std::chrono::seconds>(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<std::mutex> 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