In letzter Zeit sind auf Habré häufiger Beiträge darüber erschienen, wie gut Telegramm ist, wie brillant und erfahren die Brüder Durov beim Aufbau von Netzwerksystemen usw. sind. Gleichzeitig haben sich nur sehr wenige Menschen wirklich in das technische Gerät gestürzt - maximal verwenden sie eine ziemlich einfache (und sich stark von MTProto unterscheidende) Bot-API, die auf JSON basiert, und normalerweise nehmen sie nur all das Lob und die Öffentlichkeitsarbeit entgegen, die sich um den Messenger drehen. Vor fast anderthalb Jahren begann mein Kollege bei der Echelon NGO Vasily (leider wurde sein Konto bei Habr zusammen mit einem Entwurf gelöscht), seinen eigenen Telegramm-Client von Grund auf auf Perl zu schreiben, und der Autor dieser Zeilen trat später bei. Warum bei Perl werden einige sofort fragen? Denn in anderen Sprachen existieren solche Projekte bereits In der Tat ist dies nicht der Punkt, es könnte eine andere Sprache geben, in der es noch keine fertige Bibliothek gibt , und dementsprechend muss der Autor den ganzen Weg von Grund auf neu gehen . Darüber hinaus ist Kryptographie so etwas - Vertrauen, aber überprüfen. Mit einem Produkt, das auf Sicherheit ausgerichtet ist, können Sie sich nicht einfach auf die fertige Bibliothek des Herstellers verlassen und sich blind darauf verlassen (dies ist jedoch eher ein Thema für den zweiten Teil). Im Moment funktioniert die Bibliothek auf der "mittleren" Ebene recht gut (Sie können beliebige API-Anforderungen stellen).
In dieser Reihe von Beiträgen wird es jedoch nicht viel Kryptographie und Mathematik geben. Es wird aber noch viele andere technische Details und architektonische Krücken geben (nützlich für diejenigen, die nicht von Grund auf neu schreiben, sondern die Bibliothek in einer beliebigen Sprache verwenden). Das Hauptziel war es daher, den Client gemäß der offiziellen Dokumentation von Grund auf neu zu implementieren. Angenommen, der Quellcode der offiziellen Clients ist geschlossen (im zweiten Teil werden wir uns erneut mit dem Thema befassen , wie dies wirklich geschieht ), aber wie in früheren Zeiten gibt es beispielsweise einen Standard wie RFC - ist es möglich, einen Client mit zu schreiben? nur eine Spezifikation, "nicht gucken" an der Quelle, zumindest offiziell (Telegram Desktop, mobil), zumindest inoffiziell Telethon?
Inhaltsverzeichnis:
Dokumentation ... existiert sie? Wirklich? ..
Im letzten Sommer wurden Fragmente von Notizen für diesen Artikel gesammelt. Während dieser ganzen Zeit auf der offiziellen Website https://core.telegram.org war die Dokumentation ab Schicht 23, d. H. 2014 irgendwo hängen geblieben (erinnerst du dich, dann gab es noch nicht einmal Kanäle?). Theoretisch hätte dies natürlich die Implementierung eines Client mit Funktionalität zu diesem Zeitpunkt im Jahr 2014 ermöglichen müssen. Aber auch in diesem Zustand war die Dokumentation zum einen unvollständig und zum anderen widersprach sie sich manchmal. Vor etwas mehr als einem Monat, im September 2019, wurde versehentlich festgestellt, dass die Site eine große Aktualisierung der Dokumentation auf der völlig neuen Schicht 105 aufwies, mit dem Hinweis, dass jetzt alles erneut gelesen werden muss. In der Tat wurden viele Artikel überarbeitet, aber viele blieben unverändert. Wenn man die folgenden Kritikpunkte bezüglich der Dokumentation liest, sollte man bedenken, dass einige dieser Dinge nicht mehr relevant sind, andere aber immer noch recht. Immerhin sind 5 Jahre in der modernen Welt nicht nur viel, sondern viel. Seit dieser Zeit (insbesondere wenn Sie die seitdem ausgeworfenen und wieder aufgenommenen Geochats nicht berücksichtigen) ist die Anzahl der API-Methoden im Schema von hundert auf mehr als zweihundertfünfzig gestiegen!
Wo soll man einen jungen Autor anfangen?
, Telethon Python Madeline PHP, — api_id
api_hash
( API ), . , , , . , , — , , .
, , , Telegram , , .. , "" , , .. . , , .
, . https://core.telegram.org/ Getting Started , MTProto — OSI , .
, MTProto, , ( , layer violation) , ...
: TL (Type Language) , ,
, , Telegram — . , , .
, . , , JSON Schema, . : . , , . MTProto, , - , :
int ? = Int;
long ? = Long;
double ? = Double;
string ? = String;
vector#1cb5c415 {t:Type} # [ t ] = Vector t;
rpc_error#2144ca19 error_code:int error_message:string = RpcError;
rpc_answer_unknown#5e2ad36e = RpcDropAnswer;
rpc_answer_dropped_running#cd78e586 = RpcDropAnswer;
rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer;
msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;
---functions---
set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:bytes = Set_client_DH_params_answer;
ping#7abe77ec ping_id:long = Pong;
ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;
invokeAfterMsg#cb9f372d msg_id:long query:!X = X;
invokeAfterMsgs#3dc4b4f0 msg_ids:Vector<long> query:!X = X;
account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User;
account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode;
, , — , ( , ?), , … . ++ ( , ). , , , , ( ), - , - , — , ( ) ? (, JSON- — ).
Binary Data Serialization 4 . , , , , , , , … ! TL Language, , , , !
, , , , , , , - . :
LeoNerd #perl
IRC- FreeNode, Telegram Matrix ( ):
, - , , , .
, bare- (int, long ..) - — — . , , , .
TL , …
constructor = Type;
myVec ids:Vector<long> = Type;
fixed#abcdef34 id:int = Type2;
fixedVec set:Vector<Type2> = FixedVec;
constructorOne#crc32 field1:int = PolymorType;
constructorTwo#2crc32 field_a:long field_b:Type3 field_c:int = PolymorType;
constructorThree#deadcrc bit_flags_of_what_really_present:# optional_field4:bit_flags_of_what_really_present.1?Type = PolymorType;
an_id#12abcd34 id:int = Type3;
a_null#6789cdef = Type3;
, ( — ) #
CRC32 . , — . , — , , — . , , — .
---functions---
, , : RPC-, — ( , , ), " " — . , , — ---types---
, " ". , .. , , C++, TL - .
"" "", ? , , - — , — -, final
. , , - . — , ( , , ) — , .
? , 4 , 0xcrc32
— , field1
int
, .. 4 , PolymorType
. 0x2crc32
, , long
, 8 . , . , Type3
, , 0x12abcd34
, 4 int
, 0x6789cdef
, . — . 4 int
field_c
constructorTwo
PolymorType
.
, 0xdeadcrc
constructorThree
, . bit_flags_of_what_really_present
#
— , nat
, " ". , , unsigned int — , , , . , , , — on the wire, , ( ). , , , , Type
, 2 . ( ), ids
ids:Vector<long>
.
, generic' Java. . , . , Vector. 4 CRC32 Vector, , 4 — , .
, 4 , — bytes
string
4 — , ? TL , , , 4 , JSON ? , , , , ?..
, , , . -, CRC32 ( whitespace ..) — , , CRC32 , , . , , , ?..
-, CRC32, - , (). — , 232, . , CRC32 ( ) , ? , : CRC32 , 4 4 — . ( ), , .
, , CRC32? ( ) -, 239, -!
, , , Vector<int>
Vector<PolymorType>
CRC32. ? , ? , , Vector<int>
, 40000 . Vector<Type2>
, int
— 10000 0xabcdef34 4 int
, fixedVec
80000 40000 ?
— , , id, , — . Telegram .
...
Vector,
, , ( ) tuples . , , , . ? , , — lazy evaluation . : , .. — , — ( (cons)
Lisp). , , 4 (CRC32 TL) . , — .
, TL , . :
Serialization always uses the same constructor “vector” (const 0x1cb5c415 = crc32("vector t:Type # [ t ] = Vector t”) that is not dependent on the specific value of the variable of type t.
The value of the optional parameter t is not involved in the serialization since it is derived from the result type (always known prior to deserialization).
: vector {t:Type} # [ t ] = Vector t
— , ! . , . , :
The Vector t polymorphic pseudotype is a “type” whose value is a sequence of values of any type t, either boxed or bare.
… . , ( ), , : , ( - ACM), . — — .
, . , #
nat
, :
There are type expressions (type-expr) and numeric expressions (nat-expr). However, they are defined the same way.
type-expr ::= expr
nat-expr ::= expr
, .. .
, (vector<int>
, vector<User>
) (#1cb5c415
), .. ,
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
, . , — , bare-, , - — ? - PHP, ?
— TL? , , protobuf, ? , .
TL
TL (), Telegram. . , Telegram. , ( ( ) ).
Templates are not used now. Instead, the same universal constructors (for example, vector {t:Type} [t] = Vector t) are used w
, , , .
#define ZHUKOV_BYTES_HACK
#ifdef ZHUKOV_BYTES_HACK
/* dirty hack for Zhukov request */
, :
static const char *reserved_words_polymorhic[] = {
"alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", NULL
};
— , :
intHash {alpha:Type} vector<coupleInt<alpha>> = IntHash<alpha>;
, int — Type. C++ :
template <T> class IntHash {
vector<pair<int,T>> _map;
}
, alpha
— ! C++ T, alpha, beta… 8 , . , - :
-- TL
-- ... , ,... ... , !
-- ?
-- , !
-- , ?
-- , , --
TL "". Telegram-.
:
Vasily, [09.10.18 17:07]
, , ,
, .jpg
.webp
, , , , - DSL, ?..
telegram-cli , TLO (cli) , — TL , TL?..
16.12 04:18 Vasily: -, - lex+yacc
16.12 04:18 Vasily:
16.12 04:18 Vasily:
16.12 04:19 Vasily: 3+ <censored>
, ? , — Telegram Desktop:
nametype = re.match(r'([a-zA-Z\.0-9_]+)(#[0-9a-f]+)?([^=]*)=\s*([a-zA-Z\.<>0-9_]+);', line);
if (not nametype):
if (not re.match(r'vector#1cb5c415 \{t:Type\} # \[ t \] = Vector t;', line)):
print('Bad line found: ' + line);
1100+ , + , , , TL, , … , , ?!
… , CRC32? , Telegram Desktop , CRC32 !
Vasily, [18.12 22:49]
, TL
, ,
tdesktop, ,
, .
, telegram-cli — , Telegram Desktop — , ? ?.. Android- ( , ), , .
? , , , :
Vasily: flags.0? true
, true,
Vasily: flags.1? int
, ,
Vasily: , , !
Vasily: - , true — , -
Vasily: ,
, , Telethon? MTProto, — , %
" bare-", .. , :
Vasily, [22.06.18 18:38]
:
msg_container#73f1f8dc messages:vector message = MessageContainer;
:
msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;
, -
bare
telethon
msg_container
, %. .
Vadim Goncharov, [22.06.18 19:22]
tdesktop?
Vasily, [22.06.18 19:23]
TL
// parsed manually
TL ,
%
,
,
TL,
" ", , "- , , ".
: " ,
args: /* empty */ { $$ = NULL; }
| args arg { $$ = g_list_append( $1, $2 ); }
;
arg: LC_ID ':' type-term { $$ = tl_arg_new( $1, $3 ); }
| LC_ID ':' condition '?' type-term { $$ = tl_arg_new_cond( $1, $5, $3 ); free($3); }
| UC_ID ':' type-term { $$ = tl_arg_new( $1, $3 ); }
| type-term { $$ = tl_arg_new( "", $1 ); }
| '[' LC_ID ']' { $$ = tl_arg_new_mult( "", tl_type_new( $2, TYPE_MOD_NONE ) ); }
;
- ,
struct tree *parse_args4 (void) {
PARSE_INIT (type_args4);
struct parse so = save_parse ();
PARSE_TRY (parse_optional_arg_def);
if (S) {
tree_add_child (T, S);
} else {
load_parse (so);
}
if (LEX_CHAR ('!')) {
PARSE_ADD (type_exclam);
EXPECT ("!");
}
PARSE_TRY_PES (parse_type_term);
PARSE_OK;
}
# Regex to match the whole line
match = re.match(r'''
^ # We want to match from the beginning to the end
([\w.]+) # The .tl object can contain alpha_name or namespace.alpha_name
(?:
\# # After the name, comes the ID of the object
([0-9a-f]+) # The constructor ID is in hexadecimal form
)? # If no constructor ID was given, CRC32 the 'tl' to determine it
(?:\s # After that, we want to match its arguments (name:type)
{? # For handling the start of the '{X:Type}' case
\w+ # The argument name will always be an alpha-only name
: # Then comes the separator between name:type
[\w\d<>#.?!]+ # The type is slightly more complex, since it's alphanumeric and it can
# also have Vector<type>, flags:# and flags.0?default, plus :!X as type
}? # For handling the end of the '{X:Type}' case
)* # Match 0 or more arguments
\s # Leave a space between the arguments and the equal
=
\s # Leave another space between the equal and the result
([\w\d<>#.?]+) # The result can again be as complex as any argument type
;$ # Finally, the line should always end with ;
''', tl, re.IGNORECASE | re.VERBOSE)
:
---functions--- return FUNCTIONS;
---types--- return TYPES;
[a-z][a-zA-Z0-9_]* yylval.string = strdup(yytext); return LC_ID;
[A-Z][a-zA-Z0-9_]* yylval.string = strdup(yytext); return UC_ID;
[0-9]+ yylval.number = atoi(yytext); return NUM;
#[0-9a-fA-F]{1,8} yylval.number = strtol(yytext+1, NULL, 16); return ID_HASH;
\n /* skip new line */
[ \t]+ /* skip spaces */
\/\/.*$ /* skip comments */
\/\*.*\*\/ /* skip comments */
. return (int)yytext[0];
.. — ".
, TL 100 ~300 ( print
' ), . , — .
— , ? , ( ), TL. , . , , , . ?
, constraints. :
The file’s binary content is then split into parts. All parts must have the same size ( part_size ) and the following conditions must be met:
part_size % 1024 = 0
(divisible by 1KB)524288 % part_size = 0
(512KB must be evenly divisible by part_size)
The last part does not have to satisfy these conditions, provided its size is less than part_size.
Each part should have a sequence number, file_part, with a value ranging from 0 to 2,999.
After the file has been partitioned you need to choose a method for saving it on the server. Use upload.saveBigFilePart in case the full size of the file is more than 10 MB and upload.saveFilePart for smaller files.
[...] one of the following data input errors may be returned:
- FILE_PARTS_INVALID — Invalid number of parts. The value is not between
1..3000
- ? - TL? . , Turbo Pascal , . , enum
— , () . — , , . , … , , , ?
TL . , , JSON Schema. 512 - , , , 1..3000
( ) , ?..
, . , TL — , TL , . TL . , ( , RPC -, ) — ?.. — .
, ? , , description ( JSON- ), , — ? :
-channelFull#76af5481 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull;
+channelFull#1c87a71a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull;
-message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;
+message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;
, GitHub, , . " 10 ", , , - … , , .
, . ? , ? . , , . :
storage.fileUnknown#aa963b05 = storage.FileType;
storage.filePartial#40bc6f52 = storage.FileType;
storage.fileJpeg#7efe0e = storage.FileType;
storage.fileGif#cae1aadf = storage.FileType;
storage.filePng#a4f63c0 = storage.FileType;
storage.filePdf#ae1e508d = storage.FileType;
storage.fileMp3#528a0677 = storage.FileType;
storage.fileMov#4b09ebbc = storage.FileType;
storage.fileMp4#b3cea0e4 = storage.FileType;
storage.fileWebp#1081464c = storage.FileType;
, 5 , 32 . . TL .
, . , MTProto ( ) Gzip, — , . , RpcResult, . ?.. , .
, — InputPeerUser
InputUser
. . ! . ? , , telegram-cli:
if (tgl_get_peer_type (E->id) != TGL_PEER_CHANNEL || (C && (C->flags & TGLCHF_MEGAGROUP))) {
out_int (CODE_messages_get_history);
out_peer_id (TLS, E->id);
} else {
out_int (CODE_channels_get_important_history);
out_int (CODE_input_channel);
out_int (tgl_get_peer_id (E->id));
out_long (E->id.access_hash);
}
out_int (E->max_id);
out_int (E->offset);
out_int (E->limit);
out_int (0);
out_int (0);
, , ! , ?.. , , , ? ? .
. (layers)
, , . , , , , , , . , — "", . , . , — , . 2. TL:
If a client supports Layer 2, then the following constructor must be used:
invokeWithLayer2#289dd1f6 {X:Type} query:!X = X;
In practice, this means that before every API call, an int with the value 0x289dd1f6
must be added before the method number.
. ?
invokeWithLayer3#b7475268 query:!X = X;
? ,
invokeWithLayer4#dea0d430 query:!X = X;
? , , , — , -? 4 — . So,
invokeWithLayer5#417a57ae query:!X = X;
, . :
Update: Starting with Layer 9, helper methods invokeWithLayerN
can be used only together with initConnection
! 9 , , , Internet- 80- — !
?..
invokeWithLayer10#39620c41 query:!X = X;
...
invokeWithLayer18#1c900537 query:!X = X;
. 9 , , , , , , . .
?..
Vasily, [16.07.18 14:01]
:
. InvokeWithLayer. , .
.. ,
Vadim Goncharov, [16.07.18 14:02]
InvokeWithLayer ?
Vasily, [16.07.18 14:02]
Vadim Goncharov, [16.07.18 14:02]
, ,
, .. Updates
— , API-, . , , , Updates .
, , :
, , , ( , )? ! !
. 14 , Telegram - … :
2019-08-15 09:28:35.880640 MSK warn main: ANON:87: unknown object type: 0x80d182d1 at TL/Object.pm line 213.
2019-08-15 09:28:35.751899 MSK warn main: ANON:87: unknown object type: 0xb5223b0f at TL/Object.pm line 213.
(, ). TL - — , , . ?
, — . . CRC32 — 73 , 82. — !
, ? , Telegram Desktop 1.2.17 (, Linux), Exception: MTP Unexpected type id #b5223b0f read in MTPMessageMedia...

, - , ...
-? : 91, 73. , , , , .
: , , , , , — , . .
? , . , , "", , , , . "", .
… ?!.. , , . Android TL-, ( ) (). :
public static class TL_message_layer68 extends TL_message {
public static int constructor = 0xc09be45f;
//...
//
//...
public static class TL_message_layer47 extends TL_message {
public static int constructor = 0xc992e15c;
public static Message TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) {
Message result = null;
switch (constructor) {
case 0x1d86f70e:
result = new TL_messageService_old2();
break;
case 0xa7ab1991:
result = new TL_message_old3();
break;
case 0xc3060325:
result = new TL_message_old4();
break;
case 0x555555fa:
result = new TL_message_secret();
break;
case 0x555555f9:
result = new TL_message_secret_layer72();
break;
case 0x90dddc11:
result = new TL_message_layer72();
break;
case 0xc09be45f:
result = new TL_message_layer68();
break;
case 0xc992e15c:
result = new TL_message_layer47();
break;
case 0x5ba66c13:
result = new TL_message_old7();
break;
case 0xc06b9607:
result = new TL_messageService_layer48();
break;
case 0x83e5de54:
result = new TL_messageEmpty();
break;
case 0x2bebfa86:
result = new TL_message_old6();
break;
case 0x44f9b43d:
result = new TL_message_layer104();
break;
case 0x1c9b1027:
result = new TL_message_layer104_2();
break;
case 0xa367e716:
result = new TL_messageForwarded_old2(); //custom
break;
case 0x5f46804:
result = new TL_messageForwarded_old(); //custom
break;
case 0x567699b3:
result = new TL_message_old2(); //custom
break;
case 0x9f8d60bb:
result = new TL_messageService_old(); //custom
break;
case 0x22eb6aba:
result = new TL_message_old(); //custom
break;
case 0x555555F8:
result = new TL_message_secret_old(); //custom
break;
case 0x9789dac4:
result = new TL_message_layer104_3();
break;
boolean fixCaption = !TextUtils.isEmpty(message) &&
(media instanceof TLRPC.TL_messageMediaPhoto_old ||
media instanceof TLRPC.TL_messageMediaPhoto_layer68 ||
media instanceof TLRPC.TL_messageMediaPhoto_layer74 ||
media instanceof TLRPC.TL_messageMediaDocument_old ||
media instanceof TLRPC.TL_messageMediaDocument_layer68 ||
media instanceof TLRPC.TL_messageMediaDocument_layer74)
&& message.startsWith("-1");
… . , , , ?.. ! , , , , _old7
- … ,
TL_message_layer104
TL_message_layer104_2
TL_message_layer104_3
, , ?! , , "", , , , ?.. ? , ?..
Telegram Desktop, , — , , - . , , , ? , , , .
? , -, .
, :
public static class TL_folders_deleteFolder extends TLObject {
public static int constructor = 0x1c295881;
public int folder_id;
public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) {
return Updates.TLdeserialize(stream, constructor, exception);
}
public void serializeToStream(AbstractSerializedData stream) {
stream.writeInt32(constructor);
stream.writeInt32(folder_id);
}
}
//manually created
//RichText start
public static abstract class RichText extends TLObject {
public String url;
public long webpage_id;
public String email;
public ArrayList<RichText> texts = new ArrayList<>();
public RichText parentRichText;
public static RichText TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) {
RichText result = null;
switch (constructor) {
case 0x1ccb966a:
result = new TL_textPhone();
break;
case 0xc7fb5e01:
result = new TL_textSuperscript();
break;
"manually created" , ( maintenance?), . , — , (- GPL Linux), .
. , .
MTProto
, . . , Telegram — -, , (, API sticker pack — , ).
, "" (message) "" (session) — , Telegram-. , , , "" — , , , , . … .
— . 5 :
- TCP
- Websocket
- Websocket over HTTPS
- HTTP
- HTTPS
Vasily, [15.06.18 15:04]
UDP ,
TCP
UDP TCP, sequence number crc
?
, TCP 4 :
- Abridged
- Intermediate
- Padded intermediate
- Full
, Padded intermediate MTProxy, - . ( ), ? , payload MTProto, :
- Abridged 1 4 , 0xef,
- Intermediate 4 ,
0xeeeeeeee
, Intermediate - Full , : , sequence number, , MTProto, , CRC32. , TCP. , , . , , TCP 16- , . , - 16 , — — SHA . CRC32 — .
Abridged, , Intermediate, "In case 4-byte data alignment is needed", - . , , Telegram , ? , ( -...). , Abridged, padding' 16 — 3 ?
, , , .
, .. Web MTProxy, , , , . MTProxy , 2018, , , ! , ( ) MTProxy , ( ), Go, Node.js .
, . 5- OSI, — MTProto session.
, , , Diffie-Hellman
… — , Active sessions. .

. , plaintext — . "" ? Telegram ( 4 , ):
session — UI "current sessions", / OS.
— MTProto session, sequence number ( ) , TCP-. MTProto-, .
sessions authorization. , , UI- , authorization, , . :
- auth_key bounds it to account, SMS — authorization
- MTProto session,
session_id
. - , authorization
session_id
instance — - , MTProto sessions auth_key — DC.
- , DC — DC auth_key !
- , , authorization (UI-), API
auth.exportAuthorization
DC auth.importAuthorization
DC. - , MTProto sessions (
session_id
) DC, auth_key. - , Perfect Forward Secrecy. auth_key permanent key — per DC —
auth.bindTempAuthKey
temporary auth_key — , temp_auth_key per DC, MTProto sessions DC.
, salt ( future salts) auth_key .. shared MTProto sessions DC.
" TCP-"? , - — () TCP- , . HTTP, MTProto , , — , TCP-.
, . — ? — .
, auth_key
- Telegram. ...
Vasily, [19.06.18 20:05]
data_with_hash := SHA1(data) + data + (any random bytes); such that the length equal 255 bytes;
encrypted_data := RSA (data_with_hash, server_public_key); a 255-byte long number (big endian) is raised to the requisite power over the requisite modulus, and the result is stored as a 256-byte number.
- DH
DH
— proof of work , . DoS-. RSA- , , new_nonce
. , ?
Vasily, [20.06.18 00:26]
appid
DH
, , 4 .
-404, ?
: " -, DH", 404
? ? - ( ).
, -
32 .
, BE
Vadim Goncharov, [20.06.18 15:49]
- 404?
Vasily, [20.06.18 15:49]
!
Vadim Goncharov, [20.06.18 15:50]
, " "
Vasily, [20.06.18 15:50]
%)
error reporting
Vasily, [20.06.18 20:18]
, MD5.
The key fingerprint is computed as follows:
digest = md5(key + iv)
fingerprint = substr(digest, 0, 4) XOR substr(digest, 4, 4)
SHA1 sha2
, , auth_key
2048 - . ? , 1024 … . . TLS-, . , ! , , . .. "-", - ICQ, "-", SSH ( - gitlab/github). . " DC"? " "? , — , .
, "" . , ? ? :
Vasily, [21.06.18 17:53]
2 %)
,
Vasily, [21.06.18 18:02]
, ,
. , ? ( , ) — , :
278 static const char *goodPrime = "c71caeb9c6b1c9048e6c522f70f13f73980d40238e3e21c14934d037563d930f48198a0aa7c14058229493d22530f4dbfa336f6e0ac925139543aed44cce7c3720fd51f69458705ac68cd4fe6b6b13abdc9746512969328454f18faf8c595f642477fe96bb2a941d5bcd1d4ac8cc49880708fa9b378e3c4f3a9060bee67cf9a4a4a695811051907e162753b56b0f6b410dba74d8a84b2a14b3144e0ef1284754fd17ed950d5965b4b9dd46582db1178d169c6bc465b0d6ff9ca3928fef5b9ae4e418fc15e83ebea0f87fa9ff5eed70050ded2849f47bf959d956850ce929851f0d8115f635b105ee2e4e15d04b2454bf6f4fadf034b10403119cd8e3b92fcc5b";
279 if (!strcasecmp(prime, goodPrime)) {
, - , .
, . , .. , , AES.
The message key is defined as the 128 middle bits of the SHA256 of the message body (including session, message ID, etc.), including the padding bytes, prepended by 32 bytes taken from the authorization key.
Vasily, [22.06.18 14:08]
, ,
auth_key
. . … . Feel free to study the open source code.
Note that MTProto 2.0 requires from 12 to 1024 bytes of padding, still subject to the condition that the resulting message length be divisible by 16 bytes.
?
, 404
, , MAC . AES , IGE. , , FAQ… , , SHA- , — - silently ignore ( , ?).
, , . , Telegram Desktop. ( D877F783D5D3EF8C) , MTProto ( 1.0), .. , ( - auth_key
256 , msg_key
). , . , — . , , ?.. MAC , . MTProto , . Telegram Desktop user_data
— AES CTR.
Vasily, [21.06.18 01:27]
, , IGE: IGE was the first attempt at an "authenticating encryption mode," originally for Kerberos. It was a failed attempt (it does not provide integrity protection), and had to be removed. That was the beginning of a 20 year quest for an authenticating encryption mode that works, which recently culminated in modes like OCB and GCM.
:
The team behind Telegram, led by Nikolai Durov, consists of six ACM champions, half of them Ph.Ds in math. It took them about two years to roll out the current version of MTProto.
.
tls
, , . , , TL ? ? , , initConnection, ?
Vasily, [25.06.18 18:46]
Initializes connection and save information on the user's device and application.
app_id, device_model, system_version, app_version lang_code.
query
. Feel free to study the open source
invokeWithLayer , - ? , — , — , :
Vasily, [25.06.18 19:13]
, , invokewithlayer
initConnection , ? , , , , . ! ! , — , ...
Only a small portion of the API methods are available to unauthorized users:
- auth.sendCode
- auth.resendCode
- account.getPassword
- auth.checkPassword
- auth.checkPhone
- auth.signUp
- auth.signIn
- auth.importAuthorization
- help.getConfig
- help.getNearestDc
- help.getAppUpdate
- help.getCdnConfig
- langpack.getLangPack
- langpack.getStrings
- langpack.getDifference
- langpack.getLanguages
- langpack.getLanguage
, auth.sendCode
, , api_id api_hash, SMS . DC ( , ), DC. , IP- DC , help.getConfig
. - 5 , 2018 .
, . , IP-? , , MTProto? : " , ?". , - RSA-, .. . , , (, MTProto, , ).
, . . , , . ...
Vasily, [10.07.18 14:45]
https://core.telegram.org/method/help.getConfig
config#7dae33e0 [...] = Config;
help.getConfig#c4f9186b = Config;
https://core.telegram.org/api/datacenter
config#232d5905 [...] = Config;
help.getConfig#c4f9186b = Config;
,
tdesktop
, , , . . ? , , ? , — (, ).
… , - API, .. , - MTProto? :
Vasily, [28.06.18 02:04]
, e2e
Mtproto ,
, , mtproto
? PFS, (, Telegram Desktop ). API auth.bindTempAuthKey
, .. . — , , initConnection
.., . , DC, auth_key_id
, "" — , … , future salts, ?..
MTProto .
, msg_id, msg_seqno, ,
? "" , , API. , msg_key , . ( , , padding, ):
- salt — int64
- session_id — int64
- message_id — int64
- seq_no — int32
, — DC. ? , get_future_salts
, , , , "", () — . , , , new_session_created
— - , . .
. , MTProto ? , session_id
seq_no
. , TCP-, . , , , . — TCP- , seq_no
. — , , .
seq_no
? , . , :
Content-related Message
A message requiring an explicit acknowledgment. These include all the user and many service messages, virtually all with the exception of containers and acknowledgments.
Message Sequence Number (msg_seqno)
A 32-bit number equal to twice the number of “content-related” messages (those requiring acknowledgment, and in particular those that are not containers) created by the sender prior to this message and subsequently incremented by one if the current message is a content-related message. A container is always generated after its entire contents; therefore, its sequence number is greater than or equal to the sequence numbers of the messages contained in it.
1, 2?.. , " ACK, ", — , , , seq_no
! ? - , , , . . TCP , - , , TCP seq_no
, seq_no
— . MTProto seq_no
, TCP, msg_id
!
msg_id
, ? , . 64- , "- ", — Unix timestamp, , 32 . .. ( ). , - , . , — session_id
— : Under no circumstances can a message meant for one session be sent into a different session. , , — , , id . , .
, msg_id
...
RPC: , , . .
, , , " RPC-", . content-related ! , ! . msg_id
. — :
rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult;
, . , API, , — , , , , ? , , no workers, : TCP- — -, message_id
. , .
?.. ? RPC- msg_id
! " !"? , ? ,
msgs_ack#62d6b459 msg_ids:Vector long = MsgsAck;
. ! RpcResult, . , MsgsAck — , " ". RpcResult. .
, ! . . . , , . .
.
rpc_error#2144ca19 error_code:int error_message:string = RpcError;
, -, — ! . , , , . , — HTTP- ( , , ), ___. , PHONE_NUMBER_OCCUPIED FILE_PART__MISSING. , . , FLOOD_WAIT_3600
, , PHONE_MIGRATE_5
, 5- DC. , ? , , .
, , , , . . -, , / — RpcError
RpcResult
. ? ?.. , , RpcError
RpcResult
, ?.. , , .. req_msg_id
?..
. , , :
rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer;
, , , ( , ), (: Telegram Desktop ).
:
, TL, MTProto Telegram , , soft skills , . , , .
, .
bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification;
bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification;
, MTProto, " — — " — . :
- , . - , .
- ? 16, 17, 18, 19, 20, 32, 33, 34, 35, 48, 64… , ?
:
The intention is that error_code values are grouped (error_code >> 4): for example, the codes 0x40 — 0x4f correspond to errors in container decomposition.
, -, , -, , ? ?.. , .
:
- Request for Message Status Information
If either party has not received information on the status of its outgoing messages for a while, it may explicitly request it from the other party:
msgs_state_req#da69fb52 msg_ids:Vector long = MsgsStateReq;
- Informational Message regarding Status of Messages
msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo;
Here, info
is a string that contains exactly one byte of message status for each message from the incoming msg_ids list:
- 1 = nothing is known about the message (msg_id too low, the other party may have forgotten it)
- 2 = message not received (msg_id falls within the range of stored identifiers; however, the other party has certainly not received a message like that)
- 3 = message not received (msg_id too high; however, the other party has certainly not received it yet)
- 4 = message received (note that this response is also at the same time a receipt acknowledgment)
- +8 = message already acknowledged
- +16 = message not requiring acknowledgment
- +32 = RPC query contained in message being processed or processing already complete
- +64 = content-related response to message already generated
- +128 = other party knows for a fact that message is already received
This response does not require an acknowledgment. It is an acknowledgment of the relevant msgs_state_req, in and of itself.
Note that if it turns out suddenly that the other party does not have a message that looks like it has been sent to it, the message can simply be re-sent. Even if the other party should receive two copies of the message at the same time, the duplicate will be ignored. (If too much time has passed, and the original msg_id is not longer valid, the message is to be wrapped in msg_copy).
- Voluntary Communication of Status of Messages
Either party may voluntarily inform the other party of the status of the messages transmitted by the other party.
msgs_all_info#8cc0d131 msg_ids:Vector long info:string = MsgsAllInfo
- Extended Voluntary Communication of Status of One Message
…
msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
- Explicit Request to Re-Send Messages
msg_resend_req#7d861a08 msg_ids:Vector long = MsgResendReq;
The remote party immediately responds by re-sending the requested messages [...] - Explicit Request to Re-Send Answers
msg_resend_ans_req#8610baeb msg_ids:Vector long = MsgResendReq;
The remote party immediately responds by re-sending answers to the requested messages [...] - Message Copies
In some situations, an old message with a msg_id that is no longer valid needs to be re-sent. Then, it is wrapped in a copy container:
msg_copy#e06046b2 orig_message:Message = MessageCopy;
Once received, the message is processed as if the wrapper were not there. However, if it is known for certain that the message orig_message.msg_id was received, then the new message is not processed (while at the same time, it and orig_message.msg_id are acknowledged). The value of orig_message.msg_id must be lower than the container’s msg_id.
, msgs_state_info
TL ( , enum, ). . - , ?.. , - , , — , . .
, , , , . , . , ! , -, . , , , TL — () , , , .. .
. .
, ( ), — TCP ( , , ), MTProto — . , , .
— . , - — . ? . , - , , Telegram Desktop 4 , ( , , ; , , MTProto ).
? , , -, . , , TCP — RTT "" ( ) . , — .
, , ? TCP TCP — .
, , , , API? , , , . ? msg_id
, , — - (, , , — , - ). , , :
- .
msg_id
— ; .- ) MsgsAck — , " ".
) , - , badmsg — " "
) , — , . RpcResult
— ( ) — , .
, . , , msg_id
. , - , .
. , , , — , ? (, ).
? " " " , !" ( , , rationale , ), / — , . ?
A server usually acknowledges the receipt of a message from a client (normally, an RPC query) using an RPC response. If a response is a long time coming, a server may first send a receipt acknowledgment, and somewhat later, the RPC response itself.
A client normally acknowledges the receipt of a message from a server (usually, an RPC response) by adding an acknowledgment to the next RPC query if it is not transmitted too late (if it is generated, say, 60-120 seconds following the receipt of a message from the server). However, if for a long period of time there is no reason to send messages to the server or if there is a large number of unacknowledged messages from the server (say, over 16), the client transmits a stand-alone acknowledgment.
… : , , , .
:
Ping Messages (PING/PONG)
ping#7abe77ec ping_id:long = Pong;
A response is usually returned to the same connection:
pong#347773c5 msg_id:long ping_id:long = Pong;
These messages do not require acknowledgments. A pong is transmitted only in response to a ping while a ping can be initiated by either side.
Deferred Connection Closure + PING
ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;
Works like ping. In addition, after this is received, the server starts a timer which will close the current connection disconnect_delay seconds later unless it receives a new message of the same type which automatically resets all previous timers. If the client sends these pings once every 60 seconds, for example, it may set disconnect_delay equal to 75 seconds.
?! 60 , - , . 120 , , , . , — " , ", TCP_NODELAY, . , , — 200 . — , , 5 , "User is typing...". .
, . , TCP-. , 10 — , . 3 , — , ?..
. TCP-, , . , , . , SSH- , - , , — ( , ), . , , (, !), , , — .
/ IM , — -. "", . , Jabber ( 20 ) — , , , online ( ). , TCP_KEEPALIVE, , TCP, ( ), — , , , , (, ? Telegram Desktop Ubuntu 18.04 ).
, — , , .
Telegram? ! .. , , . — ping_delay_disconnect
, . , , . , , . , , , , ...
?
, Telegram/ ( ) .
, Telegram ? , , TCP-, , . — . , UDP-, ( — ). - , TCP , , ( ), " " — .
? , msg_id
, replay-, . , ( Updates, API ), :
- , TCP- , — , , , . id', " seq_no" — , TCP ( — seq ). , ?
- replay- , - nonce. , .
uint32
— , 16 , — ( ). msg_id
— , -, id , -, id , . , seq_no
.
, — API , . , , .
API ?
-! , , , , ( , , PUSH, - ).
, Perl! ( , , bless — , — ):
2019.10.24 12:00:51 $1 = {
'cb' => 'TeleUpd::__ANON__',
'out' => bless( {
'filter' => bless( {}, 'Telegram::ChannelMessagesFilterEmpty' ),
'channel' => bless( {
'access_hash' => '-6698103710539760874',
'channel_id' => '1380524958'
}, 'Telegram::InputPeerChannel' ),
'pts' => '158503',
'flags' => 0,
'limit' => 0
}, 'Telegram::Updates::GetChannelDifference' ),
'req_id' => '6751291954012037292'
};
2019.10.24 12:00:51 $1 = {
'in' => bless( {
'req_msg_id' => '6751291954012037292',
'result' => bless( {
'pts' => 158508,
'flags' => 3,
'final' => 1,
'new_messages' => [],
'users' => [],
'chats' => [
bless( {
'title' => '',
'username' => 'hoolinomics',
'flags' => 8288,
'id' => 1380524958,
'access_hash' => '-6698103710539760874',
'broadcast' => 1,
'version' => 0,
'photo' => bless( {
'photo_small' => bless( {
'volume_id' => 246933270,
'file_reference' => '
'secret' => '1854156056801727328',
'local_id' => 228648,
'dc_id' => 2
}, 'Telegram::FileLocation' ),
'photo_big' => bless( {
'dc_id' => 2,
'local_id' => 228650,
'file_reference' => '
'secret' => '1275570353387113110',
'volume_id' => 246933270
}, 'Telegram::FileLocation' )
}, 'Telegram::ChatPhoto' ),
'date' => 1531221081
}, 'Telegram::Channel' )
],
'timeout' => 300,
'other_updates' => [
bless( {
'pts_count' => 0,
'message' => bless( {
'post' => 1,
'id' => 852,
'flags' => 50368,
'views' => 8013,
'entities' => [
bless( {
'length' => 20,
'offset' => 0
}, 'Telegram::MessageEntityBold' ),
bless( {
'length' => 18,
'offset' => 480,
'url' => 'https://alexeymarkov.livejournal.com/[url_].html'
}, 'Telegram::MessageEntityTextUrl' )
],
'reply_markup' => bless( {
'rows' => [
bless( {
'buttons' => [
bless( {
'text' => '???? 165',
'data' => 'send_reaction_0'
}, 'Telegram::KeyboardButtonCallback' ),
bless( {
'data' => 'send_reaction_1',
'text' => '???? 9'
}, 'Telegram::KeyboardButtonCallback' )
]
}, 'Telegram::KeyboardButtonRow' )
]
}, 'Telegram::ReplyInlineMarkup' ),
'message' => ' !
// [ ]
.',
'to_id' => bless( {
'channel_id' => 1380524958
}, 'Telegram::PeerChannel' ),
'date' => 1571724559,
'edit_date' => 1571907562
}, 'Telegram::Message' ),
'pts' => 158508
}, 'Telegram::UpdateEditChannelMessage' ),
bless( {
'pts' => 158508,
'message' => bless( {
'edit_date' => 1571907589,
'to_id' => bless( {
'channel_id' => 1380524958
}, 'Telegram::PeerChannel' ),
'date' => 1571807301,
'message' => ' Facebook ? ? -, . , , , .
: Facebook . , , . . - . , , - . .
, : Whatsapp, Instagram. , !
. . - - , .
# #facebook # #',
'reply_markup' => bless( {
'rows' => [
bless( {
'buttons' => [
bless( {
'data' => 'send_reaction_0',
'text' => '???? 452'
}, 'Telegram::KeyboardButtonCallback' ),
bless( {
'text' => '???? 21',
'data' => 'send_reaction_1'
}, 'Telegram::KeyboardButtonCallback' )
]
}, 'Telegram::KeyboardButtonRow' )
]
}, 'Telegram::ReplyInlineMarkup' ),
'entities' => [
bless( {
'length' => 199,
'offset' => 0
}, 'Telegram::MessageEntityBold' ),
bless( {
'length' => 8,
'offset' => 919
}, 'Telegram::MessageEntityHashtag' ),
bless( {
'offset' => 928,
'length' => 9
}, 'Telegram::MessageEntityHashtag' ),
bless( {
'length' => 6,
'offset' => 938
}, 'Telegram::MessageEntityHashtag' ),
bless( {
'length' => 11,
'offset' => 945
}, 'Telegram::MessageEntityHashtag' )
],
'views' => 6964,
'flags' => 50368,
'id' => 854,
'post' => 1
}, 'Telegram::Message' ),
'pts_count' => 0
}, 'Telegram::UpdateEditChannelMessage' ),
bless( {
'message' => bless( {
'reply_markup' => bless( {
'rows' => [
bless( {
'buttons' => [
bless( {
'data' => 'send_reaction_0',
'text' => '???? 213'
}, 'Telegram::KeyboardButtonCallback' ),
bless( {
'data' => 'send_reaction_1',
'text' => '???? 8'
}, 'Telegram::KeyboardButtonCallback' )
]
}, 'Telegram::KeyboardButtonRow' )
]
}, 'Telegram::ReplyInlineMarkup' ),
'views' => 2940,
'entities' => [
bless( {
'length' => 609,
'offset' => 348
}, 'Telegram::MessageEntityItalic' )
],
'flags' => 50368,
'post' => 1,
'id' => 857,
'edit_date' => 1571907636,
'date' => 1571902479,
'to_id' => bless( {
'channel_id' => 1380524958
}, 'Telegram::PeerChannel' ),
'message' => ' 1 . 10 (, 1-) :
// [ ]
, 1 , ... , .'
}, 'Telegram::Message' ),
'pts_count' => 0,
'pts' => 158508
}, 'Telegram::UpdateEditChannelMessage' ),
bless( {
'pts' => 158508,
'pts_count' => 0,
'message' => bless( {
'message' => ', , , 1?
// [ ]
# #it #',
'edit_date' => 1571907650,
'date' => 1571893707,
'to_id' => bless( {
'channel_id' => 1380524958
}, 'Telegram::PeerChannel' ),
'flags' => 50368,
'post' => 1,
'id' => 856,
'reply_markup' => bless( {
'rows' => [
bless( {
'buttons' => [
bless( {
'data' => 'send_reaction_0',
'text' => '???? 360'
}, 'Telegram::KeyboardButtonCallback' ),
bless( {
'data' => 'send_reaction_1',
'text' => '???? 32'
}, 'Telegram::KeyboardButtonCallback' )
]
}, 'Telegram::KeyboardButtonRow' )
]
}, 'Telegram::ReplyInlineMarkup' ),
'views' => 4416,
'entities' => [
bless( {
'offset' => 0,
'length' => 64
}, 'Telegram::MessageEntityBold' ),
bless( {
'offset' => 1551,
'length' => 5
}, 'Telegram::MessageEntityHashtag' ),
bless( {
'length' => 3,
'offset' => 1557
}, 'Telegram::MessageEntityHashtag' ),
bless( {
'offset' => 1561,
'length' => 10
}, 'Telegram::MessageEntityHashtag' )
]
}, 'Telegram::Message' )
}, 'Telegram::UpdateEditChannelMessage' )
]
}, 'Telegram::Updates::ChannelDifference' )
}, 'MTProto::RpcResult' )
};
2019.10.24 12:00:51 $1 = {
'in' => bless( {
'update' => bless( {
'user_id' => 2507460,
'status' => bless( {
'was_online' => 1571907651
}, 'Telegram::UserStatusOffline' )
}, 'Telegram::UpdateUserStatus' ),
'date' => 1571907650
}, 'Telegram::UpdateShort' )
};
2019.10.24 12:05:46 $1 = {
'in' => bless( {
'chats' => [],
'date' => 1571907946,
'seq' => 0,
'updates' => [
bless( {
'max_id' => 141719,
'channel_id' => 1295963795
}, 'Telegram::UpdateReadChannelInbox' )
],
'users' => []
}, 'Telegram::Updates' )
};
2019.10.24 13:01:23 $1 = {
'in' => bless( {
'server_salt' => '4914425622822907323',
'unique_id' => '5297282355827493819',
'first_msg_id' => '6751307555044380692'
}, 'MTProto::NewSessionCreated' )
};
2019.10.24 13:24:21 $1 = {
'in' => bless( {
'chats' => [
bless( {
'username' => 'freebsd_ru',
'version' => 0,
'flags' => 5440,
'title' => 'freebsd_ru',
'min' => 1,
'photo' => bless( {
'photo_small' => bless( {
'local_id' => 328733,
'volume_id' => 235140688,
'dc_id' => 2,
'file_reference' => '
'secret' => '4426006807282303416'
}, 'Telegram::FileLocation' ),
'photo_big' => bless( {
'dc_id' => 2,
'file_reference' => '
'volume_id' => 235140688,
'local_id' => 328735,
'secret' => '71251192991540083'
}, 'Telegram::FileLocation' )
}, 'Telegram::ChatPhoto' ),
'date' => 1461248502,
'id' => 1038300508,
'democracy' => 1,
'megagroup' => 1
}, 'Telegram::Channel' )
],
'users' => [
bless( {
'last_name' => 'Panov',
'flags' => 1048646,
'min' => 1,
'id' => 82234609,
'status' => bless( {}, 'Telegram::UserStatusRecently' ),
'first_name' => 'Dima'
}, 'Telegram::User' )
],
'seq' => 0,
'date' => 1571912647,
'updates' => [
bless( {
'pts' => 137596,
'message' => bless( {
'flags' => 256,
'message' => ' ??',
'to_id' => bless( {
'channel_id' => 1038300508
}, 'Telegram::PeerChannel' ),
'id' => 119634,
'date' => 1571912647,
'from_id' => 82234609
}, 'Telegram::Message' ),
'pts_count' => 1
}, 'Telegram::UpdateNewChannelMessage' )
]
}, 'Telegram::Updates' )
};
, — , !
Oh, wai~~… ? - … , Web API JSON, ?..
… , ?.. — , Web- ?.. JSON HTTPS ?! ? ?
, TL+MTProto, . , HTTP, "-", , - TLS ?
. , JSON, , . MsgPack , , , CBOR — , , RFC 7049. , , , :
- 25 + 256 — ,
- 26 — Perl c
- 27 —
, TL CBOR . CBOR - :
cborlen=1039673 tl_len=1095092
, : , , .
. RTT ( ) — MTProto, — , , etc. TLS? :
PFS TLS TLS session tickets (RFC 5077) . , ( session ticket). , session ticket, , . ticket (session ticket key), frontend-, SSL .[10]. , session ticket PFS , , (OpenSSL, nginx, Apache ; , ).
RTT , ClientHello ServerHello, Finished . , Web, , , - , Web- — . , , .
- ? .
To be continued!
, — , , , .. , , , .
/ . , :
- TL-
- dialogs roster
- vs
- photo image
! Stay tuned!