gotd v0.165.0: on the wire like Telegram Desktop
· 4 min read
gotd v0.165.0 changes how gotd talks to Telegram where it matters: fewer bytes per request, Telegram Desktop's ping rhythm, no requests the official clients never send, and server sessions and keys that survive reconnects and restarts. A local clock that is minutes off no longer breaks the client.
How we found the differences
We recorded Telegram Desktop and gotd doing the same things on the same account (start, open a chat, send, scroll, download, sit idle) with wire traces and diffed them step by step. Most differences were app traffic: a full UI client asks for stickers, emoji and previews. The protocol ones became this release. A few numbers from the same scenarios before and after:
| gotd v0.164 | gotd v0.165 | Telegram Desktop | |
|---|---|---|---|
invokeWithLayer | on every request (9–32 per run) | only until the connection is inited | only until the connection is inited |
| Pings | ping_delay_disconnect(75) every 60 s | (60) every 30–45 s | (60) every ~35 s |
Differences in a 5-minute idle (getDifference / getChannelDifference) | 7 / 10 | 3 / 3 | 0 / 3 |
Highlights
Traffic
invokeWithLayeris sent only until the connection is inited; afterCONNECTION_NOT_INITEDorCONNECTION_LAYER_INVALIDit is sent again until the server accepts it.- No
get_future_salts: salts come fromnew_session_createdandbad_server_salt, as in Telegram Desktop. - Pings like Telegram Desktop. See Pings and salts.
upload.getFilesetspreciseonly for unaligned parts, and emptyentitiesvectors are no longer sent.
Sessions and clock
- The session keeps the keys of other DCs, so downloads and redirects after a restart
don't run a new key exchange and authorization transfer. It also stores the key age,
the server time offset and the self ID (
client.SelfID()answers without a request). Old session files load unchanged. See Sessions. - A reconnect continues the server session. When the server starts a new one, requests it didn't see are re-sent and updates are re-fetched.
- Server time offset like TDLib: message IDs follow the spec and use server time, so a skewed clock works. See Clock skew.
- Received messages are deduplicated, also inside containers.
- PFS: the permanent key is dropped only when the server confirms it's gone.
Updates and peers
- Failed differences are retried with backoff (1 s doubling to 60 s), flood waits are
waited out, and
PERSISTENT_TIMESTAMP_*resets the state. See Failed differences. telegram/peerscaches peers and usernames by default; usernames are normalized like TDLib and kept for a day.peers.Managercan be the access hasher of the updates manager, which removes the extra differences for channels the app already knows. See Access hashes.
LogOut and documents
client.LogOutlogs out on every DC, returns the future auth token and wipes the session. See Logging out.- Uploaded documents get a MIME type from the extension (or
application/octet-stream) and a file name. Before, Telegram Desktop could show such a file as an audio track.
Upgrading
Most changes are additions. Check these:
- Session continuity: reconnects continue the server session. Duplicate updates are filtered by pts, but after a server-side session loss a write the server already executed may be sent again.
- Session format: new optional fields, format version unchanged; older gotd versions ignore them.
- Duplicates: a server message re-sent after more than 100 newer ones is dropped, as the spec intends.
- Salts: one extra round trip when a salt expires. Set
SaltFetchIntervalfor the old periodic fetch. - Pings: every 30–45 s by default; an explicit
PingIntervalkeeps a fixed interval. - Peers cache:
peers.Options.Cachedefaults to an unbounded in-memory cache; passpeers.NoopCache{}to opt out. - Difference retries: failures are retried instead of waiting for the 15-minute idle timer.
- Documents: audio, video and sticker uploads without an explicit MIME type now get one from the extension.
Full list of changes: gotd/td v0.165.0.
