MCPcopy
hub / github.com/electerm/electerm / httpDownload

Function httpDownload

npm/utils.js:53–111  ·  view source on GitHub ↗

* Make an HTTP GET request and download to a file with progress * @param {string} url - URL to fetch * @param {string} filepath - Destination file path * @param {number} timeout - Request timeout in milliseconds (default: 300000 = 5min) * @param {function} onProgress - Progress callback (receive

(url, filepath, timeout = 300000, onProgress)

Source from the content-addressed store, hash-verified

51 * @returns {Promise<string>} Path to downloaded file
52 */
53function httpDownload (url, filepath, timeout = 300000, onProgress) {
54 return new Promise((resolve, reject) => {
55 const client = url.startsWith('https') ? https : http
56
57 const req = client.get(url, { timeout }, (res) => {
58 // Handle redirects
59 if (res.statusCode === 301 || res.statusCode === 302 || res.statusCode === 307) {
60 if (res.headers.location) {
61 // Handle relative URLs
62 let redirectUrl = res.headers.location
63 if (!redirectUrl.startsWith('http://') && !redirectUrl.startsWith('https://')) {
64 const parsedUrl = new URL(url)
65 redirectUrl = `${parsedUrl.protocol}//${parsedUrl.host}${redirectUrl}`
66 }
67 resolve(httpDownload(redirectUrl, filepath, timeout, onProgress))
68 return
69 }
70 }
71
72 if (res.statusCode !== 200) {
73 reject(new Error(`HTTP ${res.statusCode}: ${res.statusMessage || 'Unknown error'}`))
74 return
75 }
76
77 const total = parseInt(res.headers['content-length'] || '0', 10)
78 let received = 0
79 let lastPercent = -1
80
81 const fileStream = fs.createWriteStream(filepath)
82
83 res.on('data', (chunk) => {
84 received += chunk.length
85 if (onProgress && total > 0) {
86 const percent = Math.round((received / total) * 100)
87 if (percent !== lastPercent) {
88 lastPercent = percent
89 onProgress(received, total, percent)
90 }
91 }
92 })
93
94 res.pipe(fileStream)
95 fileStream.on('finish', () => {
96 fileStream.close()
97 resolve(filepath)
98 })
99 fileStream.on('error', (err) => {
100 fs.unlink(filepath, () => {}) // Clean up partial download
101 reject(err)
102 })
103 })
104
105 req.on('error', reject)
106 req.on('timeout', () => {
107 req.destroy()
108 reject(new Error(`Request timeout after ${timeout}ms`))
109 })
110 })

Callers 1

downloadFunction · 0.85

Calls 5

resolveFunction · 0.85
getMethod · 0.45
onMethod · 0.45
closeMethod · 0.45
destroyMethod · 0.45

Tested by

no test coverage detected