mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2024-12-01 22:03:46 +03:00
Tidy up TelegramBareClient.download_file CDN's mess
This commit is contained in:
parent
d5323c5506
commit
4384ccb132
|
@ -458,7 +458,6 @@ class TelegramBareClient:
|
||||||
takes two parameters, (bytes_downloaded, total_bytes). Note that
|
takes two parameters, (bytes_downloaded, total_bytes). Note that
|
||||||
'total_bytes' simply equals 'file_size', and may be None.
|
'total_bytes' simply equals 'file_size', and may be None.
|
||||||
"""
|
"""
|
||||||
# TODO Clean up the CDN mess below
|
|
||||||
if not part_size_kb:
|
if not part_size_kb:
|
||||||
if not file_size:
|
if not file_size:
|
||||||
part_size_kb = 64 # Reasonable default
|
part_size_kb = 64 # Reasonable default
|
||||||
|
@ -487,15 +486,18 @@ class TelegramBareClient:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
offset_index = 0
|
offset_index = 0
|
||||||
cdn_redirect = None
|
cdn_file_token = None
|
||||||
cdn_aes = None
|
|
||||||
|
def encrypt_method(x):
|
||||||
|
return x # Defaults to no-op
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
offset = offset_index * part_size
|
offset = offset_index * part_size
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if cdn_redirect:
|
if cdn_file_token:
|
||||||
result = client(GetCdnFileRequest(
|
result = client(GetCdnFileRequest(
|
||||||
cdn_redirect.file_token, offset, part_size
|
cdn_file_token, offset, part_size
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
result = client(GetFileRequest(
|
result = client(GetFileRequest(
|
||||||
|
@ -503,32 +505,13 @@ class TelegramBareClient:
|
||||||
))
|
))
|
||||||
|
|
||||||
if isinstance(result, FileCdnRedirect):
|
if isinstance(result, FileCdnRedirect):
|
||||||
# https://core.telegram.org/cdn
|
client, cdn_file_token, encrypt_method, result = \
|
||||||
cdn_redirect = result
|
self._prepare_cdn_redirect(
|
||||||
cdn_aes = pyaes.AESModeOfOperationCTR(
|
result, offset, part_size
|
||||||
result.encryption_key
|
|
||||||
)
|
|
||||||
# The returned IV is the counter used on CTR
|
|
||||||
cdn_aes._counter._counter = list(
|
|
||||||
result.encryption_iv[:12] +
|
|
||||||
(offset >> 4).to_bytes(4, 'big')
|
|
||||||
)
|
)
|
||||||
|
|
||||||
client, cdn_file = self._get_cdn_client(
|
if result is None:
|
||||||
result.dc_id,
|
# File was not ready on the CDN yet
|
||||||
GetCdnFileRequest(
|
|
||||||
cdn_redirect.file_token, offset, part_size
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if isinstance(cdn_file, CdnFileReuploadNeeded):
|
|
||||||
# We need to use the original client here
|
|
||||||
self(ReuploadCdnFileRequest(
|
|
||||||
file_token=cdn_redirect.file_token,
|
|
||||||
request_token=cdn_file.request_token
|
|
||||||
))
|
|
||||||
# TODO else: we have the first file bytes already,
|
|
||||||
# avoid a redundant call
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
except FileMigrateError as e:
|
except FileMigrateError as e:
|
||||||
|
@ -543,16 +526,42 @@ class TelegramBareClient:
|
||||||
# Return some extra information, unless it's a cdn file
|
# Return some extra information, unless it's a cdn file
|
||||||
return getattr(result, 'type', '')
|
return getattr(result, 'type', '')
|
||||||
|
|
||||||
if cdn_redirect:
|
f.write(encrypt_method(result.bytes))
|
||||||
# We first need to decrypt the result
|
|
||||||
# TODO Use libssl if available
|
|
||||||
result.bytes = cdn_aes.encrypt(result.bytes)
|
|
||||||
|
|
||||||
f.write(result.bytes)
|
|
||||||
if progress_callback:
|
if progress_callback:
|
||||||
progress_callback(f.tell(), file_size)
|
progress_callback(f.tell(), file_size)
|
||||||
finally:
|
finally:
|
||||||
if isinstance(file, str):
|
if isinstance(file, str):
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
def _prepare_cdn_redirect(self, cdn_redirect, offset, part_size):
|
||||||
|
"""Returns (client, cdn_file_token, encrypt_method, result)"""
|
||||||
|
# https://core.telegram.org/cdn
|
||||||
|
# TODO Use libssl if available
|
||||||
|
cdn_aes = pyaes.AESModeOfOperationCTR(
|
||||||
|
cdn_redirect.encryption_key
|
||||||
|
)
|
||||||
|
# The returned IV is the counter used on CTR
|
||||||
|
cdn_aes._counter._counter = list(
|
||||||
|
cdn_redirect.encryption_iv[:12] +
|
||||||
|
(offset >> 4).to_bytes(4, 'big')
|
||||||
|
)
|
||||||
|
|
||||||
|
client, cdn_file = self._get_cdn_client(
|
||||||
|
cdn_redirect.dc_id,
|
||||||
|
GetCdnFileRequest(
|
||||||
|
cdn_redirect.file_token, offset, part_size
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if isinstance(cdn_file, CdnFileReuploadNeeded):
|
||||||
|
# We need to use the original client here
|
||||||
|
self(ReuploadCdnFileRequest(
|
||||||
|
file_token=cdn_redirect.file_token,
|
||||||
|
request_token=cdn_file.request_token
|
||||||
|
))
|
||||||
|
return client, cdn_redirect.file_token, cdn_aes.encrypt, None
|
||||||
|
else:
|
||||||
|
# We have the first bytes for the file
|
||||||
|
return client, cdn_redirect.file_token, cdn_aes.encrypt, cdn_file
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
|
@ -39,6 +39,10 @@ class HigherLevelTests(unittest.TestCase):
|
||||||
client.download_media(msg, out)
|
client.download_media(msg, out)
|
||||||
assert sha256(data).digest() == sha256(out.getvalue()).digest()
|
assert sha256(data).digest() == sha256(out.getvalue()).digest()
|
||||||
|
|
||||||
|
out = BytesIO()
|
||||||
|
client.download_media(msg, out) # Won't redirect
|
||||||
|
assert sha256(data).digest() == sha256(out.getvalue()).digest()
|
||||||
|
|
||||||
client.log_out()
|
client.log_out()
|
||||||
finally:
|
finally:
|
||||||
client.disconnect()
|
client.disconnect()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user