|
1 | | -const { open, fstat, read, close, openSync, fstatSync, readSync, closeSync } = require('node:fs'); |
| 1 | +const { openSync, fstatSync, readSync, closeSync } = require('node:fs'); |
| 2 | +const fsPromises = require('node:fs/promises'); |
2 | 3 | const { basename, join, resolve } = require('node:path'); |
3 | 4 | const { isIP } = require('node:net'); |
4 | | -const async = require('async'); |
5 | 5 | const { aton4, aton6, cmp6, removeNullTerminator, readIp6, createGeoData, populateGeoDataFromLocation } = require('./scripts/utils.js'); |
6 | 6 | const fsWatcher = require('./scripts/fsWatcher.js'); |
7 | 7 | const { version } = require('./package.json'); |
@@ -81,8 +81,6 @@ const lookup4 = ip => { |
81 | 81 | ceil = buffer.readUInt32BE(offset + 4); |
82 | 82 |
|
83 | 83 | if (floor <= ip && ceil >= ip) { |
84 | | - geoData.range = [floor, ceil]; |
85 | | - |
86 | 84 | if (recordSize === RECORD_SIZE) { |
87 | 85 | geoData.country = buffer.toString('utf8', offset + 8, offset + 10); |
88 | 86 | } else { |
@@ -180,105 +178,55 @@ const get4mapped = ip => { |
180 | 178 | return null; |
181 | 179 | }; |
182 | 180 |
|
183 | | -const preload = callback => { |
184 | | - let datFile; |
185 | | - let datSize; |
| 181 | +const readFileBuffer = async filePath => { |
| 182 | + const fileHandle = await fsPromises.open(filePath, 'r'); |
| 183 | + try { |
| 184 | + const { size } = await fileHandle.stat(); |
| 185 | + const buffer = Buffer.alloc(size); |
| 186 | + if (size > 0) { |
| 187 | + await fileHandle.read(buffer, 0, size, 0); |
| 188 | + } |
| 189 | + return { buffer, size }; |
| 190 | + } finally { |
| 191 | + await fileHandle.close(); |
| 192 | + } |
| 193 | +}; |
| 194 | + |
| 195 | +const isExpectedMissingDataError = err => err?.code === 'ENOENT' || err?.code === 'EBADF'; |
| 196 | + |
| 197 | +const preloadAsync = async () => { |
186 | 198 | const asyncCache = { ...conf4 }; |
| 199 | + let mainData; |
| 200 | + |
| 201 | + try { |
| 202 | + const cityNamesData = await readFileBuffer(dataFiles.cityNames); |
| 203 | + if (cityNamesData.size === 0) { |
| 204 | + const emptyFileError = new Error('geoip-city-names.dat is empty'); |
| 205 | + emptyFileError.code = 'ENOENT'; |
| 206 | + throw emptyFileError; |
| 207 | + } |
| 208 | + |
| 209 | + asyncCache.locationBuffer = cityNamesData.buffer; |
| 210 | + mainData = await readFileBuffer(dataFiles.city); |
| 211 | + } catch (err) { |
| 212 | + if (!isExpectedMissingDataError(err)) throw err; |
| 213 | + mainData = await readFileBuffer(dataFiles.country); |
| 214 | + asyncCache.recordSize = RECORD_SIZE; |
| 215 | + } |
| 216 | + |
| 217 | + asyncCache.mainBuffer = mainData.buffer; |
| 218 | + asyncCache.lastLine = (mainData.size / asyncCache.recordSize) - 1; |
| 219 | + asyncCache.lastIP = asyncCache.mainBuffer.readUInt32BE((asyncCache.lastLine * asyncCache.recordSize) + 4); |
| 220 | + asyncCache.firstIP = asyncCache.mainBuffer.readUInt32BE(0); |
| 221 | + cache4 = asyncCache; |
| 222 | +}; |
| 223 | + |
| 224 | +const preload = callback => { |
187 | 225 | if (typeof callback === 'function') { |
188 | | - void async.series([ |
189 | | - cb => { |
190 | | - void async.series([ |
191 | | - cb2 => { |
192 | | - open(dataFiles.cityNames, 'r', (err, file) => { |
193 | | - datFile = file; |
194 | | - cb2(err); |
195 | | - }); |
196 | | - }, |
197 | | - cb2 => { |
198 | | - fstat(datFile, (err, stats) => { |
199 | | - if (err) { |
200 | | - cb2(err); |
201 | | - return; |
202 | | - } |
203 | | - datSize = stats.size; |
204 | | - asyncCache.locationBuffer = Buffer.alloc(datSize); |
205 | | - cb2(); |
206 | | - }); |
207 | | - }, |
208 | | - cb2 => { |
209 | | - read(datFile, asyncCache.locationBuffer, 0, datSize, 0, cb2); |
210 | | - }, |
211 | | - cb2 => { |
212 | | - close(datFile, cb2); |
213 | | - }, |
214 | | - cb2 => { |
215 | | - open(dataFiles.city, 'r', (err, file) => { |
216 | | - datFile = file; |
217 | | - cb2(err); |
218 | | - }); |
219 | | - }, |
220 | | - cb2 => { |
221 | | - fstat(datFile, (err, stats) => { |
222 | | - if (err) { |
223 | | - cb2(err); |
224 | | - return; |
225 | | - } |
226 | | - datSize = stats.size; |
227 | | - cb2(); |
228 | | - }); |
229 | | - }, |
230 | | - ], err => { |
231 | | - if (err) { |
232 | | - if (err.code !== 'ENOENT' && err.code !== 'EBADF') { |
233 | | - cb(err); |
234 | | - return; |
235 | | - } |
236 | | - |
237 | | - open(dataFiles.country, 'r', (err, file) => { |
238 | | - if (err) { |
239 | | - cb(err); |
240 | | - } else { |
241 | | - datFile = file; |
242 | | - fstat(datFile, (err, stats) => { |
243 | | - if (err) { |
244 | | - cb(err); |
245 | | - return; |
246 | | - } |
247 | | - datSize = stats.size; |
248 | | - asyncCache.recordSize = RECORD_SIZE; |
249 | | - |
250 | | - cb(); |
251 | | - }); |
252 | | - } |
253 | | - }); |
254 | | - |
255 | | - } else { |
256 | | - cb(); |
257 | | - } |
258 | | - }); |
259 | | - }, |
260 | | - cb => { |
261 | | - asyncCache.mainBuffer = Buffer.alloc(datSize); |
262 | | - |
263 | | - void async.series([ |
264 | | - cb2 => { |
265 | | - read(datFile, asyncCache.mainBuffer, 0, datSize, 0, cb2); |
266 | | - }, |
267 | | - cb2 => { |
268 | | - close(datFile, cb2); |
269 | | - }, |
270 | | - ], err => { |
271 | | - if (!err) { |
272 | | - asyncCache.lastLine = (datSize / asyncCache.recordSize) - 1; |
273 | | - asyncCache.lastIP = asyncCache.mainBuffer.readUInt32BE((asyncCache.lastLine * asyncCache.recordSize) + 4); |
274 | | - asyncCache.firstIP = asyncCache.mainBuffer.readUInt32BE(0); |
275 | | - cache4 = asyncCache; |
276 | | - } |
277 | | - cb(err); |
278 | | - }); |
279 | | - }, |
280 | | - ], callback); |
| 226 | + preloadAsync().then(() => callback()).catch(callback); |
281 | 227 | } else { |
| 228 | + let datFile; |
| 229 | + let datSize; |
282 | 230 | try { |
283 | 231 | datFile = openSync(dataFiles.cityNames, 'r'); |
284 | 232 | datSize = fstatSync(datFile).size; |
@@ -315,81 +263,38 @@ const preload = callback => { |
315 | 263 | } |
316 | 264 | }; |
317 | 265 |
|
318 | | -const preload6 = callback => { |
319 | | - let datFile; |
320 | | - let datSize; |
| 266 | +const preload6Async = async () => { |
321 | 267 | const asyncCache6 = { ...conf6 }; |
| 268 | + let mainData; |
| 269 | + |
| 270 | + try { |
| 271 | + const cityData = await readFileBuffer(dataFiles.city6); |
| 272 | + if (cityData.size === 0) { |
| 273 | + const emptyFileError = new Error('geoip-city6.dat is empty'); |
| 274 | + emptyFileError.code = 'ENOENT'; |
| 275 | + throw emptyFileError; |
| 276 | + } |
| 277 | + |
| 278 | + mainData = cityData; |
| 279 | + } catch (err) { |
| 280 | + if (!isExpectedMissingDataError(err)) throw err; |
| 281 | + mainData = await readFileBuffer(dataFiles.country6); |
| 282 | + asyncCache6.recordSize = RECORD_SIZE6; |
| 283 | + } |
| 284 | + |
| 285 | + asyncCache6.mainBuffer = mainData.buffer; |
| 286 | + asyncCache6.lastLine = (mainData.size / asyncCache6.recordSize) - 1; |
| 287 | + asyncCache6.lastIP = readIp6(asyncCache6.mainBuffer, asyncCache6.lastLine, asyncCache6.recordSize, 1); |
| 288 | + asyncCache6.firstIP = readIp6(asyncCache6.mainBuffer, 0, asyncCache6.recordSize, 0); |
| 289 | + cache6 = asyncCache6; |
| 290 | +}; |
| 291 | + |
| 292 | +const preload6 = callback => { |
322 | 293 | if (typeof callback === 'function') { |
323 | | - void async.series([ |
324 | | - cb => { |
325 | | - void async.series([ |
326 | | - cb2 => { |
327 | | - open(dataFiles.city6, 'r', (err, file) => { |
328 | | - datFile = file; |
329 | | - cb2(err); |
330 | | - }); |
331 | | - }, |
332 | | - cb2 => { |
333 | | - fstat(datFile, (err, stats) => { |
334 | | - if (err) { |
335 | | - cb2(err); |
336 | | - return; |
337 | | - } |
338 | | - datSize = stats.size; |
339 | | - cb2(); |
340 | | - }); |
341 | | - }, |
342 | | - ], err => { |
343 | | - if (err) { |
344 | | - if (err.code !== 'ENOENT' && err.code !== 'EBADF') { |
345 | | - cb(err); |
346 | | - return; |
347 | | - } |
348 | | - |
349 | | - open(dataFiles.country6, 'r', (err, file) => { |
350 | | - if (err) { |
351 | | - cb(err); |
352 | | - } else { |
353 | | - datFile = file; |
354 | | - fstat(datFile, (err, stats) => { |
355 | | - if (err) { |
356 | | - cb(err); |
357 | | - return; |
358 | | - } |
359 | | - datSize = stats.size; |
360 | | - asyncCache6.recordSize = RECORD_SIZE6; |
361 | | - |
362 | | - cb(); |
363 | | - }); |
364 | | - } |
365 | | - }); |
366 | | - } else { |
367 | | - cb(); |
368 | | - } |
369 | | - }); |
370 | | - }, |
371 | | - cb => { |
372 | | - asyncCache6.mainBuffer = Buffer.alloc(datSize); |
373 | | - |
374 | | - void async.series([ |
375 | | - cb2 => { |
376 | | - read(datFile, asyncCache6.mainBuffer, 0, datSize, 0, cb2); |
377 | | - }, |
378 | | - cb2 => { |
379 | | - close(datFile, cb2); |
380 | | - }, |
381 | | - ], err => { |
382 | | - if (!err) { |
383 | | - asyncCache6.lastLine = (datSize / asyncCache6.recordSize) - 1; |
384 | | - asyncCache6.lastIP = readIp6(asyncCache6.mainBuffer, asyncCache6.lastLine, asyncCache6.recordSize, 1); |
385 | | - asyncCache6.firstIP = readIp6(asyncCache6.mainBuffer, 0, asyncCache6.recordSize, 0); |
386 | | - cache6 = asyncCache6; |
387 | | - } |
388 | | - cb(err); |
389 | | - }); |
390 | | - }, |
391 | | - ], callback); |
| 294 | + preload6Async().then(() => callback()).catch(callback); |
392 | 295 | } else { |
| 296 | + let datFile; |
| 297 | + let datSize; |
393 | 298 | try { |
394 | 299 | datFile = openSync(dataFiles.city6, 'r'); |
395 | 300 | datSize = fstatSync(datFile).size; |
@@ -421,14 +326,10 @@ const preload6 = callback => { |
421 | 326 | }; |
422 | 327 |
|
423 | 328 | const runAsyncReload = callback => { |
424 | | - void async.series([ |
425 | | - cb => { |
426 | | - preload(cb); |
427 | | - }, |
428 | | - cb => { |
429 | | - preload6(cb); |
430 | | - }, |
431 | | - ], callback); |
| 329 | + preloadAsync() |
| 330 | + .then(() => preload6Async()) |
| 331 | + .then(() => callback()) |
| 332 | + .catch(callback); |
432 | 333 | }; |
433 | 334 |
|
434 | 335 | module.exports = { |
|
0 commit comments