@k03mad/ip2geo 9.2.0 → 9.4.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.
@@ -1,3 +1,7 @@
1
1
  {
2
- "eslint.experimental.useFlatConfig": true
2
+ "cSpell.words": [
3
+ "consts",
4
+ "geoip",
5
+ "nvmrc"
6
+ ]
3
7
  }
package/app/cli.js CHANGED
@@ -7,7 +7,7 @@ import {DEFAULT_CACHE_FILE_DIR, DEFAULT_CACHE_FILE_NEWLINE, DEFAULT_CACHE_FILE_S
7
7
  import {pruneCache} from './helpers/cache.js';
8
8
  import {codeText, nameText} from './helpers/colors.js';
9
9
 
10
- const {blue, red, green} = chalk;
10
+ const {blue, red, green, dim, bold} = chalk;
11
11
 
12
12
  const args = process.argv.slice(2);
13
13
  const argsExtra = args.filter(arg => !arg.startsWith('-'));
@@ -43,6 +43,7 @@ if (isHelp) {
43
43
 
44
44
  if (isPrune) {
45
45
  const cacheFolder = argsExtra[0] || DEFAULT_CACHE_FILE_DIR;
46
+ log(blue(cacheFolder));
46
47
 
47
48
  try {
48
49
  const {duplicates, empty, longLinesFiles} = await pruneCache(
@@ -51,27 +52,22 @@ if (isPrune) {
51
52
  DEFAULT_CACHE_FILE_NEWLINE,
52
53
  );
53
54
 
54
- const message = [
55
+ log([
55
56
  '',
56
- `Removed duplicate cache entries: ${green(duplicates)}`,
57
- `Removed empty cache entries: ${green(empty)}`,
58
- ];
59
-
60
- if (longLinesFiles.size > 0) {
61
- message.push(
62
- '',
63
- red('Something went wrong with these cache files (lines too long):'),
64
- ...[...longLinesFiles].map(elem => blue(`— ${elem}`)),
65
- );
57
+ green(`Removed duplicate cache entries: ${bold(duplicates.length)}`),
58
+ ...duplicates.map(elem => dim(`— ${elem}`)),
59
+ green(`Removed empty cache entries: ${bold(empty.length)}`),
60
+ ...empty.map(elem => dim(`— ${elem}`)),
61
+ ]);
62
+
63
+ if (longLinesFiles.length > 0) {
64
+ log([
65
+ red(`Required manual check, some cache files has too long lines: ${bold(longLinesFiles.length)}`),
66
+ ...longLinesFiles.map(({file, elem}) => dim(`— ${file}\n|— ${elem}`)),
67
+ ]);
66
68
  }
67
-
68
- log(message);
69
69
  } catch (err) {
70
- if (err.code !== 'ENOENT') {
71
- logErrorExit(err);
72
- }
73
-
74
- log(`Cache folder empty: ${cacheFolder}`);
70
+ logErrorExit(red(err));
75
71
  }
76
72
  } else {
77
73
  const output = argsExtra.length === 0
@@ -1,14 +1,12 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
 
4
- import {log} from '@k03mad/simple-log';
5
- import chalk from 'chalk';
6
4
  import _debug from 'debug';
7
5
 
8
- const {dim, bold} = chalk;
9
-
10
6
  const debug = _debug('mad:geoip');
11
7
 
8
+ const ipRe = /((25[0-5]|((?:2[0-4]|1\d|[1-9])?)\d)\.?\b){4}/;
9
+
12
10
  const outputKeys = [
13
11
  'ip',
14
12
  'continent',
@@ -165,6 +163,19 @@ export const writeToMapCache = (body, cacheMap, cacheMapMaxEntries) => {
165
163
  export const pruneCache = async (cacheDir, cacheFileSeparator, cacheFileNewline) => {
166
164
  const files = await fs.readdir(cacheDir);
167
165
 
166
+ await Promise.all(files.map(async file => {
167
+ const fullFilePath = path.join(cacheDir, file);
168
+
169
+ const [stat, data] = await Promise.all([
170
+ fs.lstat(fullFilePath),
171
+ fs.readFile(fullFilePath, {encoding: 'utf8'}),
172
+ ]);
173
+
174
+ if (stat.isDirectory() || !ipRe.test(data)) {
175
+ throw new Error(`Folder has subfolders or files without IPs, wrong cache folder arg?\n${fullFilePath}`);
176
+ }
177
+ }));
178
+
168
179
  const cacheLineToNum = line => Number(
169
180
  line.split(cacheFileSeparator)[0]
170
181
  .split('.')
@@ -172,9 +183,8 @@ export const pruneCache = async (cacheDir, cacheFileSeparator, cacheFileNewline)
172
183
  .join(''),
173
184
  );
174
185
 
175
- let duplicates = 0;
176
- let empty = 0;
177
- let counter = 0;
186
+ const duplicates = new Set();
187
+ const empty = [];
178
188
  const longLinesFiles = new Set();
179
189
 
180
190
  await Promise.all(files.map(async file => {
@@ -187,10 +197,14 @@ export const pruneCache = async (cacheDir, cacheFileSeparator, cacheFileNewline)
187
197
  const splitted = elem.split(cacheFileSeparator);
188
198
 
189
199
  if (splitted.length > outputKeys.length) {
190
- longLinesFiles.add(fullFilePath);
200
+ longLinesFiles.add({file: fullFilePath, elem});
191
201
  }
192
202
 
193
- return splitted.filter(Boolean).length > 1;
203
+ if (splitted.filter(Boolean).length > 1) {
204
+ return true;
205
+ }
206
+
207
+ empty.push(elem);
194
208
  });
195
209
 
196
210
  const uniq = [...new Set(dataArrRemoveEmpty)]
@@ -199,12 +213,13 @@ export const pruneCache = async (cacheDir, cacheFileSeparator, cacheFileNewline)
199
213
  const fileContent = uniq.join(cacheFileNewline).trim();
200
214
  await (fileContent ? fs.writeFile(fullFilePath, fileContent) : fs.rm(fullFilePath));
201
215
 
202
- empty += dataArr.length - dataArrRemoveEmpty.length;
203
- duplicates += dataArrRemoveEmpty.length - uniq.length;
204
-
205
- counter++;
206
- log(`${bold(dim(`[${counter}/${files.length}]`))} ${dim(fullFilePath)}`);
216
+ dataArrRemoveEmpty
217
+ .forEach((elem, i, arr) => arr.indexOf(elem) !== i && duplicates.add(elem));
207
218
  }));
208
219
 
209
- return {duplicates, empty, longLinesFiles};
220
+ return {
221
+ duplicates: [...duplicates],
222
+ empty,
223
+ longLinesFiles: [...longLinesFiles],
224
+ };
210
225
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k03mad/ip2geo",
3
- "version": "9.2.0",
3
+ "version": "9.4.0",
4
4
  "description": "GeoIP library",
5
5
  "maintainers": [
6
6
  "Kirill Molchanov <k03.mad@gmail.com"
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "dependencies": {
22
22
  "@k03mad/request": "6.1.0",
23
- "@k03mad/simple-log": "2.3.0",
23
+ "@k03mad/simple-log": "3.0.0",
24
24
  "chalk": "5.3.0",
25
25
  "debug": "4.3.6"
26
26
  },