@kmamal/sdl
Version:
SDL bindings for Node.js
86 lines (72 loc) • 1.69 kB
JavaScript
const _consume = async (stream) => {
const chunks = []
for await (const chunk of stream) {
chunks.push(chunk)
}
return Buffer.concat(chunks)
}
const fetch = async (_url, options = {}) => {
let url = _url
let {
maxRedirect = 5,
body = null,
} = options
const { protocol } = new URL(url)
const lib = require(protocol.slice(0, -1))
const evalPromise = (resolve, reject) => {
const request = lib.request(url, options)
.on('error', reject)
.on('response', resolve)
if (!body) {
request.end()
return
}
if (body?.length) {
if (!Buffer.isBuffer(body)) { body = Buffer.from(body) }
body = Promise.resolve(body)
}
else {
body = _consume(body)
}
body.then((buffer) => {
request.setHeader('Content-Length', buffer.length)
request.end(buffer)
})
}
for (;;) {
const response = await new Promise(evalPromise)
const { statusCode } = response
if (300 <= statusCode && statusCode < 400) {
if (maxRedirect-- > 0) {
url = response.headers.location
continue
}
}
if (!(200 <= statusCode && statusCode < 300)) {
let responseBody
try { responseBody = (await _consume(response)).toString() }
catch (_) {}
try { responseBody = JSON.parse(responseBody) }
catch (_) {}
throw Object.assign(new Error(`bad status code ${statusCode}`), {
statusCode,
responseBody,
})
}
return {
stream () { return response },
async buffer () {
return await _consume(response)
},
async text () {
const buffer = await this.buffer()
return buffer.toString()
},
async json () {
const text = await this.text()
return JSON.parse(text)
},
}
}
}
module.exports = { fetch }