| 38 | return { oldRev, newRev, alreadyUpToDate, commits, files }; |
| 39 | } |
| 40 | function downloadFile(url, dest, visited = new Set()) { |
| 41 | return new Promise((resolve, reject) => { |
| 42 | try { |
| 43 | if (visited.has(url) || visited.size > 5) { |
| 44 | return reject(new Error('Too many redirects')); |
| 45 | } |
| 46 | visited.add(url); |
| 47 | const useHttps = url.startsWith('https://'); |
| 48 | const http = require('http'); |
| 49 | const client = useHttps ? https : http; |
| 50 | const req = client.get(url, { |
| 51 | headers: { |
| 52 | 'User-Agent': 'MegaBot-Updater/1.0', |
| 53 | 'Accept': '*/*' |
| 54 | } |
| 55 | }, (res) => { |
| 56 | if ([301, 302, 303, 307, 308].includes(res.statusCode)) { |
| 57 | const location = res.headers.location; |
| 58 | if (!location) |
| 59 | return reject(new Error(`HTTP ${res.statusCode} without Location`)); |
| 60 | const nextUrl = new URL(location, url).toString(); |
| 61 | res.resume(); |
| 62 | return downloadFile(nextUrl, dest, visited).then(resolve).catch(reject); |
| 63 | } |
| 64 | if (res.statusCode !== 200) { |
| 65 | return reject(new Error(`HTTP ${res.statusCode}`)); |
| 66 | } |
| 67 | const file = fs.createWriteStream(dest); |
| 68 | res.pipe(file); |
| 69 | file.on('finish', () => file.close(resolve)); |
| 70 | file.on('error', (err) => { |
| 71 | try { |
| 72 | file.close(() => { }); |
| 73 | } |
| 74 | catch { } |
| 75 | fs.unlink(dest, () => reject(err)); |
| 76 | }); |
| 77 | }); |
| 78 | req.on('error', (err) => { |
| 79 | fs.unlink(dest, () => reject(err)); |
| 80 | }); |
| 81 | } |
| 82 | catch (e) { |
| 83 | reject(e); |
| 84 | } |
| 85 | }); |
| 86 | } |
| 87 | async function extractZip(zipPath, outDir) { |
| 88 | if (process.platform === 'win32') { |
| 89 | const cmd = `powershell -NoProfile -Command "Expand-Archive -Path '${zipPath}' -DestinationPath '${outDir.replace(/\\/g, '/')}' -Force"`; |