diff --git a/packages/client/src/methods/files/download-iterable.ts b/packages/client/src/methods/files/download-iterable.ts index c1f3b18f..fcfcc34a 100644 --- a/packages/client/src/methods/files/download-iterable.ts +++ b/packages/client/src/methods/files/download-iterable.ts @@ -32,6 +32,9 @@ export async function* downloadAsIterable( let dcId = params?.dcId let fileSize = params?.fileSize + const abortSignal = params?.abortSignal + let aborted = false + let location: tl.TypeInputFileLocation | tl.TypeInputWebFileLocation if (input instanceof FileLocation) { let locationInner = input.location @@ -102,6 +105,10 @@ export async function* downloadAsIterable( const downloadChunk = async (chunk = nextWorkerChunkIdx++): Promise => { let result: tl.RpcCallReturn['upload.getFile'] | tl.RpcCallReturn['upload.getWebFile'] + if (aborted) { + return + } + try { result = await client.call( { @@ -111,9 +118,15 @@ export async function* downloadAsIterable( offset: chunkSize * chunk, limit: chunkSize, }, - { dcId, kind: connectionKind, abortSignal: params?.abortSignal }, + { + dcId, + kind: connectionKind, + maxRetryCount: Infinity, // retry until explicitly aborted (or finished) + abortSignal, + }, ) } catch (e: unknown) { + if (e instanceof DOMException && e.name === 'AbortError') return if (!tl.RpcError.is(e)) throw e 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)') } + if (aborted) { + return + } + if (result._ === 'upload.webFile' && result.size && limitBytes === Infinity) { limitBytes = result.size numChunks = ~~((limitBytes + chunkSize - offset - 1) / chunkSize) @@ -155,12 +172,22 @@ export async function* downloadAsIterable( .catch((e) => { client.log.debug('download workers errored: %s', e.message) error = e + aborted = true // not really aborted, but we dont want to download more chunks nextChunkCv.notify() }) .then(() => { 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 while (position < limitBytes) {