|
1 |
| -'use strict' |
| 1 | +"use strict"; |
2 | 2 |
|
3 |
| -const debug = require('debug')('geo-from-ip:updater') |
4 |
| -const fs = require('fs') |
5 |
| -const zlib = require('zlib') |
6 |
| -const async = require('async') |
7 |
| -const request = require('request') |
| 3 | +const debug = require("debug")("geo-from-ip:updater"); |
| 4 | +const fs = require("fs"); |
| 5 | +const path = require("path"); |
| 6 | +const util = require("util"); |
| 7 | +const streamPipeline = util.promisify(require("stream").pipeline); |
| 8 | +const fetch = require("node-fetch"); |
| 9 | +const targz = require("targz"); |
8 | 10 |
|
9 |
| -const config = require('../mmdb/config') |
10 |
| -debug(`Running update script with config: ${JSON.stringify(config)}`) |
| 11 | +if (process.env.MAXMIND_LICENSE_KEY === undefined) { |
| 12 | + debug( |
| 13 | + "Seems like you forgot to add MAXMIND_LICENSE_KEY to your environment variables. Read more: https://github.com/VikramTiwari/geo-from-ip#how-to-use" |
| 14 | + ); |
| 15 | + process.exit(1); |
| 16 | +} |
| 17 | + |
| 18 | +const config = require("../mmdb/config"); |
11 | 19 |
|
12 | 20 | /**
|
13 |
| - * check if remote file is newer |
14 |
| - * @param {String} dest path for local file |
15 |
| - * @param {String} remote path for remote file |
16 |
| - * @param {Function} cb true/false |
| 21 | + * uncompresses the zipped file into folders and does cleanup of remaining files and folders |
| 22 | + * @param {String} zipped path to zipped file |
| 23 | + * @param {Object} database database object |
17 | 24 | */
|
18 |
| -function isRemoteNewer (dest, remote, cb) { |
19 |
| - // if no file |
20 |
| - if (!fs.existsSync(dest)) { |
21 |
| - cb(null, false) |
22 |
| - } else { |
23 |
| - // if dest file is not a file, remove it |
24 |
| - const stats = fs.statSync(dest) |
25 |
| - if (!stats.isFile()) { |
26 |
| - debug(`${dest} is not a file`) |
27 |
| - fs.unlink(dest, () => { |
28 |
| - debug(`${dest} deleted`) |
29 |
| - }) |
30 |
| - } |
31 |
| - |
32 |
| - request( |
| 25 | +async function uncompress(zipped, database) { |
| 26 | + new Promise((resolve, reject) => { |
| 27 | + targz.decompress( |
33 | 28 | {
|
34 |
| - url: remote, |
35 |
| - headers: { |
36 |
| - 'If-Modified-Since': stats.mtime.toUTCString() |
| 29 | + src: zipped, |
| 30 | + dest: config.dbDir, |
| 31 | + tar: { |
| 32 | + ignore: function(name) { |
| 33 | + return path.extname(name) !== ".mmdb"; |
| 34 | + } |
37 | 35 | }
|
38 | 36 | },
|
39 |
| - res => { |
40 |
| - if (res === null) { |
41 |
| - cb(null, true) |
| 37 | + err => { |
| 38 | + if (err) { |
| 39 | + debug(err); |
| 40 | + reject(); |
42 | 41 | } else {
|
43 |
| - cb(null, false) |
| 42 | + fs.readdirSync(config.dbDir).forEach(file => { |
| 43 | + if (fs.lstatSync(`${config.dbDir}/${file}`).isDirectory()) { |
| 44 | + fs.renameSync( |
| 45 | + `${config.dbDir}/${file}/${database.filename}.mmdb`, |
| 46 | + `${config.dbDir}/${database.filename}.mmdb` |
| 47 | + ); |
| 48 | + fs.rmdirSync(`${config.dbDir}/${file}`); |
| 49 | + } |
| 50 | + }); |
| 51 | + fs.unlinkSync(`${config.dbDir}/${database.filename}.tar.gz`); |
| 52 | + resolve(); |
44 | 53 | }
|
45 | 54 | }
|
46 |
| - ) |
47 |
| - } |
| 55 | + ); |
| 56 | + }); |
48 | 57 | }
|
49 | 58 |
|
50 | 59 | /**
|
51 |
| - * downloads file |
52 |
| - * @param {String} dest path for local file |
53 |
| - * @param {String} remote path for remote file |
54 |
| - * @param {Function} cb true/false |
| 60 | + * download database and unzip |
| 61 | + * |
| 62 | + * @param {Object} database database to download |
55 | 63 | */
|
56 |
| -function download (dest, remote, cb) { |
57 |
| - request |
58 |
| - .get(remote) |
59 |
| - .pipe(zlib.createGunzip()) |
60 |
| - .pipe(fs.createWriteStream(dest)) |
61 |
| - .on('error', error => { |
62 |
| - cb(error, false) |
63 |
| - }) |
64 |
| - .on('finish', () => { |
65 |
| - cb(null, true) |
66 |
| - }) |
| 64 | +async function download(database) { |
| 65 | + const zipped = `${config.dbDir}/${database.filename}.tar.gz`; |
| 66 | + const response = await fetch(database.remote); |
| 67 | + await streamPipeline(response.body, fs.createWriteStream(zipped)); |
| 68 | + debug("download complete, uncompressing"); |
| 69 | + await uncompress(zipped, database); |
| 70 | + debug("ready!"); |
67 | 71 | }
|
68 | 72 |
|
69 | 73 | /**
|
70 |
| - * runs downloads for all the files |
71 |
| - * @param {String} item which database |
72 |
| - * @param {Function} cb true/false |
| 74 | + * check if remote file is newer |
| 75 | + * |
| 76 | + * @param {Object} database database to download |
73 | 77 | */
|
74 |
| -function dl (item, cb) { |
75 |
| - const dest = config.dbDir + '/' + item.local |
| 78 | +async function isRemoteNewer(database) { |
| 79 | + const mmdb = `${config.dbDir}/${database.filename}.mmdb`; |
| 80 | + // if no file |
| 81 | + if (!fs.existsSync(mmdb)) { |
| 82 | + debug("file does not exist"); |
| 83 | + return true; |
| 84 | + } else { |
| 85 | + // if dest file is not a file, remove it |
| 86 | + const stats = fs.statSync(mmdb); |
| 87 | + if (!stats.isFile()) { |
| 88 | + debug(`${mmdb} is not a file`); |
| 89 | + fs.unlinkSync(mmdb, () => { |
| 90 | + debug(`${mmdb} deleted`); |
| 91 | + }); |
| 92 | + } |
76 | 93 |
|
77 |
| - isRemoteNewer(dest, item.remote, (err, newer) => { |
78 |
| - if (err) { |
79 |
| - cb(err, false) |
80 |
| - } else if (!err && newer) { |
81 |
| - cb(null, false) |
82 |
| - } else if (!err && !newer) { |
83 |
| - // begin downloading |
84 |
| - debug(`downloading ${dest}`) |
| 94 | + const response = await fetch(database.remote, { |
| 95 | + method: "GET", |
| 96 | + headers: { |
| 97 | + "If-Modified-Since": stats.mtime.toUTCString() |
| 98 | + } |
| 99 | + }); |
85 | 100 |
|
86 |
| - download(dest, item.remote, (err, done) => { |
87 |
| - if (err) { |
88 |
| - cb(err, false) |
89 |
| - } else if (!err && !done) { |
90 |
| - cb(null, false) |
91 |
| - } else if (!err && done) { |
92 |
| - cb(null, true) |
93 |
| - } |
94 |
| - }) |
| 101 | + if (response === null) { |
| 102 | + return true; |
95 | 103 | }
|
96 |
| - }) |
| 104 | + return false; |
| 105 | + } |
97 | 106 | }
|
98 | 107 |
|
99 | 108 | /**
|
100 |
| - * Runs a sync function to download the files |
101 |
| - * |
102 |
| - * @param {any} cb |
| 109 | + * sync databases to local |
103 | 110 | */
|
104 |
| -function sync (cb) { |
105 |
| - async.eachSeries(config.geoIpDbs, dl, err => { |
106 |
| - cb(err, true) |
107 |
| - }) |
| 111 | +function sync() { |
| 112 | + config.geoIpDbs.forEach(async database => { |
| 113 | + if (await isRemoteNewer(database)) { |
| 114 | + debug("remote is newer, downloading"); |
| 115 | + await download(database); |
| 116 | + } |
| 117 | + }); |
108 | 118 | }
|
109 | 119 |
|
110 |
| -async.eachSeries(config.geoIpDbs, dl, err => { |
111 |
| - if (err) { |
112 |
| - debug(`🚨 Error: ${err}`) |
113 |
| - } else { |
114 |
| - debug(`🚀 All set!`) |
115 |
| - } |
116 |
| -}) |
| 120 | +sync(); |
117 | 121 |
|
118 |
| -module.exports.sync = sync |
| 122 | +module.exports.sync = sync; |
0 commit comments