tencentcloud-sdk-nodejs-common
Version:
240 lines (239 loc) • 8.83 kB
JavaScript
import { sdkVersion } from "./sdk_version";
import { SUPPORT_LANGUAGE_LIST, } from "./interface";
import Sign from "./sign";
import { HttpConnection } from "./http/http_connection";
import TencentCloudSDKHttpException from "./exception/tencent_cloud_sdk_exception";
import { SSEResponseModel } from "./sse_response_model";
import { v4 as uuidv4 } from "uuid";
export class AbstractClient {
constructor(endpoint, version, { credential, region, profile = {} }) {
this.path = "/";
if (credential && "getCredential" in credential) {
this.credential = credential;
}
else {
this.credential = Object.assign({
secretId: null,
secretKey: null,
token: null,
}, credential);
}
this.region = region || null;
this.sdkVersion = "SDK_NODEJS_" + sdkVersion;
this.apiVersion = version;
this.endpoint = (profile && profile.httpProfile && profile.httpProfile.endpoint) || endpoint;
this.profile = {
signMethod: (profile && profile.signMethod) || "TC3-HMAC-SHA256",
httpProfile: Object.assign({
reqMethod: "POST",
endpoint: null,
protocol: "https://",
reqTimeout: 60,
}, profile && profile.httpProfile),
language: profile.language,
};
if (this.profile.language && !SUPPORT_LANGUAGE_LIST.includes(this.profile.language)) {
throw new TencentCloudSDKHttpException(`Language invalid, choices: ${SUPPORT_LANGUAGE_LIST.join("|")}`);
}
}
async getCredential() {
if ("getCredential" in this.credential) {
return await this.credential.getCredential();
}
return this.credential;
}
async request(action, req, options, cb) {
if (typeof options === "function") {
cb = options;
options = {};
}
try {
const result = await this.doRequest(action, req !== null && req !== void 0 ? req : {}, options);
cb && cb(null, result);
return result;
}
catch (e) {
cb && cb(e, null);
throw e;
}
}
async requestOctetStream(action, req, options, cb) {
if (typeof options === "function") {
cb = options;
options = {};
}
try {
const result = await this.doRequest(action, req !== null && req !== void 0 ? req : {}, Object.assign({}, options, {
headers: {
"Content-Type": "application/octet-stream; charset=utf-8",
},
}));
cb && cb(null, result);
return result;
}
catch (e) {
cb && cb(e, null);
throw e;
}
}
async doRequest(action, req, options = {}) {
if (this.profile.signMethod === "TC3-HMAC-SHA256") {
return this.doRequestWithSign3(action, req, options);
}
let params = this.mergeData(req);
params = await this.formatRequestData(action, params);
const headers = Object.assign({}, this.profile.httpProfile.headers, options.headers);
let traceId = "";
for (let key in headers) {
if (key.toLowerCase() === "x-tc-traceid") {
traceId = headers[key];
break;
}
}
if (!traceId) {
traceId = uuidv4();
headers["X-TC-TraceId"] = traceId;
}
let res;
try {
res = await HttpConnection.doRequest({
method: this.profile.httpProfile.reqMethod,
url: this.profile.httpProfile.protocol + this.endpoint + this.path,
data: params,
timeout: this.profile.httpProfile.reqTimeout * 1000,
headers,
agent: this.profile.httpProfile.agent,
proxy: this.profile.httpProfile.proxy,
signal: options.signal,
});
}
catch (error) {
throw new TencentCloudSDKHttpException(error.message, "", traceId);
}
return this.parseResponse(res);
}
async doRequestWithSign3(action, params, options = {}) {
const headers = Object.assign({}, this.profile.httpProfile.headers, options.headers);
let traceId = "";
for (let key in headers) {
if (key.toLowerCase() === "x-tc-traceid") {
traceId = headers[key];
break;
}
}
if (!traceId) {
traceId = uuidv4();
headers["X-TC-TraceId"] = traceId;
}
let res;
try {
const credential = await this.getCredential();
res = await HttpConnection.doRequestWithSign3({
method: this.profile.httpProfile.reqMethod,
url: this.profile.httpProfile.protocol + this.endpoint + this.path,
secretId: credential.secretId,
secretKey: credential.secretKey,
region: this.region,
data: params || "",
service: this.endpoint.split(".")[0],
action: action,
version: this.apiVersion,
multipart: options && options.multipart,
timeout: this.profile.httpProfile.reqTimeout * 1000,
token: credential.token,
requestClient: this.sdkVersion,
language: this.profile.language,
headers,
agent: this.profile.httpProfile.agent,
proxy: this.profile.httpProfile.proxy,
signal: options.signal,
});
}
catch (e) {
throw new TencentCloudSDKHttpException(e.message, "", traceId);
}
return this.parseResponse(res);
}
async parseResponse(res) {
const traceId = res.headers.get("x-tc-traceid");
if (res.status !== 200) {
const tcError = new TencentCloudSDKHttpException(res.statusText, "", traceId);
tcError.httpCode = res.status;
throw tcError;
}
else {
if (res.headers.get("content-type") === "text/event-stream") {
return new SSEResponseModel(res.body);
}
else {
const data = await res.json();
if (data.Response.Error) {
const tcError = new TencentCloudSDKHttpException(data.Response.Error.Message, data.Response.RequestId, traceId);
tcError.code = data.Response.Error.Code;
throw tcError;
}
else {
return data.Response;
}
}
}
}
mergeData(data, prefix = "") {
const ret = {};
for (const k in data) {
if (data[k] === null || data[k] === undefined) {
continue;
}
if (data[k] instanceof Array || data[k] instanceof Object) {
Object.assign(ret, this.mergeData(data[k], prefix + k + "."));
}
else {
ret[prefix + k] = data[k];
}
}
return ret;
}
async formatRequestData(action, params) {
params.Action = action;
params.RequestClient = this.sdkVersion;
params.Nonce = Math.round(Math.random() * 65535);
params.Timestamp = Math.round(Date.now() / 1000);
params.Version = this.apiVersion;
const credential = await this.getCredential();
if (credential.secretId) {
params.SecretId = credential.secretId;
}
if (this.region) {
params.Region = this.region;
}
if (credential.token) {
params.Token = credential.token;
}
if (this.profile.language) {
params.Language = this.profile.language;
}
if (this.profile.signMethod) {
params.SignatureMethod = this.profile.signMethod;
}
const signStr = this.formatSignString(params);
params.Signature = Sign.sign(credential.secretKey, signStr, this.profile.signMethod);
return params;
}
formatSignString(params) {
let strParam = "";
const keys = Object.keys(params);
keys.sort();
for (const k in keys) {
if (!keys.hasOwnProperty(k)) {
continue;
}
strParam += "&" + keys[k] + "=" + params[keys[k]];
}
const strSign = this.profile.httpProfile.reqMethod.toLocaleUpperCase() +
this.endpoint +
this.path +
"?" +
strParam.slice(1);
return strSign;
}
}