cvitool 1.0.6

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.
package/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # cvitool
2
+
3
+ just.
4
+
5
+ ## 安装
6
+
7
+ ```js
8
+ npm i cvitool
9
+ ```
@@ -0,0 +1,9 @@
1
+ interface randomStringOptions {
2
+ special?: boolean;
3
+ lowercase?: boolean;
4
+ upperCase?: boolean;
5
+ number?: boolean;
6
+ specials?: string;
7
+ }
8
+ declare function randomString(length: number, options?: randomStringOptions): string;
9
+ export { randomStringOptions, randomString };
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.randomString = void 0;
4
+ const crypto_1 = require("crypto");
5
+ function randomString(length, options) {
6
+ let { special = false, lowercase = true, upperCase = true, number = true, specials } = options || {};
7
+ if (specials) {
8
+ special = true;
9
+ }
10
+ if (!special && !lowercase && !upperCase && !number) {
11
+ throw new Error('randomString|must choose one of (special|lowercase|upperCase|number)');
12
+ }
13
+ const numbers = '0123456789';
14
+ const lowercaseLetters = 'abcdefghijklmnopqrstuvwxyz';
15
+ const upperCaseLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
16
+ specials = specials || '~!@#$%^*()_+-=[]{}|;:,./<>?';
17
+ let targetStr = '';
18
+ if (special) {
19
+ targetStr += specials;
20
+ }
21
+ if (lowercase) {
22
+ targetStr += lowercaseLetters;
23
+ }
24
+ if (upperCase) {
25
+ targetStr += upperCaseLetters;
26
+ }
27
+ if (number) {
28
+ targetStr += numbers;
29
+ }
30
+ let result = '';
31
+ while (length > 0) {
32
+ result += targetStr.charAt((0, crypto_1.randomInt)(targetStr.length));
33
+ length--;
34
+ }
35
+ return result;
36
+ }
37
+ exports.randomString = randomString;
@@ -0,0 +1,48 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node" />
4
+ /// <reference types="node" />
5
+ import * as https from 'https';
6
+ import * as http from 'http';
7
+ import { ReadStream } from 'fs';
8
+ type Method = 'get' | 'put' | 'post' | 'delete' | 'patch' | 'head';
9
+ type ResType = 'json' | 'buffer' | 'stream' | 'text';
10
+ interface CustomObject {
11
+ [key: string]: any;
12
+ }
13
+ interface baseReqOptions {
14
+ timeout?: number;
15
+ method?: Method;
16
+ agent?: http.Agent | https.Agent;
17
+ headers?: {
18
+ [key: string]: string;
19
+ };
20
+ resType?: ResType;
21
+ }
22
+ interface reqOptions extends baseReqOptions {
23
+ query?: {
24
+ [key: string]: string;
25
+ };
26
+ body?: {
27
+ [key: string]: any;
28
+ };
29
+ }
30
+ interface reqSendBufferOptions extends baseReqOptions {
31
+ buffer: Buffer;
32
+ }
33
+ interface reqSendStreamOptions extends baseReqOptions {
34
+ stream: ReadStream;
35
+ }
36
+ interface reqSendMultiPartOptions extends baseReqOptions {
37
+ form: any;
38
+ }
39
+ interface ResData {
40
+ reqUrl: string;
41
+ resHeaders: CustomObject;
42
+ resBody: http.IncomingMessage | CustomObject | string | Buffer | null;
43
+ }
44
+ declare function request(url: string, options?: reqOptions): Promise<ResData>;
45
+ declare function reqSendBuffer(url: string, options: reqSendBufferOptions): Promise<ResData>;
46
+ declare function reqSendStream(url: string, options: reqSendStreamOptions): Promise<ResData>;
47
+ declare function reqSendMultiPart(url: string, options: reqSendMultiPartOptions): Promise<ResData>;
48
+ export { reqOptions, reqSendBufferOptions, reqSendStreamOptions, reqSendMultiPartOptions, ResData, request, reqSendBuffer, reqSendStream, reqSendMultiPart, };
@@ -0,0 +1,265 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.reqSendMultiPart = exports.reqSendStream = exports.reqSendBuffer = exports.request = void 0;
13
+ const querystring = require("querystring");
14
+ const https = require("https");
15
+ const http = require("http");
16
+ function getTimeOutMessage(timeout) {
17
+ return `request timeout of ${timeout} ms`;
18
+ }
19
+ function getProtocol(url) {
20
+ return url.startsWith('https') ? https : http;
21
+ }
22
+ function request(url, options) {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ const { query = {}, body = {}, headers = {}, timeout = 5000, method = 'get', agent, resType = 'json' } = options || {};
25
+ if (Object.keys(query).length !== 0) {
26
+ if (url.indexOf('?') > -1) {
27
+ url = url + '&' + querystring.stringify(query);
28
+ }
29
+ else {
30
+ url = url + '?' + querystring.stringify(query);
31
+ }
32
+ }
33
+ const data = JSON.stringify(body);
34
+ const protocol = getProtocol(url);
35
+ const isbodyEmpty = Object.keys(body).length === 0;
36
+ const baseHeaders = {
37
+ 'Content-Type': 'application/json;charset=utf-8',
38
+ 'Content-length': isbodyEmpty ? 0 : Buffer.byteLength(data)
39
+ };
40
+ return new Promise((resolve, reject) => {
41
+ const req = protocol.request(url, {
42
+ timeout,
43
+ headers: Object.assign(headers, baseHeaders),
44
+ method,
45
+ agent
46
+ }, res => {
47
+ resHandld(res, resolve, reject, resType, method);
48
+ });
49
+ req.on('timeout', () => {
50
+ req.destroy();
51
+ reject(new Error(getTimeOutMessage(timeout)));
52
+ });
53
+ req.on('error', e => {
54
+ req.destroy();
55
+ reject(e);
56
+ });
57
+ if (isbodyEmpty) {
58
+ req.end();
59
+ }
60
+ else {
61
+ req.write(data, (e) => {
62
+ req.end();
63
+ if (e) {
64
+ req.destroy();
65
+ reject(e);
66
+ }
67
+ });
68
+ }
69
+ });
70
+ });
71
+ }
72
+ exports.request = request;
73
+ function reqSendBuffer(url, options) {
74
+ return __awaiter(this, void 0, void 0, function* () {
75
+ const { timeout = 60000, headers = {}, buffer, method = 'post', agent, resType = 'json' } = options;
76
+ const protocol = getProtocol(url);
77
+ return new Promise((resolve, reject) => {
78
+ const req = protocol.request(url, {
79
+ timeout,
80
+ headers: Object.assign(headers, { 'Content-Length': buffer.byteLength }),
81
+ method,
82
+ agent
83
+ }, res => {
84
+ resHandld(res, resolve, reject, resType, method);
85
+ });
86
+ req.on('timeout', () => {
87
+ req.destroy();
88
+ reject(new Error(getTimeOutMessage(timeout)));
89
+ });
90
+ req.on('error', e => {
91
+ req.destroy();
92
+ reject(e);
93
+ });
94
+ req.write(buffer, (e) => {
95
+ req.end();
96
+ if (e) {
97
+ req.destroy();
98
+ reject(e);
99
+ }
100
+ });
101
+ });
102
+ });
103
+ }
104
+ exports.reqSendBuffer = reqSendBuffer;
105
+ function reqSendStream(url, options) {
106
+ return __awaiter(this, void 0, void 0, function* () {
107
+ const { timeout = 60000, method = 'post', stream, headers = {}, agent, resType = 'json' } = options;
108
+ const protocol = getProtocol(url);
109
+ return new Promise((resolve, reject) => {
110
+ const baseHeaders = {
111
+ 'Content-Type': 'application/octet-stream',
112
+ 'Transfer-Encoding': 'chunked',
113
+ Connection: 'keep-alive'
114
+ };
115
+ const req = protocol.request(url, {
116
+ timeout,
117
+ headers: Object.assign(headers, baseHeaders),
118
+ method,
119
+ agent
120
+ }, res => {
121
+ resHandld(res, resolve, reject, resType, method);
122
+ });
123
+ req.on('timeout', () => {
124
+ req.destroy();
125
+ reject(new Error(getTimeOutMessage(timeout)));
126
+ });
127
+ req.on('error', e => {
128
+ req.destroy();
129
+ reject(e);
130
+ });
131
+ stream.on('data', chunk => {
132
+ req.write(chunk, e => {
133
+ if (e) {
134
+ req.destroy();
135
+ reject(e);
136
+ }
137
+ });
138
+ });
139
+ stream.on('end', () => {
140
+ req.end();
141
+ stream.close();
142
+ });
143
+ stream.on('error', e => {
144
+ req.destroy();
145
+ stream.close();
146
+ reject(e);
147
+ });
148
+ });
149
+ });
150
+ }
151
+ exports.reqSendStream = reqSendStream;
152
+ function reqSendMultiPart(url, options) {
153
+ return __awaiter(this, void 0, void 0, function* () {
154
+ const { timeout = 60000, headers = {}, form, agent, resType = 'json' } = options;
155
+ const protocol = getProtocol(url);
156
+ return new Promise((resolve, reject) => {
157
+ const req = protocol.request(url, {
158
+ timeout,
159
+ headers: Object.assign(headers, Object.assign({}, form.getHeaders())),
160
+ method: 'post',
161
+ agent
162
+ }, res => {
163
+ resHandld(res, resolve, reject, resType, 'post');
164
+ });
165
+ req.on('timeout', () => {
166
+ req.destroy();
167
+ reject(new Error(getTimeOutMessage(timeout)));
168
+ });
169
+ req.on('error', e => {
170
+ req.destroy();
171
+ reject(e);
172
+ });
173
+ form.pipe(req);
174
+ form.on('end', () => {
175
+ req.end();
176
+ });
177
+ form.on('error', e => {
178
+ req.destroy();
179
+ form.destroy();
180
+ reject(e);
181
+ });
182
+ });
183
+ });
184
+ }
185
+ exports.reqSendMultiPart = reqSendMultiPart;
186
+ function resHandld(res, resolve, reject, resType, method) {
187
+ const reqUrl = `${res.req.protocol}//${res.req.host}${res.req.path}`;
188
+ const resHeaders = {};
189
+ for (let i = 0; i < res.rawHeaders.length; i += 2) {
190
+ resHeaders[res.rawHeaders[i]] = res.rawHeaders[i + 1];
191
+ if (i === res.rawHeaders.length - 2) {
192
+ break;
193
+ }
194
+ }
195
+ if (res.statusCode !== 200) {
196
+ errHandle(reject, res, reqUrl, resHeaders);
197
+ return;
198
+ }
199
+ const resData = {
200
+ reqUrl,
201
+ resHeaders,
202
+ resBody: null
203
+ };
204
+ if (method === 'head') {
205
+ resolve(resData);
206
+ return;
207
+ }
208
+ if (resType === 'stream') {
209
+ resData.resBody = res;
210
+ resolve(resData);
211
+ return;
212
+ }
213
+ let resBody;
214
+ const chunks = [];
215
+ res.on('data', chunk => {
216
+ chunks.push(chunk);
217
+ });
218
+ res.on('end', () => {
219
+ const buffer = Buffer.concat(chunks);
220
+ if (resType === 'buffer') {
221
+ resBody = buffer;
222
+ }
223
+ else {
224
+ const responseStr = buffer.toString();
225
+ if (resType === 'text') {
226
+ resBody = responseStr;
227
+ }
228
+ else {
229
+ try {
230
+ resBody = JSON.parse(responseStr);
231
+ }
232
+ catch (e) {
233
+ resBody = resData;
234
+ }
235
+ }
236
+ }
237
+ resData.resBody = resBody;
238
+ resolve(resData);
239
+ });
240
+ }
241
+ function errHandle(reject, res, reqUrl, resHeaders) {
242
+ const chunks = [];
243
+ res.on('data', chunk => {
244
+ chunks.push(chunk);
245
+ });
246
+ res.on('end', () => {
247
+ const buffer = Buffer.concat(chunks);
248
+ const resData = buffer.toString();
249
+ let resBody;
250
+ try {
251
+ resBody = JSON.parse(resData);
252
+ }
253
+ catch (e) {
254
+ resBody = resData;
255
+ }
256
+ const err = new Error();
257
+ err.code = res.statusCode;
258
+ err.name = 'statusCodeError';
259
+ err.message = `${res.statusCode}|${res.statusMessage}`;
260
+ err.resBody = resBody;
261
+ err.reqUrl = reqUrl;
262
+ err.resHeaders = resHeaders;
263
+ reject(err);
264
+ });
265
+ }
@@ -0,0 +1,9 @@
1
+ /// <reference types="node" />
2
+ import { ReadStream, WriteStream } from 'fs';
3
+ interface pipeOptions {
4
+ timeout?: number;
5
+ readBytesPreSec?: number;
6
+ }
7
+ declare function pipe(source: ReadStream, target: WriteStream, options?: pipeOptions): Promise<void>;
8
+ declare function limitStreamFlowingRate(stream: ReadStream, readBytesPreSec: number): void;
9
+ export { pipeOptions, pipe, limitStreamFlowingRate };
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.limitStreamFlowingRate = exports.pipe = void 0;
13
+ function pipe(source, target, options) {
14
+ return __awaiter(this, void 0, void 0, function* () {
15
+ const { timeout, readBytesPreSec } = options || {};
16
+ return new Promise((resolve, reject) => {
17
+ if (readBytesPreSec) {
18
+ limitStreamFlowingRate(source, readBytesPreSec);
19
+ }
20
+ source.pipe(target);
21
+ target.on('finish', () => {
22
+ resolve();
23
+ });
24
+ source.on('error', e => {
25
+ reject(e);
26
+ });
27
+ if (timeout) {
28
+ setTimeout(() => {
29
+ if (!target.closed) {
30
+ target.destroy();
31
+ source.destroy();
32
+ const downloadErr = new Error(`文件下载超时|${(timeout / 1000).toFixed(3)}s`);
33
+ reject(downloadErr);
34
+ }
35
+ }, timeout);
36
+ }
37
+ });
38
+ });
39
+ }
40
+ exports.pipe = pipe;
41
+ function limitStreamFlowingRate(stream, readBytesPreSec) {
42
+ let start = 0;
43
+ let calReadBytesTotal = 0;
44
+ stream.on('data', (chunk) => {
45
+ if (!start) {
46
+ start = Date.now();
47
+ }
48
+ calReadBytesTotal += chunk.length;
49
+ const fromStartSecs = Math.ceil((Date.now() - start) / 1000);
50
+ if (calReadBytesTotal > fromStartSecs * readBytesPreSec && fromStartSecs > 0) {
51
+ const stopTime = Math.ceil((fromStartSecs - ((Date.now() - start) / 1000)) * 1000);
52
+ if (stopTime > 0) {
53
+ stream.pause();
54
+ setTimeout(() => {
55
+ stream.resume();
56
+ }, stopTime);
57
+ }
58
+ }
59
+ });
60
+ }
61
+ exports.limitStreamFlowingRate = limitStreamFlowingRate;
package/index.d.ts ADDED
@@ -0,0 +1,78 @@
1
+ import { ReadStream, WriteStream } from 'fs';
2
+
3
+ import {
4
+ reqOptions,
5
+ reqSendBufferOptions,
6
+ reqSendStreamOptions,
7
+ reqSendMultiPartOptions,
8
+ ResData
9
+ } from './src/hgo';
10
+
11
+ import {
12
+ pipeOptions,
13
+ } from './src/streamhelper';
14
+
15
+ import {
16
+ randomStringOptions
17
+ } from './src/cutil';
18
+
19
+ interface Hgo {
20
+ /**
21
+ * 发出普通请求
22
+ * @param url
23
+ * @param options
24
+ */
25
+ request(url: string, options?: reqOptions): Promise<ResData>,
26
+ /**
27
+ * 发出传送buffer请求
28
+ * @param url
29
+ * @param options
30
+ */
31
+ reqSendBuffer(url: string, options: reqSendBufferOptions): Promise<ResData>,
32
+ /**
33
+ * 发出传送stream请求
34
+ * @param url
35
+ * @param options
36
+ */
37
+ reqSendStream(url: string, options: reqSendStreamOptions): Promise<ResData>,
38
+ /**
39
+ * 发出传送表单formData请求
40
+ * @param url
41
+ * @param options
42
+ */
43
+ reqSendMultiPart(url: string, options: reqSendMultiPartOptions): Promise<ResData>,
44
+ }
45
+
46
+ interface StreamHelper {
47
+ /**
48
+ * 实现一个promise流传输
49
+ * @param source
50
+ * @param target
51
+ * @param options
52
+ */
53
+ pipe(source: ReadStream, target: WriteStream, options?: pipeOptions): Promise<void>,
54
+ /**
55
+ * stream传输限流
56
+ * @param stream
57
+ * @param readBytesPreSec
58
+ */
59
+ limitStreamFlowingRate(stream: ReadStream, readBytesPreSec: number): void
60
+ }
61
+
62
+ interface Cutil {
63
+ /**
64
+ * 获取一个随机字符串
65
+ * @param length
66
+ * @param options
67
+ */
68
+ randomString(length: number, options?: randomStringOptions): string
69
+ }
70
+
71
+ declare const hgo: Hgo;
72
+ declare const streamhelper: StreamHelper;
73
+ declare const cutil: Cutil;
74
+ export {
75
+ hgo,
76
+ streamhelper,
77
+ cutil
78
+ }
package/index.js ADDED
@@ -0,0 +1,9 @@
1
+ const hgo = require('./build/src/hgo');
2
+ const streamhelper = require('./build/src/streamhelper');
3
+ const cutil = require('./build/src/cutil');
4
+
5
+ module.exports = {
6
+ hgo,
7
+ streamhelper,
8
+ cutil
9
+ };
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "cvitool",
3
+ "version": "1.0.6",
4
+ "description": "cvitool",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "npm run build && node ./build/test/index.test.js",
8
+ "build": "rm -rf build && tsc"
9
+ },
10
+ "dependencies": {},
11
+ "devDependencies": {
12
+ "@typescript-eslint/eslint-plugin": "5.54.0",
13
+ "@typescript-eslint/parser": "5.54.0",
14
+ "eslint": "7.32.0",
15
+ "eslint-config-standard": "16.0.3",
16
+ "@types/node": "20.10.4"
17
+ },
18
+ "files": [
19
+ "build/src",
20
+ "src",
21
+ "index.js",
22
+ "index.d.ts",
23
+ "package.json"
24
+ ],
25
+ "keywords": [],
26
+ "repository": {
27
+ "type": "git",
28
+ "url": ""
29
+ },
30
+ "author": "",
31
+ "license": "ISC"
32
+ }
package/src/cutil.ts ADDED
@@ -0,0 +1,47 @@
1
+ import { randomInt } from 'crypto';
2
+
3
+ interface randomStringOptions {
4
+ special?: boolean,
5
+ lowercase?: boolean,
6
+ upperCase?: boolean,
7
+ number?: boolean
8
+ specials?: string
9
+ }
10
+
11
+ function randomString(length: number, options?: randomStringOptions) {
12
+ let { special = false, lowercase = true, upperCase = true, number = true, specials } = options || {};
13
+ if (specials) {
14
+ special = true;
15
+ }
16
+ if (!special && !lowercase && !upperCase && !number) {
17
+ throw new Error('randomString|must choose one of (special|lowercase|upperCase|number)');
18
+ }
19
+ const numbers = '0123456789';
20
+ const lowercaseLetters = 'abcdefghijklmnopqrstuvwxyz';
21
+ const upperCaseLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
22
+ specials = specials || '~!@#$%^*()_+-=[]{}|;:,./<>?';
23
+ let targetStr = '';
24
+ if (special) {
25
+ targetStr += specials;
26
+ }
27
+ if (lowercase) {
28
+ targetStr += lowercaseLetters;
29
+ }
30
+ if (upperCase) {
31
+ targetStr += upperCaseLetters;
32
+ }
33
+ if (number) {
34
+ targetStr += numbers;
35
+ }
36
+ let result = '';
37
+ while (length > 0) {
38
+ result += targetStr.charAt(randomInt(targetStr.length));
39
+ length--;
40
+ }
41
+ return result;
42
+ }
43
+
44
+ export {
45
+ randomStringOptions,
46
+ randomString
47
+ };
package/src/hgo.ts ADDED
@@ -0,0 +1,300 @@
1
+ import * as querystring from 'querystring';
2
+ import * as https from 'https';
3
+ import * as http from 'http';
4
+ import { ReadStream } from 'fs';
5
+
6
+ type Method = 'get' | 'put' | 'post' | 'delete' | 'patch' | 'head';
7
+ type ResType = 'json' | 'buffer' | 'stream' | 'text';
8
+
9
+ interface CustomObject {
10
+ [key: string]: any
11
+ }
12
+
13
+ interface baseReqOptions {
14
+ timeout?: number,
15
+ method?: Method,
16
+ agent?: http.Agent | https.Agent,
17
+ headers?: {
18
+ [key: string]: string
19
+ },
20
+ resType?: ResType
21
+ }
22
+
23
+ interface reqOptions extends baseReqOptions {
24
+ query?: {
25
+ [key: string]: string
26
+ },
27
+ body?: {
28
+ [key: string]: any
29
+ }
30
+ }
31
+
32
+ interface reqSendBufferOptions extends baseReqOptions {
33
+ buffer: Buffer
34
+ }
35
+
36
+ interface reqSendStreamOptions extends baseReqOptions {
37
+ stream: ReadStream
38
+ }
39
+
40
+ interface reqSendMultiPartOptions extends baseReqOptions {
41
+ form: any
42
+ }
43
+
44
+ interface ResData {
45
+ reqUrl: string,
46
+ resHeaders: CustomObject,
47
+ resBody: http.IncomingMessage | CustomObject | string | Buffer | null
48
+ }
49
+
50
+ function getTimeOutMessage(timeout: number): string {
51
+ return `request timeout of ${timeout} ms`;
52
+ }
53
+
54
+ function getProtocol(url: string) {
55
+ return url.startsWith('https') ? https : http;
56
+ }
57
+
58
+ async function request(url: string, options?: reqOptions): Promise<ResData> {
59
+ const { query = {}, body = {}, headers = {}, timeout = 5000, method = 'get', agent, resType = 'json' } = options || {};
60
+ if (Object.keys(query).length !== 0) {
61
+ if (url.indexOf('?') > -1) {
62
+ url = url + '&' + querystring.stringify(query);
63
+ } else {
64
+ url = url + '?' + querystring.stringify(query);
65
+ }
66
+ }
67
+ const data = JSON.stringify(body);
68
+ const protocol = getProtocol(url);
69
+ const isbodyEmpty = Object.keys(body).length === 0;
70
+ const baseHeaders = {
71
+ 'Content-Type': 'application/json;charset=utf-8',
72
+ 'Content-length': isbodyEmpty ? 0 : Buffer.byteLength(data)
73
+ };
74
+ return new Promise((resolve, reject) => {
75
+ const req = protocol.request(url, {
76
+ timeout,
77
+ headers: Object.assign(headers, baseHeaders),
78
+ method,
79
+ agent
80
+ }, res => {
81
+ resHandld(res, resolve, reject, resType, method);
82
+ });
83
+ req.on('timeout', () => {
84
+ req.destroy();
85
+ reject(new Error(getTimeOutMessage(timeout)));
86
+ });
87
+ req.on('error', e => {
88
+ req.destroy();
89
+ reject(e);
90
+ });
91
+ if (isbodyEmpty) {
92
+ req.end();
93
+ } else {
94
+ req.write(data, (e) => {
95
+ req.end();
96
+ if (e) {
97
+ req.destroy();
98
+ reject(e);
99
+ }
100
+ });
101
+ }
102
+ });
103
+ }
104
+
105
+ async function reqSendBuffer(url: string, options: reqSendBufferOptions): Promise<ResData> {
106
+ const { timeout = 60000, headers = {}, buffer, method = 'post', agent, resType = 'json' } = options;
107
+ const protocol = getProtocol(url);
108
+ return new Promise((resolve, reject) => {
109
+ const req = protocol.request(url, {
110
+ timeout,
111
+ headers: Object.assign(headers, { 'Content-Length': buffer.byteLength }),
112
+ method,
113
+ agent
114
+ }, res => {
115
+ resHandld(res, resolve, reject, resType, method);
116
+ });
117
+ req.on('timeout', () => {
118
+ req.destroy();
119
+ reject(new Error(getTimeOutMessage(timeout)));
120
+ });
121
+ req.on('error', e => {
122
+ req.destroy();
123
+ reject(e);
124
+ });
125
+ req.write(buffer, (e) => {
126
+ req.end();
127
+ if (e) {
128
+ req.destroy();
129
+ reject(e);
130
+ }
131
+ });
132
+ });
133
+ }
134
+
135
+ async function reqSendStream(url: string, options: reqSendStreamOptions): Promise<ResData> {
136
+ const { timeout = 60000, method = 'post', stream, headers = {}, agent, resType = 'json' } = options;
137
+ const protocol = getProtocol(url);
138
+ return new Promise((resolve, reject) => {
139
+ const baseHeaders = {
140
+ 'Content-Type': 'application/octet-stream',
141
+ 'Transfer-Encoding': 'chunked',
142
+ Connection: 'keep-alive'
143
+ };
144
+ const req = protocol.request(url, {
145
+ timeout,
146
+ headers: Object.assign(headers, baseHeaders),
147
+ method,
148
+ agent
149
+ }, res => {
150
+ resHandld(res, resolve, reject, resType, method);
151
+ });
152
+ req.on('timeout', () => {
153
+ req.destroy();
154
+ reject(new Error(getTimeOutMessage(timeout)));
155
+ });
156
+ req.on('error', e => {
157
+ req.destroy();
158
+ reject(e);
159
+ });
160
+ stream.on('data', chunk => {
161
+ req.write(chunk, e => {
162
+ if (e) {
163
+ req.destroy();
164
+ reject(e);
165
+ }
166
+ });
167
+ });
168
+ stream.on('end', () => {
169
+ req.end();
170
+ stream.close();
171
+ });
172
+ stream.on('error', e => {
173
+ req.destroy();
174
+ stream.close();
175
+ reject(e);
176
+ });
177
+ });
178
+ }
179
+
180
+ async function reqSendMultiPart(url: string, options: reqSendMultiPartOptions): Promise<ResData> {
181
+ const { timeout = 60000, headers = {}, form, agent, resType = 'json' } = options;
182
+ const protocol = getProtocol(url);
183
+ return new Promise((resolve, reject) => {
184
+ const req = protocol.request(url, {
185
+ timeout,
186
+ headers: Object.assign(headers, { ...form.getHeaders() }),
187
+ method: 'post',
188
+ agent
189
+ }, res => {
190
+ resHandld(res, resolve, reject, resType, 'post');
191
+ });
192
+ req.on('timeout', () => {
193
+ req.destroy();
194
+ reject(new Error(getTimeOutMessage(timeout)));
195
+ });
196
+ req.on('error', e => {
197
+ req.destroy();
198
+ reject(e);
199
+ });
200
+ form.pipe(req);
201
+ form.on('end', () => {
202
+ req.end();
203
+ });
204
+ form.on('error', e => {
205
+ req.destroy();
206
+ form.destroy();
207
+ reject(e);
208
+ });
209
+ });
210
+ }
211
+
212
+ function resHandld(res: http.IncomingMessage, resolve: any, reject: any, resType: ResType, method: Method) {
213
+ const reqUrl = `${(res as any).req.protocol}//${(res as any).req.host}${(res as any).req.path}`;
214
+ const resHeaders: CustomObject = {};
215
+ for (let i = 0; i < res.rawHeaders.length; i += 2) {
216
+ resHeaders[res.rawHeaders[i]] = res.rawHeaders[i + 1];
217
+ if (i === res.rawHeaders.length - 2) {
218
+ break;
219
+ }
220
+ }
221
+ if (res.statusCode !== 200) {
222
+ errHandle(reject, res, reqUrl, resHeaders);
223
+ return;
224
+ }
225
+ const resData = {
226
+ reqUrl,
227
+ resHeaders,
228
+ resBody: null
229
+ };
230
+ if (method === 'head') {
231
+ resolve(resData);
232
+ return;
233
+ }
234
+ if (resType === 'stream') {
235
+ resData.resBody = res;
236
+ resolve(resData);
237
+ return;
238
+ }
239
+ let resBody: Buffer | object | string;
240
+ const chunks = [];
241
+ res.on('data', chunk => {
242
+ chunks.push(chunk);
243
+ });
244
+ res.on('end', () => {
245
+ const buffer = Buffer.concat(chunks);
246
+ if (resType === 'buffer') {
247
+ resBody = buffer;
248
+ } else {
249
+ const responseStr = buffer.toString();
250
+ if (resType === 'text') {
251
+ resBody = responseStr;
252
+ } else {
253
+ try {
254
+ resBody = JSON.parse(responseStr);
255
+ } catch (e) {
256
+ resBody = resData;
257
+ }
258
+ }
259
+ }
260
+ resData.resBody = resBody;
261
+ resolve(resData);
262
+ });
263
+ }
264
+
265
+ function errHandle(reject: any, res: http.IncomingMessage, reqUrl: string, resHeaders: CustomObject) {
266
+ const chunks = [];
267
+ res.on('data', chunk => {
268
+ chunks.push(chunk);
269
+ });
270
+ res.on('end', () => {
271
+ const buffer = Buffer.concat(chunks);
272
+ const resData = buffer.toString();
273
+ let resBody: object | string;
274
+ try {
275
+ resBody = JSON.parse(resData);
276
+ } catch (e) {
277
+ resBody = resData;
278
+ }
279
+ const err: any = new Error();
280
+ err.code = res.statusCode;
281
+ err.name = 'statusCodeError';
282
+ err.message = `${res.statusCode}|${res.statusMessage}`;
283
+ err.resBody = resBody;
284
+ err.reqUrl = reqUrl;
285
+ err.resHeaders = resHeaders;
286
+ reject(err);
287
+ });
288
+ }
289
+
290
+ export {
291
+ reqOptions,
292
+ reqSendBufferOptions,
293
+ reqSendStreamOptions,
294
+ reqSendMultiPartOptions,
295
+ ResData,
296
+ request,
297
+ reqSendBuffer,
298
+ reqSendStream,
299
+ reqSendMultiPart,
300
+ };
@@ -0,0 +1,59 @@
1
+ import { ReadStream, WriteStream } from 'fs';
2
+
3
+ interface pipeOptions {
4
+ timeout?: number,
5
+ readBytesPreSec?: number
6
+ }
7
+
8
+ async function pipe(source: ReadStream, target: WriteStream, options?: pipeOptions): Promise<void> {
9
+ const { timeout, readBytesPreSec } = options || {};
10
+ return new Promise((resolve, reject) => {
11
+ if (readBytesPreSec) {
12
+ limitStreamFlowingRate(source, readBytesPreSec);
13
+ }
14
+ source.pipe(target);
15
+ target.on('finish', () => {
16
+ resolve();
17
+ });
18
+ source.on('error', e => {
19
+ reject(e);
20
+ });
21
+ if (timeout) {
22
+ setTimeout(() => {
23
+ if (!target.closed) {
24
+ target.destroy();
25
+ source.destroy();
26
+ const downloadErr = new Error(`文件下载超时|${(timeout / 1000).toFixed(3)}s`);
27
+ reject(downloadErr);
28
+ }
29
+ }, timeout);
30
+ }
31
+ });
32
+ }
33
+
34
+ function limitStreamFlowingRate(stream: ReadStream, readBytesPreSec: number) {
35
+ let start = 0;
36
+ let calReadBytesTotal = 0;
37
+ stream.on('data', (chunk) => {
38
+ if (!start) {
39
+ start = Date.now();
40
+ }
41
+ calReadBytesTotal += chunk.length;
42
+ const fromStartSecs = Math.ceil((Date.now() - start) / 1000);
43
+ if (calReadBytesTotal > fromStartSecs * readBytesPreSec && fromStartSecs > 0) {
44
+ const stopTime = Math.ceil((fromStartSecs - ((Date.now() - start) / 1000)) * 1000);
45
+ if (stopTime > 0) {
46
+ stream.pause();
47
+ setTimeout(() => {
48
+ stream.resume();
49
+ }, stopTime);
50
+ }
51
+ }
52
+ });
53
+ }
54
+
55
+ export {
56
+ pipeOptions,
57
+ pipe,
58
+ limitStreamFlowingRate
59
+ };