fix(client): file download cancellation issues
This commit is contained in:
parent
3eaceedb8b
commit
391049b86f
1 changed files with 28 additions and 1 deletions
|
@ -32,6 +32,9 @@ export async function* downloadAsIterable(
|
||||||
let dcId = params?.dcId
|
let dcId = params?.dcId
|
||||||
let fileSize = params?.fileSize
|
let fileSize = params?.fileSize
|
||||||
|
|
||||||
|
const abortSignal = params?.abortSignal
|
||||||
|
let aborted = false
|
||||||
|
|
||||||
let location: tl.TypeInputFileLocation | tl.TypeInputWebFileLocation
|
let location: tl.TypeInputFileLocation | tl.TypeInputWebFileLocation
|
||||||
if (input instanceof FileLocation) {
|
if (input instanceof FileLocation) {
|
||||||
let locationInner = input.location
|
let locationInner = input.location
|
||||||
|
@ -102,6 +105,10 @@ export async function* downloadAsIterable(
|
||||||
const downloadChunk = async (chunk = nextWorkerChunkIdx++): Promise<void> => {
|
const downloadChunk = async (chunk = nextWorkerChunkIdx++): Promise<void> => {
|
||||||
let result: tl.RpcCallReturn['upload.getFile'] | tl.RpcCallReturn['upload.getWebFile']
|
let result: tl.RpcCallReturn['upload.getFile'] | tl.RpcCallReturn['upload.getWebFile']
|
||||||
|
|
||||||
|
if (aborted) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result = await client.call(
|
result = await client.call(
|
||||||
{
|
{
|
||||||
|
@ -111,9 +118,15 @@ export async function* downloadAsIterable(
|
||||||
offset: chunkSize * chunk,
|
offset: chunkSize * chunk,
|
||||||
limit: chunkSize,
|
limit: chunkSize,
|
||||||
},
|
},
|
||||||
{ dcId, kind: connectionKind, abortSignal: params?.abortSignal },
|
{
|
||||||
|
dcId,
|
||||||
|
kind: connectionKind,
|
||||||
|
maxRetryCount: Infinity, // retry until explicitly aborted (or finished)
|
||||||
|
abortSignal,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
|
if (e instanceof DOMException && e.name === 'AbortError') return
|
||||||
if (!tl.RpcError.is(e)) throw e
|
if (!tl.RpcError.is(e)) throw e
|
||||||
|
|
||||||
if (e.is('FILE_MIGRATE_%d')) {
|
if (e.is('FILE_MIGRATE_%d')) {
|
||||||
|
@ -134,6 +147,10 @@ export async function* downloadAsIterable(
|
||||||
throw new MtUnsupportedError('Received CDN redirect, which is not supported (yet)')
|
throw new MtUnsupportedError('Received CDN redirect, which is not supported (yet)')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aborted) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (result._ === 'upload.webFile' && result.size && limitBytes === Infinity) {
|
if (result._ === 'upload.webFile' && result.size && limitBytes === Infinity) {
|
||||||
limitBytes = result.size
|
limitBytes = result.size
|
||||||
numChunks = ~~((limitBytes + chunkSize - offset - 1) / chunkSize)
|
numChunks = ~~((limitBytes + chunkSize - offset - 1) / chunkSize)
|
||||||
|
@ -155,12 +172,22 @@ export async function* downloadAsIterable(
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
client.log.debug('download workers errored: %s', e.message)
|
client.log.debug('download workers errored: %s', e.message)
|
||||||
error = e
|
error = e
|
||||||
|
aborted = true // not really aborted, but we dont want to download more chunks
|
||||||
nextChunkCv.notify()
|
nextChunkCv.notify()
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
client.log.debug('download workers finished')
|
client.log.debug('download workers finished')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// to avoid MaxListenersExceededWarning we do this instead
|
||||||
|
// already sent requests can go to hell (they will get ignored)
|
||||||
|
abortSignal?.addEventListener('abort', () => {
|
||||||
|
client.log.debug('download aborted')
|
||||||
|
error = abortSignal.reason
|
||||||
|
aborted = true
|
||||||
|
nextChunkCv.notify()
|
||||||
|
})
|
||||||
|
|
||||||
let position = offset
|
let position = offset
|
||||||
|
|
||||||
while (position < limitBytes) {
|
while (position < limitBytes) {
|
||||||
|
|
Loading…
Reference in a new issue