tencentcloud-sdk-nodejs-intl-en 3.0.871 → 3.0.872

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,34 @@
1
+ syntax = "proto2";
2
+
3
+ package cls;
4
+
5
+ message Log
6
+ {
7
+ message Content
8
+ {
9
+ required string key = 1; // 每组字段的 key
10
+ required string value = 2; // 每组字段的 value
11
+ }
12
+ required int64 time = 1; // 时间戳,UNIX时间格式
13
+ repeated Content contents = 2; // 一条日志里的多个kv组合
14
+ }
15
+
16
+ message LogTag
17
+ {
18
+ required string key = 1;
19
+ required string value = 2;
20
+ }
21
+
22
+ message LogGroup
23
+ {
24
+ repeated Log logs = 1; // 多条日志合成的日志数组
25
+ optional string contextFlow = 2; // 目前暂无效用
26
+ optional string filename = 3; // 日志文件名
27
+ optional string source = 4; // 日志来源,一般使用机器IP
28
+ repeated LogTag logTags = 5;
29
+ }
30
+
31
+ message LogGroupList
32
+ {
33
+ repeated LogGroup logGroupList = 1; // 日志组列表
34
+ }
@@ -0,0 +1,68 @@
1
+ const tencentcloud = require("../../../../tencentcloud-sdk-nodejs-intl-en");
2
+ const protobuf = require("protobufjs")
3
+ const lz4 = require("lz4")
4
+ const path = require("path")
5
+
6
+ const Credential = tencentcloud.common.Credential;
7
+ const ClientProfile = tencentcloud.common.ClientProfile;
8
+ const HttpProfile = tencentcloud.common.HttpProfile;
9
+ const CommonClient = tencentcloud.common.CommonClient
10
+
11
+ let cred = new Credential(process.env.TENCENTCLOUD_SECRET_ID, process.env.TENCENTCLOUD_SECRET_KEY);
12
+
13
+ let httpProfile = new HttpProfile();
14
+ httpProfile.endpoint = "cls.tencentcloudapi.com";
15
+ httpProfile.headers["X-CLS-TopicId"] = "c241abf2-7acd-470d-845a-fb1da6916c99"; // 替换为自己业务的 topic
16
+ httpProfile.headers["X-CLS-HashKey"] = ""; // 可选参数
17
+ httpProfile.headers["X-CLS-CompressType"] = "lz4"; // lz4压缩方式, 空字符串意味不压缩
18
+
19
+ let clientProfile = new ClientProfile();
20
+ clientProfile.signMethod = "TC3-HMAC-SHA256";
21
+ clientProfile.httpProfile = httpProfile;
22
+
23
+ let client = new CommonClient('cls.tencentcloudapi.com', '2020-10-16', cred, "ap-guangzhou", clientProfile);
24
+
25
+ let params = compress(getBodyInfo())
26
+
27
+ client.requestOctetStream('UploadLog', params, function(err, response) {
28
+ if (err) {
29
+ console.log(err);
30
+ return;
31
+ }
32
+
33
+ console.log(response)
34
+ })
35
+
36
+
37
+ function compress(input) {
38
+ const output = Buffer.alloc(lz4.encodeBound(input.length))
39
+ const compressedBlockSize = lz4.encodeBlock(input, output)
40
+ return output.slice(0, compressedBlockSize)
41
+ }
42
+
43
+ function getBodyInfo() {
44
+ const root = protobuf.loadSync(path.join(__dirname, "cls.proto"))
45
+ const LogGroupList = root.lookupType("cls.LogGroupList")
46
+ const payload = {
47
+ logGroupList: [
48
+ {
49
+ logs: [
50
+ {
51
+ time: Date.now(),
52
+ contents: [
53
+ {
54
+ key: "name",
55
+ value: "张三",
56
+ },
57
+ {
58
+ key: "age",
59
+ value: "18",
60
+ },
61
+ ],
62
+ },
63
+ ],
64
+ },
65
+ ],
66
+ }
67
+ return LogGroupList.encode(payload).finish()
68
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tencentcloud-sdk-nodejs-intl-en",
3
- "version": "3.0.871",
3
+ "version": "3.0.872",
4
4
  "description": "腾讯云 API NODEJS SDK",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -4,6 +4,7 @@ const ClientProfile = require("./profile/client_profile");
4
4
  const Sign = require("./sign");
5
5
  const HttpConnection = require("./http/http_connection");
6
6
  const TencentCloudSDKHttpException = require("./exception/tencent_cloud_sdk_exception");
7
+ const SSEResponseModel = require("./sse_response_model");
7
8
 
8
9
  /**
9
10
  * @inner
@@ -80,6 +81,26 @@ class AbstractClient {
80
81
  }
81
82
  }
82
83
 
84
+ /**
85
+ * @inner
86
+ */
87
+ requestOctetStream(action, req, resp, options, cb) {
88
+ if (typeof options === 'function') {
89
+ cb = options
90
+ options = {}
91
+ }
92
+ options = Object.assign({}, options, {
93
+ headers: {
94
+ "Content-Type": "application/octet-stream; charset=utf-8",
95
+ }
96
+ })
97
+ if (this.profile.signMethod === 'TC3-HMAC-SHA256') {
98
+ this.doRequestWithSign3(action, req, options).then(data => this.succRequest(resp, cb, data), error => this.failRequest(error, cb));
99
+ } else {
100
+ this.doRequest(action, req).then(data => this.succRequest(resp, cb, data), error => this.failRequest(error, cb));
101
+ }
102
+ }
103
+
83
104
  /**
84
105
  * @inner
85
106
  */
@@ -92,7 +113,8 @@ class AbstractClient {
92
113
  method: this.profile.httpProfile.reqMethod,
93
114
  url: this.profile.httpProfile.protocol + this.getEndpoint() + this.path,
94
115
  data: params,
95
- timeout: this.profile.httpProfile.reqTimeout * 1000
116
+ timeout: this.profile.httpProfile.reqTimeout * 1000,
117
+ headers: Object.assign({}, this.profile.httpProfile.headers),
96
118
  });
97
119
  } catch (error) {
98
120
  throw new TencentCloudSDKHttpException(error.message);
@@ -119,7 +141,8 @@ class AbstractClient {
119
141
  multipart: options.multipart,
120
142
  timeout: this.profile.httpProfile.reqTimeout * 1000,
121
143
  token: this.credential.token,
122
- requestClient: this.sdkVersion
144
+ requestClient: this.sdkVersion,
145
+ headers: Object.assign({}, this.profile.httpProfile.headers, options.headers),
123
146
  })
124
147
  } catch (e) {
125
148
  throw new TencentCloudSDKHttpException(e.message)
@@ -133,13 +156,17 @@ class AbstractClient {
133
156
  tcError.httpCode = res.status
134
157
  throw tcError;
135
158
  } else {
136
- const data = await res.json();
137
- if (data.Response.Error) {
138
- const tcError = new TencentCloudSDKHttpException(data.Response.Error.Message, data.Response.RequestId)
139
- tcError.code = data.Response.Error.Code
140
- throw tcError;
159
+ if (res.headers.get("content-type") === "text/event-stream") {
160
+ return new SSEResponseModel(res.body)
141
161
  } else {
142
- return data.Response;
162
+ const data = await res.json();
163
+ if (data.Response.Error) {
164
+ const tcError = new TencentCloudSDKHttpException(data.Response.Error.Message, data.Response.RequestId)
165
+ tcError.code = data.Response.Error.Code
166
+ throw tcError;
167
+ } else {
168
+ return data.Response;
169
+ }
143
170
  }
144
171
  }
145
172
  }
@@ -0,0 +1,31 @@
1
+ const AbstractClient = require('./abstract_client')
2
+ const SSEResponseModel = require("./sse_response_model");
3
+
4
+ class CommonClient extends AbstractClient {
5
+ /**
6
+ * @inner
7
+ */
8
+ succRequest(resp, cb, data) {
9
+ if (data instanceof SSEResponseModel) {
10
+ cb(null, data);
11
+ return;
12
+ }
13
+ cb(null, JSON.stringify(data))
14
+ }
15
+
16
+ /**
17
+ * @inner
18
+ */
19
+ request(action, params, options, cb) {
20
+ super.request(action, params, null, options, cb);
21
+ }
22
+
23
+ /**
24
+ * @inner
25
+ */
26
+ requestOctetStream(action, params, options, cb) {
27
+ super.requestOctetStream(action, params, null, options, cb);
28
+ }
29
+ }
30
+
31
+ module.exports = CommonClient;
@@ -10,10 +10,10 @@ const fetch = require('./fetch');
10
10
  * @inner
11
11
  */
12
12
  class HttpConnection {
13
- static async doRequest({ method, url, data, timeout }) {
13
+ static async doRequest({ method, url, data, timeout, headers }) {
14
14
  let config = {
15
15
  method: method,
16
- headers: {},
16
+ headers,
17
17
  timeout
18
18
  };
19
19
  if (method === "GET") {
@@ -38,7 +38,8 @@ class HttpConnection {
38
38
  multipart = false,
39
39
  timeout = 60000,
40
40
  token,
41
- requestClient
41
+ requestClient,
42
+ headers = {}
42
43
  }) {
43
44
  // data 中可能带有 readStream,由于需要计算整个 body 的 hash,
44
45
  // 所以这里把 readStream 转为 Buffer
@@ -68,7 +69,8 @@ class HttpConnection {
68
69
  'X-TC-Timestamp': timestamp,
69
70
  'X-TC-Version': version,
70
71
  'X-TC-Token': token,
71
- 'X-TC-RequestClient': requestClient
72
+ 'X-TC-RequestClient': requestClient,
73
+ ...headers,
72
74
  }
73
75
  }
74
76
 
@@ -81,8 +83,10 @@ class HttpConnection {
81
83
  config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
82
84
  }
83
85
  if (method === 'POST' && !multipart) {
84
- config.body = JSON.stringify(data)
85
- config.headers['Content-Type'] = 'application/json'
86
+ config.body = data
87
+ const contentType = config.headers["Content-Type"] || "application/json"
88
+ if (!isBuffer(data)) config.body = JSON.stringify(data)
89
+ config.headers["Content-Type"] = contentType
86
90
  }
87
91
  if (method === 'POST' && multipart) {
88
92
  form = new FormData();
@@ -102,7 +106,8 @@ class HttpConnection {
102
106
  secretId,
103
107
  secretKey,
104
108
  multipart,
105
- boundary: form ? form.getBoundary() : undefined
109
+ boundary: form ? form.getBoundary() : undefined,
110
+ headers: config.headers,
106
111
  })
107
112
 
108
113
  config.headers['Authorization'] = signature
@@ -3,4 +3,6 @@ module.exports = {
3
3
  ClientProfile: require("./profile/client_profile"),
4
4
  HttpProfile: require("./profile/http_profile"),
5
5
  Credential: require("./credential"),
6
+ SSEResponseModel: require("./sse_response_model"),
7
+ CommonClient: require("./common_client"),
6
8
  };
@@ -2,6 +2,11 @@
2
2
  * HTTP settings.
3
3
  * @class
4
4
  */
5
+ /**
6
+ * @typedef {Object.<string, string>} StringRecord
7
+ * @property {string} key
8
+ * @property {string} value
9
+ */
5
10
  class HttpProfile {
6
11
 
7
12
  /**
@@ -9,8 +14,9 @@ class HttpProfile {
9
14
  * @param {string} endpoint Domain name, such as cvm.ap-shanghai.tencentcloud.com.
10
15
  * @param {string} reqMethod HTTP method, only supports GET and POST.
11
16
  * @param {number} reqTimeout Request timeout value, in seconds, default 60.
17
+ * @param {StringRecord} headers HTTP headers, default {}.
12
18
  */
13
- constructor(protocol, endpoint, reqMethod, reqTimeout) {
19
+ constructor(protocol, endpoint, reqMethod, reqTimeout, headers) {
14
20
  /**
15
21
  * @type {string}
16
22
  */
@@ -30,6 +36,11 @@ class HttpProfile {
30
36
  * @type {number}
31
37
  */
32
38
  this.reqTimeout = reqTimeout || 60;
39
+
40
+ /**
41
+ * @type {StringRecord}
42
+ */
43
+ this.headers = headers || {};
33
44
  }
34
45
  }
35
46
  module.exports = HttpProfile;
@@ -1,2 +1,2 @@
1
- const sdkVersion = "3.0.871";
1
+ const sdkVersion = "3.0.872";
2
2
  module.exports = sdkVersion
@@ -29,22 +29,24 @@ class Sign {
29
29
  secretId,
30
30
  secretKey,
31
31
  multipart,
32
- boundary
32
+ boundary,
33
+ headers: configHeaders = {},
33
34
  }) {
34
35
  const urlObj = new URL(url)
36
+ const contentType = configHeaders["Content-Type"]
35
37
 
36
38
  // 通用头部
37
39
  let headers = ''
38
40
  let signedHeaders = ''
39
41
  if (method === 'GET') {
40
42
  signedHeaders = 'content-type'
41
- headers = 'content-type:application/x-www-form-urlencoded\n'
43
+ headers = `content-type:${contentType}\n`
42
44
  } else if (method === 'POST') {
43
45
  signedHeaders = 'content-type'
44
46
  if (multipart) {
45
47
  headers = `content-type:multipart/form-data; boundary=${boundary}\n`
46
48
  } else {
47
- headers = 'content-type:application/json\n'
49
+ headers = `content-type:${contentType}\n`
48
50
  }
49
51
  }
50
52
  headers += `host:${urlObj.hostname}\n`
@@ -72,7 +74,8 @@ class Sign {
72
74
  hash.update(`--\r\n`)
73
75
  payload_hash = hash.digest('hex')
74
76
  } else {
75
- payload_hash = payload ? getHash(JSON.stringify(payload)) : getHash('')
77
+ const hashMessage = Buffer.isBuffer(payload) ? payload : JSON.stringify(payload)
78
+ payload_hash = payload ? getHash(hashMessage) : getHash('')
76
79
  }
77
80
 
78
81
  const canonicalRequest =
@@ -0,0 +1,154 @@
1
+ const { EventEmitter } = require('events')
2
+
3
+ /**
4
+ * @interface EventSourceMessage
5
+ * @description Represents a type EventSourceMessage.
6
+ * @property {string} id - The event ID to set the EventSource object's last event ID value.
7
+ * @property {string} event - A string identifying the type of event described.
8
+ * @property {string} data - The event data.
9
+ * @property {string} retry - The reconnection interval (in milliseconds) to wait before retrying the connection (optional).
10
+ */
11
+
12
+ class SSEEventEmitter extends EventEmitter {}
13
+
14
+ class SSEResponseModel {
15
+ /**
16
+ * Initialize the SSE response model.
17
+ * @param {NodeJS.ReadableStream} stream
18
+ */
19
+ constructor(stream) {
20
+ this.stream = stream
21
+ this.eventSource = new SSEEventEmitter()
22
+ this.init()
23
+ }
24
+
25
+ /**
26
+ * @inner
27
+ */
28
+ init() {
29
+ const { stream, eventSource } = this
30
+ stream.on("data", (chunk) => {
31
+ if (chunk !== null) {
32
+ const messages = chunk.toString().split("\n\n")
33
+ for (let i = 0; i < messages.length; i++) {
34
+ if (messages[i].length > 0) {
35
+ eventSource.emit("message", this.parseSSEMessage(messages[i]))
36
+ }
37
+ }
38
+ }
39
+ })
40
+ stream.on("close", () => {
41
+ eventSource.emit("close")
42
+ })
43
+ stream.on("error", (err) => {
44
+ eventSource.emit("error", err)
45
+ })
46
+ }
47
+
48
+ /**
49
+ * @inner
50
+ * @param {string} chunk
51
+ */
52
+ parseSSEMessage(chunk) {
53
+ /**
54
+ * @type {EventSourceMessage}
55
+ */
56
+ const message = {
57
+ data: "",
58
+ event: "",
59
+ id: "",
60
+ retry: undefined,
61
+ }
62
+
63
+ const lines = chunk.split("\n")
64
+ for (let i = 0; i < lines.length; i++) {
65
+ const line = lines[i]
66
+ // line is of format "<field>:<value>" or "<field>: <value>"
67
+ const colonIndex = line.indexOf(":")
68
+ if (colonIndex <= 0) continue // exclude comments and lines with no values
69
+ const field = line.slice(0, colonIndex)
70
+ const value = line.slice(colonIndex + (line[colonIndex + 1] === " " ? 2 : 1))
71
+
72
+ switch (field) {
73
+ case "data":
74
+ message.data = message.data ? message.data + "\n" + value : value
75
+ break
76
+ case "event":
77
+ message.event = value
78
+ break
79
+ case "id":
80
+ message.id = value
81
+ break
82
+ case "retry":
83
+ const retry = parseInt(value, 10)
84
+ if (!isNaN(retry)) {
85
+ // per spec, ignore non-integers
86
+ message.retry = retry
87
+ }
88
+ break
89
+ }
90
+ }
91
+
92
+ return message
93
+ }
94
+
95
+ /**
96
+ * add event listener.
97
+ * @param {"message"} event - The event type.
98
+ * @param {(message: EventSourceMessage) => void} listener - The event listener for "message" event.
99
+ * @returns {this}
100
+ * @param {"close"} event - The event type.
101
+ * @param {() => void} listener - The event listener for "close" event.
102
+ * @returns {this}
103
+ * @param {"error"} event - The event type.
104
+ * @param {(err: Error) => void} listener - The event listener for "error" event.
105
+ * @returns {this}
106
+ * @param {string} event - The event type.
107
+ * @param {any} listener - The event listener for other events.
108
+ * @returns {this}
109
+ */
110
+ on(event, listener) {
111
+ this.eventSource.on(event, listener)
112
+ return this
113
+ }
114
+
115
+ /**
116
+ * @param {"message"} event - The event type.
117
+ * @param {(message: EventSourceMessage) => void} listener - The event listener for "message" event.
118
+ * @returns {this}
119
+ * @param {"close"} event - The event type.
120
+ * @param {() => void} listener - The event listener for "close" event.
121
+ * @returns {this}
122
+ * @param {"error"} event - The event type.
123
+ * @param {(err: Error) => void} listener - The event listener for "error" event.
124
+ * @returns {this}
125
+ * @param {string} event - The event type.
126
+ * @param {any} listener - The event listener for other events.
127
+ * @returns {this}
128
+ */
129
+ removeListener(event, listener) {
130
+ this.eventSource.removeListener(event, listener)
131
+ return this
132
+ }
133
+
134
+ /**
135
+ * @function
136
+ * @name Symbol.asyncIterator
137
+ * @description Async iterator function for Symbol.asyncIterator.
138
+ * @returns {AsyncIterableIterator<EventSourceMessage>}
139
+ */
140
+ async *[Symbol.asyncIterator]() {
141
+ for await (const chunk of this.stream) {
142
+ if (chunk !== null) {
143
+ const messages = chunk.toString().split("\n\n")
144
+ for (let i = 0; i < messages.length; i++) {
145
+ if (messages[i].length > 0) {
146
+ yield this.parseSSEMessage(messages[i])
147
+ }
148
+ }
149
+ }
150
+ }
151
+ }
152
+ }
153
+
154
+ module.exports = SSEResponseModel;