@k03mad/request 2.1.0 → 3.0.0

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/app/lib/curl.js CHANGED
@@ -4,7 +4,6 @@ import prettyBytes from 'pretty-bytes';
4
4
  const {bgWhite, black, blue, dim, green, magenta, red, white, yellow} = chalk;
5
5
 
6
6
  /**
7
- * Сформировать curl-строку из опций got
8
7
  * @param {string} url
9
8
  * @param {object} [opts]
10
9
  * @param {string} [opts.method]
@@ -25,12 +24,10 @@ export default (url, {
25
24
  }, res) => {
26
25
  const msg = [];
27
26
 
28
- // если третий параметр — объект ошибки, то все необходимое на уровень ниже, в ключе response
29
27
  if (res?.response) {
30
28
  res = res.response;
31
29
  }
32
30
 
33
- // 200 [800 ms] [3.15 kB]
34
31
  if (res?.statusCode) {
35
32
  msg.push(bgWhite(black(res.statusCode)));
36
33
  }
package/app/lib/queue.js CHANGED
@@ -3,27 +3,24 @@ import PQueue from 'p-queue';
3
3
 
4
4
  const debug = _debug('mad:queue');
5
5
 
6
- // const rps = num => ({intervalCap: num, interval: 1000});
7
- const concurrency = num => ({concurrency: num});
6
+ const intervals = {
7
+ concurrency: num => ({concurrency: num}),
8
+ rpm: num => ({intervalCap: num, interval: 60_000}),
9
+ rps: num => ({intervalCap: num, interval: 1000}),
10
+ };
8
11
 
9
- // первый уровень — хост (* — любой, кроме уже перечисленных)
10
- // второй уровень — метод (* — любой, кроме уже перечисленных)
11
- // третий уровень — настройки очереди из p-queue
12
+ // host: p-queue options
12
13
  const requestQueue = {
13
- '*': {
14
- '*': concurrency(3),
15
- },
14
+ '*': intervals.concurrency(3),
16
15
  };
17
16
 
18
17
  /**
19
- * Поставить логирование и вернуть очередь
20
18
  * @param {string} host
21
- * @param {string} method
22
19
  * @param {object} opts
23
20
  * @returns {object}
24
21
  */
25
- const getLoggedQueue = (host, method, opts) => {
26
- const queue = requestQueue[host][method];
22
+ const getLoggedQueue = (host, opts) => {
23
+ const queue = requestQueue[host];
27
24
 
28
25
  queue.on('active', () => {
29
26
  const {pending, size} = queue;
@@ -33,9 +30,7 @@ const getLoggedQueue = (host, method, opts) => {
33
30
  ? `${concurrent} concurrent`
34
31
  : `${intervalCap} rp ${interval} ms`;
35
32
 
36
- const logMessage = `[${
37
- method === '*' ? '' : `${method}: `
38
- }${host}] ${parallel} | queue: ${size} | running: ${pending}`;
33
+ const logMessage = `[${host}] ${parallel} | queue: ${size} | running: ${pending}`;
39
34
 
40
35
  debug(logMessage);
41
36
  });
@@ -44,43 +39,34 @@ const getLoggedQueue = (host, method, opts) => {
44
39
  };
45
40
 
46
41
  /**
47
- * Получить очередь по хосту и методу
48
42
  * @param {string} host
49
- * @param {string} method
43
+ * @param {object} params
44
+ * @param {number} params.concurrency
45
+ * @param {number} params.rpm
46
+ * @param {number} params.rps
50
47
  * @returns {object}
51
48
  */
52
- export default (host, method = 'GET') => {
53
- // проверка на предустановленные настройки очереди для хоста и метода
54
- for (const elem of [method, '*']) {
55
- // очередь уже проинициализирована
56
- if (requestQueue[host]?.[elem]?._events) {
57
- return requestQueue[host][elem];
58
- }
49
+ export default (host, params) => {
50
+ if (requestQueue[host]?._events) {
51
+ return requestQueue[host];
52
+ }
59
53
 
60
- // очередь нужно проинициализировать
61
- if (requestQueue[host]?.[elem]) {
62
- const opts = requestQueue[host][elem];
63
- requestQueue[host][elem] = new PQueue(opts);
64
- return getLoggedQueue(host, elem, opts);
54
+ if (Object.keys(params).length > 0) {
55
+ for (const [key, value] of Object.entries(params)) {
56
+ if (intervals[key]) {
57
+ requestQueue[host] = intervals[key](value);
58
+ break;
59
+ }
65
60
  }
66
61
  }
67
62
 
68
- // инициализация очереди для хоста без текущего метода в предустановках
69
63
  if (requestQueue[host]) {
70
- const opts = requestQueue['*']['*'];
71
- requestQueue[host]['*'] = new PQueue(opts);
72
- return getLoggedQueue(host, '*', opts);
73
- }
74
-
75
- // инициализация очереди для хоста с методом из предустановок для всех очередей
76
- if (requestQueue['*'][method]) {
77
- const opts = requestQueue['*'][method];
78
- requestQueue[host] = {[method]: new PQueue(opts)};
79
- return getLoggedQueue(host, method, opts);
64
+ const opts = requestQueue[host];
65
+ requestQueue[host] = new PQueue(opts);
66
+ return getLoggedQueue(host, opts);
80
67
  }
81
68
 
82
- // нет ни хоста не метода в предустановках
83
- const opts = requestQueue['*']['*'];
84
- requestQueue[host] = {'*': new PQueue(opts)};
85
- return getLoggedQueue(host, '*', opts);
69
+ const opts = requestQueue['*'];
70
+ requestQueue[host] = new PQueue(opts);
71
+ return getLoggedQueue(host, opts);
86
72
  };
@@ -8,21 +8,37 @@ import getQueue from './queue.js';
8
8
  const {blue, cyan, dim, green, red, yellow} = chalk;
9
9
  const debug = _debug('mad:request');
10
10
 
11
- const gotDefault = got.extend({
11
+ const gotCache = new Map();
12
+
13
+ const cacheGotResponseKeys = [
14
+ 'body',
15
+ 'headers',
16
+ 'method',
17
+ 'statusCode',
18
+ 'statusMessage',
19
+ 'timings',
20
+ ];
21
+
22
+ const gotDefaultOpts = got.extend({
12
23
  dnsCache: true,
13
24
  timeout: {request: 15_000},
14
- headers: {'user-agent': 'curl/8.1.2'},
25
+ headers: {'user-agent': 'curl/7.81.0'},
15
26
  });
16
27
 
28
+ const cacheDebug = msgArr => {
29
+ if (process.env.DEBUG) {
30
+ debug(msgArr.join(' :: '));
31
+ }
32
+ };
33
+
17
34
  /**
18
- * Отправить запрос
19
35
  * @param {string} url
20
36
  * @param {object} opts
21
37
  * @returns {object}
22
38
  */
23
39
  const sendRequest = async (url, opts) => {
24
40
  try {
25
- const response = await gotDefault(url, opts);
41
+ const response = await gotDefaultOpts(url, opts);
26
42
 
27
43
  if (!opts.responseType) {
28
44
  try {
@@ -65,22 +81,17 @@ const sendRequest = async (url, opts) => {
65
81
  }
66
82
  };
67
83
 
68
- export const cache = new Map();
69
-
70
84
  /**
71
- * Отправить запрос c выбором использования очереди
72
85
  * @param {string} url
73
86
  * @param {object} [opts]
74
87
  * @param {object} [params]
75
- * @param {boolean} [params.skipQueue]
88
+ * @param {number} [params.concurrency]
89
+ * @param {number} [params.rpm]
90
+ * @param {number} [params.rps]
76
91
  * @returns {Promise<object>}
77
92
  */
78
- export const request = (url, opts = {}, {skipQueue} = {}) => {
79
- if (skipQueue) {
80
- return sendRequest(url, opts);
81
- }
82
-
83
- const queue = getQueue(new URL(url).host, opts.method);
93
+ export const request = (url, opts = {}, params = {}) => {
94
+ const queue = getQueue(new URL(url).host, params);
84
95
  return queue.add(() => sendRequest(url, opts));
85
96
  };
86
97
 
@@ -90,45 +101,40 @@ export const request = (url, opts = {}, {skipQueue} = {}) => {
90
101
  * @param {object} [params]
91
102
  * @param {number} [params.expire] seconds
92
103
  * @param {object} [params.cacheBy]
104
+ * @param {number} [params.concurrency]
105
+ * @param {number} [params.rpm]
106
+ * @param {number} [params.rps]
93
107
  * @returns {Promise<object>}
94
108
  */
95
- export const requestCache = (url, opts = {}, {cacheBy, expire = 43_200} = {}) => {
96
- const queue = getQueue(new URL(url).host, opts.method);
109
+ export const requestCache = (url, opts = {}, {cacheBy, expire = 43_200, ...params} = {}) => {
110
+ const queue = getQueue(new URL(url).host, params);
97
111
 
98
112
  return queue.add(async () => {
99
- const cacheGotResponseKeys = [
100
- 'body',
101
- 'headers',
102
- 'method',
103
- 'statusCode',
104
- 'statusMessage',
105
- 'timings',
106
- ];
107
-
108
113
  const cacheKey = `${url}::${JSON.stringify(cacheBy || opts)}`;
109
- const log = `${blue(url)}\n${dim(cacheKey)}`;
114
+ const urlLog = `${blue(url)}\n${dim(cacheKey)}`;
110
115
 
111
116
  try {
112
- if (cache.has(cacheKey)) {
113
- const {cachedResponse, date} = cache.get(cacheKey);
117
+ if (gotCache.has(cacheKey)) {
118
+ const {cachedResponse, date} = gotCache.get(cacheKey);
114
119
 
115
120
  const measurement = 'seconds';
116
121
  const currentDiff = Math.round((Date.now() - date) / 1000);
122
+ const diffLog = `${currentDiff}/${expire} ${measurement} left`;
117
123
 
118
124
  if (currentDiff < expire) {
119
- debug(`${green('FROM CACHE')} :: ${currentDiff}/${expire} ${measurement} left :: ${log}`);
125
+ cacheDebug([green('FROM CACHE'), diffLog, urlLog]);
120
126
  return {cacheKey, ...cachedResponse};
121
127
  }
122
128
 
123
- debug(`${red('CACHE EXPIRED')} :: ${currentDiff}/${expire} ${measurement} left :: ${log}`);
129
+ cacheDebug([yellow('CACHE EXPIRED'), diffLog, urlLog]);
124
130
  } else {
125
- debug(`${yellow('CACHE NOT FOUND')} :: ${log}`);
131
+ cacheDebug([blue('CACHE NOT FOUND'), urlLog]);
126
132
  }
127
133
  } catch (err) {
128
- debug(`${red('CACHE ERROR')} :: ${dim(err)} :: ${log}`);
134
+ cacheDebug([red('CACHE ERROR'), dim(err), urlLog]);
129
135
  }
130
136
 
131
- const res = await request(url, opts, {skipQueue: true});
137
+ const res = await sendRequest(url, opts);
132
138
 
133
139
  const cachedResponse = {};
134
140
 
@@ -136,8 +142,8 @@ export const requestCache = (url, opts = {}, {cacheBy, expire = 43_200} = {}) =>
136
142
  cachedResponse[key] = res[key];
137
143
  });
138
144
 
139
- cache.set(cacheKey, {date: Date.now(), cachedResponse});
140
- debug(`${cyan('CACHE SAVED')} :: ${log}`);
145
+ gotCache.set(cacheKey, {date: Date.now(), cachedResponse});
146
+ cacheDebug([cyan('CACHE SAVED'), urlLog]);
141
147
 
142
148
  return res;
143
149
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k03mad/request",
3
- "version": "2.1.0",
3
+ "version": "3.0.0",
4
4
  "description": "Request library",
5
5
  "maintainers": [
6
6
  "Kirill Molchanov <k03.mad@gmail.com"
@@ -20,7 +20,7 @@
20
20
  "pretty-bytes": "6.1.1"
21
21
  },
22
22
  "devDependencies": {
23
- "@k03mad/eslint-config": "12.0.5",
23
+ "@k03mad/eslint-config": "12.0.6",
24
24
  "@microsoft/eslint-formatter-sarif": "3.0.0",
25
25
  "eslint": "8.46.0",
26
26
  "eslint-plugin-import": "2.28.0",