This commit is contained in:
parent
fa2be029a2
commit
724d70e58b
3339 changed files with 1075535 additions and 0 deletions
212
frontend/node_modules/tus-js-client/lib/node/httpStack.js
generated
vendored
Normal file
212
frontend/node_modules/tus-js-client/lib/node/httpStack.js
generated
vendored
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
// The url.parse method is superseeded by the url.URL constructor,
|
||||
// but it is still included in Node.js
|
||||
import * as http from 'http'
|
||||
import * as https from 'https'
|
||||
import { Readable, Transform } from 'stream'
|
||||
import { parse } from 'url'
|
||||
import throttle from 'lodash.throttle'
|
||||
|
||||
export default class NodeHttpStack {
|
||||
constructor(requestOptions = {}) {
|
||||
this._requestOptions = requestOptions
|
||||
}
|
||||
|
||||
createRequest(method, url) {
|
||||
return new Request(method, url, this._requestOptions)
|
||||
}
|
||||
|
||||
getName() {
|
||||
return 'NodeHttpStack'
|
||||
}
|
||||
}
|
||||
|
||||
class Request {
|
||||
constructor(method, url, options) {
|
||||
this._method = method
|
||||
this._url = url
|
||||
this._headers = {}
|
||||
this._request = null
|
||||
this._progressHandler = () => {}
|
||||
this._requestOptions = options || {}
|
||||
}
|
||||
|
||||
getMethod() {
|
||||
return this._method
|
||||
}
|
||||
|
||||
getURL() {
|
||||
return this._url
|
||||
}
|
||||
|
||||
setHeader(header, value) {
|
||||
this._headers[header] = value
|
||||
}
|
||||
|
||||
getHeader(header) {
|
||||
return this._headers[header]
|
||||
}
|
||||
|
||||
setProgressHandler(progressHandler) {
|
||||
this._progressHandler = progressHandler
|
||||
}
|
||||
|
||||
send(body = null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const options = {
|
||||
...parse(this._url),
|
||||
...this._requestOptions,
|
||||
|
||||
method: this._method,
|
||||
headers: {
|
||||
...(this._requestOptions.headers || {}),
|
||||
...this._headers,
|
||||
},
|
||||
}
|
||||
|
||||
if (body?.size) {
|
||||
options.headers['Content-Length'] = body.size
|
||||
}
|
||||
|
||||
const httpModule = options.protocol === 'https:' ? https : http
|
||||
this._request = httpModule.request(options)
|
||||
const req = this._request
|
||||
req.on('response', (res) => {
|
||||
const resChunks = []
|
||||
res.on('data', (data) => {
|
||||
resChunks.push(data)
|
||||
})
|
||||
|
||||
res.on('end', () => {
|
||||
const responseText = Buffer.concat(resChunks).toString('utf8')
|
||||
resolve(new Response(res, responseText))
|
||||
})
|
||||
})
|
||||
|
||||
req.on('error', (err) => {
|
||||
reject(err)
|
||||
})
|
||||
|
||||
if (body instanceof Readable) {
|
||||
// Readable stream are piped through a PassThrough instance, which
|
||||
// counts the number of bytes passed through. This is used, for example,
|
||||
// when an fs.ReadStream is provided to tus-js-client.
|
||||
body.pipe(new ProgressEmitter(this._progressHandler)).pipe(req)
|
||||
} else if (body instanceof Uint8Array) {
|
||||
// For Buffers and Uint8Arrays (in Node.js all buffers are instances of Uint8Array),
|
||||
// we write chunks of the buffer to the stream and use that to track the progress.
|
||||
// This is used when either a Buffer or a normal readable stream is provided
|
||||
// to tus-js-client.
|
||||
writeBufferToStreamWithProgress(req, body, this._progressHandler)
|
||||
} else {
|
||||
req.end(body)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
abort() {
|
||||
if (this._request !== null) this._request.abort()
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
getUnderlyingObject() {
|
||||
return this._request
|
||||
}
|
||||
}
|
||||
|
||||
class Response {
|
||||
constructor(res, body) {
|
||||
this._response = res
|
||||
this._body = body
|
||||
}
|
||||
|
||||
getStatus() {
|
||||
return this._response.statusCode
|
||||
}
|
||||
|
||||
getHeader(header) {
|
||||
return this._response.headers[header.toLowerCase()]
|
||||
}
|
||||
|
||||
getBody() {
|
||||
return this._body
|
||||
}
|
||||
|
||||
getUnderlyingObject() {
|
||||
return this._response
|
||||
}
|
||||
}
|
||||
|
||||
// ProgressEmitter is a simple PassThrough-style transform stream which keeps
|
||||
// track of the number of bytes which have been piped through it and will
|
||||
// invoke the `onprogress` function whenever new number are available.
|
||||
class ProgressEmitter extends Transform {
|
||||
constructor(onprogress) {
|
||||
super()
|
||||
|
||||
// The _onprogress property will be invoked, whenever a chunk is piped
|
||||
// through this transformer. Since chunks are usually quite small (64kb),
|
||||
// these calls can occur frequently, especially when you have a good
|
||||
// connection to the remote server. Therefore, we are throtteling them to
|
||||
// prevent accessive function calls.
|
||||
this._onprogress = throttle(onprogress, 100, {
|
||||
leading: true,
|
||||
trailing: false,
|
||||
})
|
||||
this._position = 0
|
||||
}
|
||||
|
||||
_transform(chunk, _encoding, callback) {
|
||||
this._position += chunk.length
|
||||
this._onprogress(this._position)
|
||||
callback(null, chunk)
|
||||
}
|
||||
}
|
||||
|
||||
// writeBufferToStreamWithProgress writes chunks from `source` (either a
|
||||
// Buffer or Uint8Array) to the readable stream `stream`.
|
||||
// The size of the chunk depends on the stream's highWaterMark to fill the
|
||||
// stream's internal buffer as best as possible.
|
||||
// If the internal buffer is full, the callback `onprogress` will be invoked
|
||||
// to notify about the write progress. Writing will be resumed once the internal
|
||||
// buffer is empty, as indicated by the emitted `drain` event.
|
||||
// See https://nodejs.org/docs/latest/api/stream.html#buffering for more details
|
||||
// on the buffering behavior of streams.
|
||||
const writeBufferToStreamWithProgress = (stream, source, onprogress) => {
|
||||
onprogress = throttle(onprogress, 100, {
|
||||
leading: true,
|
||||
trailing: false,
|
||||
})
|
||||
|
||||
let offset = 0
|
||||
|
||||
function writeNextChunk() {
|
||||
// Take at most the amount of bytes from highWaterMark. This should fill the streams
|
||||
// internal buffer already.
|
||||
const chunkSize = Math.min(stream.writableHighWaterMark, source.length - offset)
|
||||
|
||||
// Note: We use subarray instead of slice because it works without copying data for
|
||||
// Buffers and Uint8Arrays.
|
||||
const chunk = source.subarray(offset, offset + chunkSize)
|
||||
offset += chunk.length
|
||||
|
||||
// `write` returns true if the internal buffer is not full and we should write more.
|
||||
// If the stream is destroyed because the request is aborted, it will return false
|
||||
// and no 'drain' event is emitted, so won't continue writing data.
|
||||
const canContinue = stream.write(chunk)
|
||||
|
||||
if (!canContinue) {
|
||||
// If the buffer is full, wait for the 'drain' event to write more data.
|
||||
stream.once('drain', writeNextChunk)
|
||||
onprogress(offset)
|
||||
} else if (offset < source.length) {
|
||||
// If there's still data to write and the buffer is not full, write next chunk.
|
||||
writeNextChunk()
|
||||
} else {
|
||||
// If all data has been written, close the stream if needed, and emit a 'finish' event.
|
||||
stream.end()
|
||||
}
|
||||
}
|
||||
|
||||
// Start writing the first chunk.
|
||||
writeNextChunk()
|
||||
}
|
||||
Reference in a new issue