Telegram Desktop File Download Upload Manager Architecture Explained
Telegram Desktop separates file transfers into two dedicated subsystems—Storage::Uploader for uploads and Storage::DownloadManagerMtproto for downloads—both operating over MTProto with per-DC session pools, priority queues, and reactive progress streams.
The telegramdesktop/tdesktop repository implements a highly concurrent file transfer system that handles millions of daily uploads and downloads. This architecture lives inside each Main::Session and provides automatic load balancing, CDN support, and seamless integration with the app's reactive UI framework.
Architecture Overview
The system maintains separate pipelines for upload and download operations, each optimized for their specific direction of data flow.
| Aspect | Upload Pipeline | Download Pipeline |
|---|---|---|
| Entry Point | session->uploader() returns a Storage::Uploader object |
session->downloader() returns a Storage::DownloadManagerMtproto object |
| Task Representation | Uploader::Entry stores parts, progress counters, and MD5 state |
DownloadMtprotoTask (derived from FileLoader) manages per-file state |
| Queue Strategy | Single FIFO queue (std::vector<Entry> _queue) |
Per-DC priority queue (DownloadManagerMtproto::Queue) |
| Session Management | Dynamic pool of upload sessions with byte budgets (kMaxUploadPerSession) |
Fixed pool per DC (up to kMaxSessionsCount) with balance tracking (DcBalanceData) |
| Part Size | Variable based on file size (kDocumentUploadPartSize0…4), supports big files |
Fixed at kDownloadPartSize = 128 KB as defined in storage/file_download.h |
| Premium Limits | Emits nonPremiumDelays() for slow-upload UI prompts |
Emits nonPremiumDelays() for download-speed-up UI prompts |
Upload Pipeline Deep Dive
Entry Point and Task Representation
Uploads begin when the client calls session->uploader().upload(fullMsgId, filePrepareResult) as implemented in Telegram/SourceFiles/storage/file_upload.cpp (lines 291-312). The Uploader creates an internal Entry structure (lines 73-84) that tracks:
- The prepared file data and MIME type
- Part boundaries and MD5 computation state
- Progress counters for emission to the UI
// From file_upload.cpp - Entry creation
session->uploader().upload(uploadId, file);
Queue Management and Session Handling
The Uploader maintains a single FIFO queue processed by Uploader::maybeSend(). This method dynamically manages a pool of DC indices through chooseDcIndexForNextRequest and removeDcIndex (lines 15-30 in file_upload.cpp).
Each session operates under a byte budget defined by kMaxUploadPerSession. When a DC index is selected, sendPart() assembles either a sliced part request (for photos/thumbnails) or a document part request, constructing the appropriate MTProto call:
MTPupload_SaveFilePartfor standard filesMTPupload_SaveBigFilePartfor large files exceeding the standard part thresholds
Progress and Completion
When the server responds, Uploader::partLoaded() updates progress counters, modifies Data::UploadState in the model, and fires events through rpl::event_stream (_photoProgress, _documentProgress). Upon completion of all parts (maybeFinishFront() → finishFront()), the system emits an UploadedMedia struct via _photoReady or _documentReady, triggering the final API call (api()->sendUploadedPhoto or api()->sendUploadedDocument).
Download Pipeline Deep Dive
Task Initialization and Queue Registration
Downloads utilize mtpFileLoader, a subclass of both FileLoader and DownloadMtprotoTask. Instantiation follows this pattern as shown in Telegram/SourceFiles/storage/file_download_mtproto.cpp:
auto loader = std::make_unique<mtpFileLoader>(
session,
StorageFileLocation{ fileId, accessHash, dcId, … },
Data::FileOrigin::FromMessage(messageId),
QString(), // write-to-file path (empty = memory only)
/*loadSize=*/0, // 0 → full size
/*fullSize=*/0,
LocationType::Unknown,
LoadToCacheAsWell,
LoadFromCloud::Yes,
/*autoLoading=*/true,
/*cacheTag=*/Data::kDocumentCacheTag);
Calling FileLoader::startLoading() invokes DownloadMtprotoTask::addToQueue(), registering the task with DownloadManagerMtproto (lines 38-45 in download_manager_mtproto.cpp).
Per-DC Session Balancing
Unlike uploads, downloads use a per-DC priority queue system. DownloadManagerMtproto::checkSendNext() iterates through each DC's Queue, selecting the highest-priority ready task and invoking task->loadPart(sessionIndex) (lines 78-80).
The manager maintains DcBalanceData structures that track:
- Requested bytes per session
- Success/failure ratios
- Timeout events (
sessionTimedOut)
Sessions are automatically added or removed based on load via changeRequestedAmount and requestSucceeded.
CDN Support and Error Handling
When a download encounters a CDN redirect (MTPupload_fileCdnRedirect), DownloadMtprotoTask::switchToCDN (lines 78-88 in download_manager_mtproto.cpp) transitions the task to CDN parameters. This flow re-uploads pending parts, validates per-chunk SHA-256 hashes, and retries missing parts automatically.
Progress updates emit through FileLoader::updates(), while failures trigger cancelOnFail(). When a task completes, it calls removeFromQueue() and the manager emits taskFinished() for UI consumption.
Integration with the Main Session and UI
Both subsystems are owned by the main session as shown in Telegram/SourceFiles/main/main_session.cpp:
_downloader(std::make_unique<Storage::DownloadManagerMtproto>(_api.get())),
_uploader(/* inside Main::Session via ApiWrap */)
UI components subscribe to reactive streams for real-time updates:
- Upload progress:
session->uploader().documentReady(),session->uploader().photoReady(), andsession->uploader().nonPremiumDelays() - Download progress:
session->downloaderTaskFinished()and per-loaderFileLoader::updates()
The Upload Progress Overlay and Download Bar components in Telegram/SourceFiles/ui/effects/upload_progress_overlay.cpp and related files consume these streams to render progress indicators.
Practical Code Examples
Uploading a Photo
FullMsgId uploadId = { peer, localMessageId };
auto file = FilePrepareResult::CreatePhoto(
QByteArray::fromRawData(imageData, imageSize),
"photo.jpg",
mimeType,
options);
session->uploader().upload(uploadId, file);
Downloading with Progress Tracking
auto loader = std::make_unique<mtpFileLoader>(
session,
StorageFileLocation{ fileId, accessHash, dcId },
Data::FileOrigin::FromMessage(messageId),
QString(), 0, 0, LocationType::Unknown,
LoadToCacheAsWell, LoadFromCloud::Yes, true,
Data::kDocumentCacheTag);
loader->updates() | rpl::start_with_next([=](auto &&) {
qDebug() << "Progress:" << loader->currentProgress();
});
loader->start();
Global Download Completion Handler
session->downloaderTaskFinished()
| rpl::start_with_next([=] {
ui->downloadBar->hide();
});
Summary
- Dual-subsystem design: Telegram Desktop uses
Storage::Uploaderfor uploads andStorage::DownloadManagerMtprotofor downloads, both residing inMain::Session. - Dynamic session pools: Uploads manage a flexible pool with byte budgets per DC, while downloads use fixed pools with automatic balancing based on success rates and timeouts.
- Queue strategies: Uploads use a single FIFO queue; downloads implement per-DC priority queues for optimal bandwidth utilization.
- CDN integration: The download pipeline fully supports CDN redirects with automatic hash validation and retry logic.
- Reactive UI binding: Both systems expose
rpl::event_streaminterfaces (documentReady(),downloaderTaskFinished()) for real-time progress updates and premium limit notifications.
Frequently Asked Questions
What file size limits trigger big file uploads in Telegram Desktop?
Large files activate the big file upload path when they exceed the thresholds defined in kDocumentUploadPartSize0 through kDocumentUploadPartSize4 constants in storage/file_upload.cpp. When this occurs, the uploader switches from MTPupload_SaveFilePart to MTPupload_SaveBigFilePart and represents the file as MTP_inputFileBig rather than MTP_inputFile.
How does Telegram Desktop handle slow network conditions during downloads?
The DownloadManagerMtproto monitors each session's performance through DcBalanceData structures that track requested bytes, successful completions, and timeout events. When sessionTimedOut() fires or success rates drop, changeRequestedAmount() automatically redistributes load across available sessions. For non-premium users hitting speed limits, the system emits nonPremiumDelays() signals to trigger UI prompts for speed upgrades.
What is the fixed download part size in Telegram Desktop?
According to storage/file_download.h, Telegram Desktop uses a fixed 128 KB (kDownloadPartSize = 128 * 1024) part size for all downloads, regardless of file type or size. This differs from uploads, which use variable part sizes based on total file dimensions.
Can uploads and downloads operate simultaneously without blocking?
Yes. Because the architectures are separate subsystems owning independent session pools and queues, uploads via Storage::Uploader and downloads via Storage::DownloadManagerMtproto execute concurrently. The per-DC session limits (kMaxUploadPerSession for uploads, kMaxSessionsCount for downloads) ensure that file transfers in one direction do not starve the other of network resources.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →