EASYAIuniappNewUI/node_modules/centra/model/CentraRequest.js
2025-02-08 18:50:38 +08:00

221 lines
4.8 KiB
JavaScript

const path = require('path')
const http = require('http')
const https = require('https')
const followRedirects = require('follow-redirects')
const qs = require('querystring')
const zlib = require('zlib')
const {URL} = require('url')
const CentraResponse = require('./CentraResponse.js')
const supportedCompressions = ['gzip', 'deflate', 'br']
const useRequest = (protocol, maxRedirects) => {
let httpr
let httpsr
if (maxRedirects <= 0) {
httpr = http.request
httpsr = https.request
}
else {
httpr = followRedirects.http.request
httpsr = followRedirects.https.request
}
if (protocol === 'http:') {
return httpr
}
else if (protocol === 'https:') {
return httpsr
}
else throw new Error('Bad URL protocol: ' + protocol)
}
module.exports = class CentraRequest {
constructor (url, method = 'GET') {
this.url = typeof url === 'string' ? new URL(url) : url
this.method = method
this.data = null
this.sendDataAs = null
this.reqHeaders = {}
this.streamEnabled = false
this.compressionEnabled = false
this.timeoutTime = null
this.coreOptions = {}
this.maxRedirects = 0
this.resOptions = {
'maxBuffer': 50 * 1000000 // 50 MB
}
return this
}
followRedirects(n) {
this.maxRedirects = n
return this
}
query (a1, a2) {
if (typeof a1 === 'object') {
Object.keys(a1).forEach((queryKey) => {
this.url.searchParams.append(queryKey, a1[queryKey])
})
}
else this.url.searchParams.append(a1, a2)
return this
}
path (relativePath) {
this.url.pathname = path.join(this.url.pathname, relativePath)
return this
}
body (data, sendAs) {
this.sendDataAs = typeof data === 'object' && !sendAs && !Buffer.isBuffer(data) ? 'json' : (sendAs ? sendAs.toLowerCase() : 'buffer')
this.data = this.sendDataAs === 'form' ? qs.stringify(data) : (this.sendDataAs === 'json' ? JSON.stringify(data) : data)
return this
}
header (a1, a2) {
if (typeof a1 === 'object') {
Object.keys(a1).forEach((headerName) => {
this.reqHeaders[headerName.toLowerCase()] = a1[headerName]
})
}
else this.reqHeaders[a1.toLowerCase()] = a2
return this
}
timeout (timeout) {
this.timeoutTime = timeout
return this
}
option (name, value) {
this.coreOptions[name] = value
return this
}
stream () {
this.streamEnabled = true
return this
}
compress () {
this.compressionEnabled = true
if (!this.reqHeaders['accept-encoding']) this.reqHeaders['accept-encoding'] = supportedCompressions.join(', ')
return this
}
send () {
return new Promise((resolve, reject) => {
if (this.data) {
if (!this.reqHeaders.hasOwnProperty('content-type')) {
if (this.sendDataAs === 'json') {
this.reqHeaders['content-type'] = 'application/json'
}
else if (this.sendDataAs === 'form') {
this.reqHeaders['content-type'] = 'application/x-www-form-urlencoded'
}
}
if (!this.reqHeaders.hasOwnProperty('content-length')) {
this.reqHeaders['content-length'] = Buffer.byteLength(this.data)
}
}
const options = Object.assign({
'protocol': this.url.protocol,
'host': this.url.hostname.replace('[', '').replace(']', ''),
'port': this.url.port,
'path': this.url.pathname + (this.url.search === null ? '' : this.url.search),
'method': this.method,
'headers': this.reqHeaders,
'maxRedirects': this.maxRedirects
}, this.coreOptions)
let req
const resHandler = (res) => {
let stream = res
if (this.compressionEnabled) {
if (res.headers['content-encoding'] === 'gzip') {
stream = res.pipe(zlib.createGunzip())
}
else if (res.headers['content-encoding'] === 'deflate') {
stream = res.pipe(zlib.createInflate())
}
else if (res.headers['content-encoding'] === 'br') {
stream = res.pipe(zlib.createBrotliDecompress())
}
}
let centraRes
if (this.streamEnabled) {
resolve(stream)
}
else {
centraRes = new CentraResponse(res, this.resOptions)
stream.on('error', (err) => {
reject(err)
})
stream.on('aborted', () => {
reject(new Error('Server aborted request'))
})
stream.on('data', (chunk) => {
centraRes._addChunk(chunk)
if (this.resOptions.maxBuffer !== null && centraRes.body.length > this.resOptions.maxBuffer) {
stream.destroy()
reject('Received a response which was longer than acceptable when buffering. (' + this.body.length + ' bytes)')
}
})
stream.on('end', () => {
resolve(centraRes)
})
}
}
const request = useRequest(this.url.protocol, this.maxRedirects)
req = request(options, resHandler)
if (this.timeoutTime) {
req.setTimeout(this.timeoutTime, () => {
req.abort()
if (!this.streamEnabled) {
reject(new Error('Timeout reached'))
}
})
}
req.on('error', (err) => {
reject(err)
})
if (this.data) req.write(this.data)
req.end()
})
}
}