UNPKG

6.56 kBPlain TextView Raw
1import { sdkVersion } from "./sdk_version"
2import { ClientProfile, Credential, ClientConfig } from "./interface"
3import Sign from "./sign"
4import { HttpConnection } from "./http/http_connection"
5import TencentCloudSDKHttpException from "./exception/tencent_cloud_sdk_exception"
6import { Response } from "node-fetch"
7
8type ResponseCallback = (error: string, rep: any) => void
9interface RequestOptions {
10 multipart: boolean
11}
12interface RequestData {
13 Action: string
14 RequestClient: string
15 Nonce: number
16 Timestamp: number
17 Version: string
18 Signature: string
19 SecretId?: string
20 region?: string
21 Token?: string
22 SinatureMethod?: string
23 [key: string]: any
24}
25type ResponseData = any
26
27/**
28 * @inner
29 */
30export class AbstractClient {
31 sdkVersion: string
32 path: string
33 credential: Credential
34 region: string
35 apiVersion: string
36 endpoint: string
37 profile: ClientProfile
38 /**
39 * 实例化client对象
40 * @param {string} endpoint 接入点域名
41 * @param {string} version 产品版本
42 * @param {Credential} credential 认证信息实例
43 * @param {string} region 产品地域
44 * @param {ClientProfile} profile 可选配置实例
45 */
46 constructor(endpoint: string, version: string, { credential, region, profile }: ClientConfig) {
47 this.path = "/"
48
49 /**
50 * 认证信息实例
51 */
52 this.credential = Object.assign(
53 {
54 secretId: null,
55 secretKey: null,
56 token: null,
57 },
58 credential
59 )
60
61 /**
62 * 产品地域
63 */
64 this.region = region || null
65 this.sdkVersion = "SDK_NODEJS_" + sdkVersion
66 this.apiVersion = version
67 this.endpoint = (profile && profile.httpProfile && profile.httpProfile.endpoint) || endpoint
68
69 /**
70 * 可选配置实例
71 * @type {ClientProfile}
72 */
73 this.profile = {
74 signMethod: (profile && profile.signMethod) || "TC3-HMAC-SHA256",
75 httpProfile: Object.assign(
76 {
77 reqMethod: "POST",
78 endpoint: null,
79 protocol: "https://",
80 reqTimeout: 60,
81 },
82 profile && profile.httpProfile
83 ),
84 }
85 }
86
87 /**
88 * @inner
89 */
90 async request(
91 action: string,
92 req: any,
93 options?: ResponseCallback | RequestOptions,
94 cb?: ResponseCallback
95 ): Promise<ResponseData> {
96 if (typeof options === "function") {
97 cb = options
98 options = {} as RequestOptions
99 }
100 try {
101 const result = await this.doRequest(action, req, options as RequestOptions)
102 cb && cb(null, result)
103 return result
104 } catch (e) {
105 cb && cb(e, null)
106 throw e
107 }
108 }
109
110 /**
111 * @inner
112 */
113 private async doRequest(
114 action: string,
115 req: any,
116 options?: RequestOptions
117 ): Promise<ResponseData> {
118 if (this.profile.signMethod === "TC3-HMAC-SHA256") {
119 return this.doRequestWithSign3(action, req, options)
120 }
121 let params = this.mergeData(req)
122 params = this.formatRequestData(action, params)
123 let res
124 try {
125 res = await HttpConnection.doRequest({
126 method: this.profile.httpProfile.reqMethod,
127 url: this.profile.httpProfile.protocol + this.endpoint + this.path,
128 data: params,
129 timeout: this.profile.httpProfile.reqTimeout * 1000,
130 })
131 } catch (error) {
132 throw new TencentCloudSDKHttpException(error.message)
133 }
134 return this.parseResponse(res)
135 }
136
137 /**
138 * @inner
139 */
140 private async doRequestWithSign3(
141 action: string,
142 params: any,
143 options?: RequestOptions
144 ): Promise<ResponseData> {
145 let res
146 try {
147 res = await HttpConnection.doRequestWithSign3({
148 method: this.profile.httpProfile.reqMethod,
149 url: this.profile.httpProfile.protocol + this.endpoint + this.path,
150 secretId: this.credential.secretId,
151 secretKey: this.credential.secretKey,
152 region: this.region,
153 data: params || "",
154 service: this.endpoint.split(".")[0],
155 action: action,
156 version: this.apiVersion,
157 multipart: options && options.multipart,
158 timeout: this.profile.httpProfile.reqTimeout * 1000,
159 token: this.credential.token,
160 requestClient: this.sdkVersion,
161 })
162 } catch (e) {
163 throw new TencentCloudSDKHttpException(e.message)
164 }
165 return this.parseResponse(res)
166 }
167
168 private async parseResponse(res: Response): Promise<ResponseData> {
169 if (res.status !== 200) {
170 const tcError = new TencentCloudSDKHttpException(res.statusText)
171 tcError.httpCode = res.status
172 throw tcError
173 } else {
174 const data = await res.json()
175 if (data.Response.Error) {
176 const tcError = new TencentCloudSDKHttpException(
177 data.Response.Error.Message,
178 data.Response.RequestId
179 )
180 tcError.code = data.Response.Error.Code
181 throw tcError
182 } else {
183 return data.Response
184 }
185 }
186 }
187
188 /**
189 * @inner
190 */
191 private mergeData(data: any, prefix = "") {
192 const ret: any = {}
193 for (const k in data) {
194 if (data[k] === null) {
195 continue
196 }
197 if (data[k] instanceof Array || data[k] instanceof Object) {
198 Object.assign(ret, this.mergeData(data[k], prefix + k + "."))
199 } else {
200 ret[prefix + k] = data[k]
201 }
202 }
203 return ret
204 }
205
206 /**
207 * @inner
208 */
209 private formatRequestData(action: string, params: RequestData): RequestData {
210 params.Action = action
211 params.RequestClient = this.sdkVersion
212 params.Nonce = Math.round(Math.random() * 65535)
213 params.Timestamp = Math.round(Date.now() / 1000)
214 params.Version = this.apiVersion
215
216 if (this.credential.secretId) {
217 params.SecretId = this.credential.secretId
218 }
219
220 if (this.region) {
221 params.Region = this.region
222 }
223
224 if (this.credential.token) {
225 params.Token = this.credential.token
226 }
227
228 if (this.profile.signMethod) {
229 params.SignatureMethod = this.profile.signMethod
230 }
231 const signStr = this.formatSignString(params)
232
233 params.Signature = Sign.sign(this.credential.secretKey, signStr, this.profile.signMethod)
234 return params
235 }
236
237 /**
238 * @inner
239 */
240 private formatSignString(params: RequestData): string {
241 let strParam = ""
242 const keys = Object.keys(params)
243 keys.sort()
244 for (const k in keys) {
245 //k = k.replace(/_/g, '.');
246 strParam += "&" + keys[k] + "=" + params[keys[k]]
247 }
248 const strSign =
249 this.profile.httpProfile.reqMethod.toLocaleUpperCase() +
250 this.endpoint +
251 this.path +
252 "?" +
253 strParam.slice(1)
254 return strSign
255 }
256}