# Telegram Desktop File Download Upload Manager Architecture Explained

> Explore the Telegram Desktop file download upload manager architecture. Learn how Storage Uploader and DownloadManagerMtproto utilize MTProto, session pools, and queues for efficient transfers.

- Repository: [Telegram Desktop/tdesktop](https://github.com/telegramdesktop/tdesktop)
- Tags: architecture
- Published: 2026-04-05

---

**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`](https://github.com/telegramdesktop/tdesktop/blob/main/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`](https://github.com/telegramdesktop/tdesktop/blob/main/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

```cpp
// 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`](https://github.com/telegramdesktop/tdesktop/blob/main/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_SaveFilePart` for standard files
- `MTPupload_SaveBigFilePart` for 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`](https://github.com/telegramdesktop/tdesktop/blob/main/Telegram/SourceFiles/storage/file_download_mtproto.cpp):

```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`](https://github.com/telegramdesktop/tdesktop/blob/main/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`](https://github.com/telegramdesktop/tdesktop/blob/main/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`](https://github.com/telegramdesktop/tdesktop/blob/main/Telegram/SourceFiles/main/main_session.cpp):

```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()`, and `session->uploader().nonPremiumDelays()`
- Download progress: `session->downloaderTaskFinished()` and per-loader `FileLoader::updates()`

The `Upload Progress Overlay` and `Download Bar` components in [`Telegram/SourceFiles/ui/effects/upload_progress_overlay.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/Telegram/SourceFiles/ui/effects/upload_progress_overlay.cpp) and related files consume these streams to render progress indicators.

## Practical Code Examples

### Uploading a Photo

```cpp
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

```cpp
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

```cpp
session->downloaderTaskFinished()
    | rpl::start_with_next([=] {
        ui->downloadBar->hide();
    });

```

## Summary

- **Dual-subsystem design**: Telegram Desktop uses `Storage::Uploader` for uploads and `Storage::DownloadManagerMtproto` for downloads, both residing in `Main::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_stream` interfaces (`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`](https://github.com/telegramdesktop/tdesktop/blob/main/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`](https://github.com/telegramdesktop/tdesktop/blob/main/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.