Skip to content

TDLib Integration

QenTerra edited this page Jul 29, 2026 · 1 revision

TDLib Integration

Unspool uses TDLib's JSON interface through a small C++ framework. There is no Python, Telethon, or separate background runtime in the shipping application.

Bridge boundary

TDLibBridge exposes creation, send, receive, execute, and destruction around TDLib's td_json_client API. The Swift target links the locally generated TDLib.xcframework plus platform C++, zlib, SQLite, and Security components.

TDLibReceiveLoop owns the blocking receive call outside Swift actor cooperative execution. It forwards envelopes to TDLibClient while retaining receive order.

Ordered client

TDLibClient is an actor responsible for:

  • assigning a unique string @extra correlation ID to every request;
  • retaining pending continuations by that ID;
  • matching responses even when they arrive out of request order;
  • publishing unsolicited updates in receive order;
  • decoding TDLib error envelopes as typed TDLibError.remote;
  • removing a pending continuation when its task is cancelled;
  • completing shutdown only after authorization reaches closed state;
  • redacting sensitive fields from diagnostics.

Telegram's 64-bit identifiers can exceed JavaScript's exact integer range. Envelope decoding supports string-encoded identifiers so chat and message IDs retain exact precision.

Session configuration

TelegramSessionController configures TDLib with:

  • API ID and API hash;
  • sandboxed database and files directories;
  • file, chat-info, and message databases enabled;
  • secret chats enabled;
  • system language, model, OS, and application version metadata.

TDLib state lives under Application Support:

Unspool/TDLib/database
Unspool/TDLib/files

The session controller converts authorization and connection updates into typed events consumed by AppModel.

Authorization

Typed commands cover:

  • phone number;
  • email address;
  • email code;
  • login code;
  • registration;
  • two-step verification password.

Other-device confirmation is presented as a link state. Unknown future TDLib authorization states become an explicit unsupported state instead of being silently interpreted as ready.

Chats

The initial ready state triggers main and archive loading. TDLibChatPageLoader asks TDLib for list pages, while update mapping normalizes chat records and position changes into ChatRepository.

The repository publishes AsyncStream<ChatSnapshot> values. Cached summaries appear first; Telegram updates then replace or reorder them.

Message history and attachments

getChatHistory requests set only_local to false, allowing TDLib to fetch from Telegram. TDLibAttachmentMapper decodes supported message content, extracts the file object, preserves filename provenance, and emits a normalized attachment identity.

The history scanner owns pagination rules; the mapper owns content decoding. This separation lets pagination tests use synthetic pages without a live account.

File transfer

Workers call TDLib downloadFile with:

  • priority 32;
  • offset 0;
  • limit 0;
  • synchronous completion requested.

Cancellation sends cancelDownloadFile for each active file ID. The local TDLib cache path is never treated as the final user destination; it is validated and copied through DestinationAccess.

Clone this wiki locally