ٹیلیگرام کے پروٹوکول اور تنظیمی طریقوں پر تنقید۔ حصہ 1، تکنیکی: ایک کلائنٹ کو شروع سے لکھنے کا تجربہ - TL, MT

حال ہی میں، ٹیلی گرام کتنا اچھا ہے، نیٹ ورک سسٹم بنانے میں ڈوروف برادران کتنے شاندار اور تجربہ کار ہیں، وغیرہ کے بارے میں پوسٹس زیادہ کثرت سے Habré پر آنا شروع ہو گئی ہیں۔ ایک ہی وقت میں، بہت کم لوگوں نے واقعی تکنیکی ڈیوائس میں اپنے آپ کو غرق کیا ہے - زیادہ سے زیادہ، وہ JSON پر مبنی کافی آسان (اور MTProto سے بالکل مختلف) Bot API استعمال کرتے ہیں، اور عام طور پر صرف قبول کرتے ہیں۔ ایمان پر تمام تعریفیں اور PR جو رسول کے گرد گھومتی ہیں۔ تقریباً ڈیڑھ سال پہلے، Eshelon NGO Vasily میں میرے ساتھی (بدقسمتی سے، Habré پر اس کا اکاؤنٹ ڈرافٹ کے ساتھ ہی مٹا دیا گیا تھا) نے پرل میں شروع سے اپنا ٹیلیگرام کلائنٹ لکھنا شروع کیا، اور بعد میں ان سطروں کے مصنف بھی شامل ہو گئے۔ کیوں پرل، کچھ فوری طور پر پوچھیں گے؟ کیونکہ اس طرح کے منصوبے دوسری زبانوں میں پہلے سے موجود ہیں، درحقیقت یہ بات نہیں ہے، کوئی اور زبان ہو سکتی ہے جہاں نہ ہو۔ ریڈی میڈ لائبریری، اور اس کے مطابق مصنف کو ہر طرح سے جانا چاہئے۔ شروع سے. مزید برآں، خفیہ نگاری اعتماد کا معاملہ ہے، لیکن تصدیق کریں۔ سیکیورٹی کے مقصد سے ایک پروڈکٹ کے ساتھ، آپ صرف مینوفیکچرر کی طرف سے تیار شدہ لائبریری پر بھروسہ نہیں کر سکتے اور اس پر آنکھیں بند کر کے بھروسہ نہیں کر سکتے (تاہم، یہ دوسرے حصے کا موضوع ہے)۔ اس وقت، لائبریری "اوسط" سطح پر کافی اچھی طرح سے کام کرتی ہے (آپ کو کسی بھی API کی درخواستیں کرنے کی اجازت دیتی ہے)۔

تاہم، پوسٹس کی اس سیریز میں زیادہ خفیہ نگاری یا ریاضی نہیں ہوگی۔ لیکن بہت سی دوسری تکنیکی تفصیلات اور آرکیٹیکچرل بیساکھییں ہوں گی (ان لوگوں کے لیے بھی مفید جو شروع سے نہیں لکھیں گے، لیکن لائبریری کو کسی بھی زبان میں استعمال کریں گے)۔ لہذا، بنیادی مقصد کلائنٹ کو شروع سے لاگو کرنے کی کوشش کرنا تھا۔ سرکاری دستاویزات کے مطابق. یعنی فرض کریں کہ آفیشل کلائنٹس کا سورس کوڈ بند ہے (دوبارہ، دوسرے حصے میں ہم مزید تفصیل سے اس موضوع کا احاطہ کریں گے کہ یہ سچ ہے۔ یہ ہوتا ہے تو)، لیکن، جیسا کہ پرانے دنوں میں، مثال کے طور پر، RFC جیسا ایک معیار ہے - کیا یہ ممکن ہے کہ کسی کلائنٹ کو صرف تصریح کے مطابق، سورس کوڈ کو "دیکھے بغیر" لکھنا، چاہے وہ آفیشل ہو (ٹیلیگرام ڈیسک ٹاپ، موبائل) یا غیر سرکاری ٹیلی تھون؟

فہرست کا خانہ:

دستاویزی... یہ موجود ہے، ٹھیک ہے؟ یہ سچ ہے؟..

اس مضمون کے لیے نوٹوں کے ٹکڑے گزشتہ موسم گرما میں جمع کیے جانے لگے۔ یہ تمام وقت سرکاری ویب سائٹ پر https://core.telegram.org دستاویزات پرت 23 کے مطابق تھی، یعنی 2014 میں کہیں پھنس گئے (یاد رکھیں، اس وقت چینلز بھی نہیں تھے؟) یقینا، نظریہ میں، اس سے ہمیں 2014 میں اس وقت فعالیت کے ساتھ ایک کلائنٹ کو لاگو کرنے کی اجازت ملنی چاہیے تھی۔ لیکن اس حالت میں بھی، دستاویزات، اول، نامکمل، اور دوم، جگہوں پر اپنے آپ سے متصادم تھیں۔ ابھی ایک ماہ قبل، ستمبر 2019 میں، یہ تھا۔ اتفاق سے یہ پتہ چلا کہ سائٹ پر دستاویزات کی ایک بڑی تازہ کاری تھی، بالکل حالیہ پرت 105 کے لیے، ایک نوٹ کے ساتھ کہ اب ہر چیز کو دوبارہ پڑھنے کی ضرورت ہے۔ بے شک، بہت سے مضامین پر نظر ثانی کی گئی تھی، لیکن بہت سے غیر تبدیل شدہ رہے. لہذا، دستاویزات کے بارے میں نیچے دی گئی تنقید کو پڑھتے وقت، آپ کو ذہن میں رکھنا چاہیے کہ ان میں سے کچھ چیزیں اب متعلقہ نہیں ہیں، لیکن کچھ اب بھی کافی ہیں۔ سب کے بعد، جدید دنیا میں 5 سال صرف ایک طویل وقت نہیں ہے، لیکن بہت بہت سے اُس وقت سے (خاص طور پر اگر آپ اُس وقت سے ضائع شدہ اور بحال شدہ جیو چیٹ سائٹس کو مدنظر نہیں رکھتے ہیں)، اسکیم میں API طریقوں کی تعداد سو سے بڑھ کر ڈھائی سو سے زیادہ ہو گئی ہے!

ایک نوجوان مصنف کے طور پر کہاں سے شروع کریں؟

اس سے کوئی فرق نہیں پڑتا کہ آپ شروع سے لکھتے ہیں یا استعمال کرتے ہیں، مثال کے طور پر، ریڈی میڈ لائبریریاں Python کے لیے ٹیلی تھون یا پی ایچ پی کے لیے میڈلینکسی بھی صورت میں، آپ کو سب سے پہلے ضرورت ہو گی اپنی درخواست رجسٹر کریں۔ - پیرامیٹرز حاصل کریں api_id и api_hash (وہ لوگ جنہوں نے VKontakte API کے ساتھ کام کیا ہے وہ فوری طور پر سمجھتے ہیں) جس کے ذریعے سرور درخواست کی شناخت کرے گا۔ یہ ضروری ہے قانونی وجوہات کی بنا پر کریں، لیکن ہم اس بارے میں مزید بات کریں گے کہ لائبریری کے مصنفین اسے دوسرے حصے میں کیوں شائع نہیں کر سکتے۔ آپ ٹیسٹ کی اقدار سے مطمئن ہو سکتے ہیں، حالانکہ وہ بہت محدود ہیں - حقیقت یہ ہے کہ اب آپ رجسٹر کر سکتے ہیں صرف ایک ایپ، لہذا اس میں جلدی نہ کریں۔

اب، تکنیکی نقطہ نظر سے، ہمیں اس حقیقت میں دلچسپی ہونی چاہیے کہ رجسٹریشن کے بعد ہمیں ٹیلی گرام سے دستاویزات، پروٹوکول وغیرہ کی اپ ڈیٹس کے بارے میں اطلاعات موصول ہونی چاہئیں۔ یعنی، کوئی یہ سمجھ سکتا ہے کہ ڈاکوں والی سائٹ کو محض چھوڑ دیا گیا تھا اور خاص طور پر ان لوگوں کے ساتھ کام کرنا جاری رکھا گیا تھا جنہوں نے کلائنٹ بنانا شروع کیے تھے، کیونکہ یہ آسان ہے. لیکن نہیں، ایسا کچھ نہیں دیکھا گیا، کوئی اطلاع نہیں آئی۔

اور اگر آپ شروع سے لکھتے ہیں، تو حاصل شدہ پیرامیٹرز کو استعمال کرنا درحقیقت ابھی بہت دور ہے۔ اگرچہ https://core.telegram.org/ اور سب سے پہلے Getting Started میں ان کے بارے میں بات کرتا ہے، درحقیقت، آپ کو سب سے پہلے لاگو کرنا پڑے گا۔ ایم ٹی پروٹو پروٹوکول - لیکن اگر آپ کو یقین ہے OSI ماڈل کے مطابق ترتیب پروٹوکول کی عمومی وضاحت کے لیے صفحہ کے آخر میں، پھر یہ مکمل طور پر بیکار ہے۔

درحقیقت، MTProto سے پہلے اور بعد میں، ایک ساتھ کئی سطحوں پر (جیسا کہ OS کرنل میں کام کرنے والے غیر ملکی نیٹ ورکرز کہتے ہیں، پرت کی خلاف ورزی)، ایک بڑا، تکلیف دہ اور خوفناک موضوع راستے میں آ جائے گا...

بائنری سیریلائزیشن: TL (Type Language) اور اس کی اسکیم، اور تہیں، اور بہت سے دوسرے خوفناک الفاظ

یہ موضوع، درحقیقت، ٹیلیگرام کے مسائل کی کلید ہے۔ اور اگر آپ اس میں کھوج لگانے کی کوشش کریں گے تو بہت سارے خوفناک الفاظ ہوں گے۔

تو، یہاں خاکہ ہے. اگر یہ لفظ آپ کے ذہن میں آئے تو کہیے JSON اسکیما، آپ نے صحیح سوچا۔ مقصد ایک ہی ہے: منتقل شدہ ڈیٹا کے ممکنہ سیٹ کو بیان کرنے کے لیے کچھ زبان۔ یہ وہ جگہ ہے جہاں مماثلت ختم ہوتی ہے۔ اگر صفحہ سے ایم ٹی پروٹو پروٹوکول، یا آفیشل کلائنٹ کے سورس ٹری سے، ہم کچھ اسکیما کھولنے کی کوشش کریں گے، ہم کچھ اس طرح دیکھیں گے:

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;

اسے پہلی بار دیکھنے والا شخص بدیہی طور پر لکھی ہوئی چیزوں کے صرف ایک حصے کو پہچان سکے گا - ٹھیک ہے، یہ بظاہر ڈھانچے ہیں (حالانکہ نام کہاں ہے، بائیں یا دائیں طرف؟)، ان میں فیلڈز ہیں، جس کے بعد بڑی آنت کے بعد ایک قسم آتی ہے... شاید۔ یہاں زاویہ بریکٹ میں شاید ٹیمپلیٹس ہیں جیسے C++ میں (حقیقت میں، واقعی نہیں)۔ اور دیگر تمام علامتوں کا کیا مطلب ہے، سوالیہ نشان، فجائیہ کے نشان، فیصد، ہیش مارکس (اور ظاہر ہے کہ ان کا مطلب مختلف جگہوں پر مختلف چیزیں ہیں)، کبھی موجود اور کبھی نہیں، ہیکساڈیسیمل نمبرز - اور سب سے اہم بات یہ ہے کہ اس سے کیسے حاصل کیا جائے؟ صحیح ہے (جسے سرور کے ذریعہ مسترد نہیں کیا جائے گا) بائٹ اسٹریم؟ آپ کو دستاویزات پڑھنی ہوں گی۔ (ہاں، قریب میں JSON ورژن میں اسکیما کے لنکس موجود ہیں - لیکن اس سے یہ کوئی واضح نہیں ہوتا).

صفحہ کھولیں۔ بائنری ڈیٹا سیریلائزیشن اور مشروم اور مجرد ریاضی کی جادوئی دنیا میں غوطہ لگائیں، جو چوتھے سال میں متان سے ملتا جلتا ہے۔ حروف تہجی، قسم، قدر، کمبینیٹر، فنکشنل کمبینیٹر، نارمل فارم، کمپوزٹ ٹائپ، پولیمورفک قسم... اور یہ سب صرف پہلا صفحہ ہے! اگلا آپ کا منتظر ہے۔ TL زبان، جو، اگرچہ اس میں پہلے سے ہی ایک معمولی درخواست اور جواب کی مثال موجود ہے، لیکن زیادہ عام صورتوں کا جواب بالکل بھی فراہم نہیں کرتا ہے، جس کا مطلب ہے کہ آپ کو مزید آٹھ ایمبیڈڈ پر روسی سے انگریزی میں ترجمہ شدہ ریاضی کے دوبارہ بیان سے گزرنا پڑے گا۔ صفحات!

فنکشنل لینگویجز اور آٹومیٹک ٹائپ انفرنس سے واقف قارئین یقیناً اس زبان میں وضاحتی زبان کو دیکھیں گے، یہاں تک کہ مثال سے بھی، اتنا ہی زیادہ مانوس، اور کہہ سکتے ہیں کہ یہ اصولی طور پر برا نہیں ہے۔ اس پر اعتراضات یہ ہیں:

  • ہاں، مقصد اچھا لگتا ہے، لیکن افسوس، وہ حاصل نہیں کیا
  • روسی یونیورسٹیوں میں تعلیم آئی ٹی کی خصوصیات کے درمیان بھی مختلف ہوتی ہے - ہر ایک نے متعلقہ کورس نہیں کیا ہے۔
  • آخر میں، جیسا کہ ہم دیکھیں گے، عملی طور پر یہ ہے ضرورت نہیں، چونکہ بیان کردہ TL کا صرف ایک محدود ذیلی سیٹ استعمال ہوتا ہے۔

جیسا کہ کہا گیا ہے لیونرڈ چینل پر #perl FreeNode IRC نیٹ ورک میں، جس نے ٹیلیگرام سے میٹرکس تک ایک گیٹ کو لاگو کرنے کی کوشش کی (اقتباس کا ترجمہ میموری سے غلط ہے):

ایسا محسوس ہوتا ہے جیسے کسی کو پہلی بار تھیوری ٹائپ کرنے کے لیے متعارف کرایا گیا تھا، پرجوش ہو گیا تھا، اور اس کے ساتھ کھیلنے کی کوشش کرنے لگا تھا، واقعی اس کی پرواہ نہیں کی تھی کہ عملی طور پر اس کی ضرورت ہے یا نہیں۔

خود ہی دیکھ لیں، اگر کسی ابتدائی چیز کے طور پر ننگی قسموں (انٹ، لمبی، وغیرہ) کی ضرورت سوال نہیں اٹھاتی ہے - بالآخر انہیں دستی طور پر لاگو کیا جانا چاہیے - مثال کے طور پر، آئیے ان سے اخذ کرنے کی کوشش کرتے ہیں۔ ویکٹر. یعنی حقیقت میں سرنی، اگر آپ نتیجہ خیز چیزوں کو ان کے مناسب ناموں سے پکارتے ہیں۔

لیکن اس سے پہلے

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 میں فراہم نہیں کیے گئے ہیں۔

کیوں "کنسٹرکٹر" اور "پولیمورفک" اگر یہ OOP نہیں ہے؟ ٹھیک ہے، درحقیقت، کسی کے لیے OOP کی اصطلاحات میں اس کے بارے میں سوچنا آسان ہو جائے گا - ایک تجریدی کلاس کے طور پر ایک پولیمورفک قسم، اور کنسٹرکٹرز اس کی براہ راست نسل کی کلاسیں ہیں، اور final متعدد زبانوں کی اصطلاحات میں۔ اصل میں، بالکل، یہاں صرف مماثلت OO پروگرامنگ زبانوں میں حقیقی اوورلوڈ کنسٹرکٹر طریقوں کے ساتھ۔ چونکہ یہاں صرف اعداد و شمار کے ڈھانچے ہیں، اس لیے کوئی طریقہ نہیں ہے (اگرچہ افعال اور طریقوں کی مزید تفصیل سر میں یہ الجھن پیدا کرنے کے قابل ہے کہ وہ موجود ہیں، لیکن یہ ایک الگ بات ہے) - آپ کنسٹرکٹر کو ایک قدر کے طور پر سوچ سکتے ہیں۔ کونسا تعمیر کیا جا رہا ہے بائٹ اسٹریم پڑھتے وقت ٹائپ کریں۔

یہ کیسے ہوتا ہے؟ ڈیسیریلائزر، جو ہمیشہ 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، جس کا مطلب ہے "قدرتی نمبر"۔ یعنی، درحقیقت، غیر دستخط شدہ int، ویسے، واحد صورت ہے جب غیر دستخط شدہ نمبر حقیقی سرکٹس میں پائے جاتے ہیں۔ لہذا، اگلا سوالیہ نشان کے ساتھ ایک تعمیر ہے، جس کا مطلب ہے کہ یہ فیلڈ - یہ صرف اس وقت تار پر موجود ہوگا جب متعلقہ بٹ کو اس فیلڈ میں سیٹ کیا گیا ہو جس کا حوالہ دیا گیا ہو (تقریباً ایک ٹرنری آپریٹر کی طرح)۔ تو، آئیے فرض کریں کہ یہ بٹ سیٹ کیا گیا تھا، جس کا مطلب ہے کہ ہمیں مزید فیلڈ کو پڑھنے کی ضرورت ہے۔ Type، جس میں ہماری مثال میں 2 کنسٹرکٹرز ہیں۔ ایک خالی ہے (صرف شناخت کنندہ پر مشتمل ہے)، دوسرے کے پاس فیلڈ ہے۔ ids قسم کے ساتھ ids:Vector<long>.

آپ سوچ سکتے ہیں کہ ٹیمپلیٹس اور جنرک دونوں پیشہ یا جاوا میں ہیں۔ لیکن نہیں. تقریبا. یہ صرف حقیقی سرکٹس میں زاویہ بریکٹ استعمال کرنے کا معاملہ، اور یہ صرف ویکٹر کے لیے استعمال ہوتا ہے۔ بائٹ سٹریم میں، یہ خود ویکٹر کی قسم کے لیے 4 CRC32 بائٹس ہوں گے، ہمیشہ ایک جیسے، پھر 4 بائٹس - ارے عناصر کی تعداد، اور پھر خود یہ عناصر۔

اس میں اس حقیقت کو شامل کریں کہ سیریلائزیشن ہمیشہ 4 بائٹس کے الفاظ میں ہوتی ہے، تمام اقسام اس کے ملٹیلز ہیں - بلٹ ان اقسام کو بھی بیان کیا گیا ہے۔ bytes и string لمبائی کی دستی سیریلائزیشن کے ساتھ اور اس سیدھ کو 4 سے - ٹھیک ہے، ایسا لگتا ہے کہ یہ عام اور یہاں تک کہ نسبتا موثر لگتا ہے؟ اگرچہ TL کو ایک مؤثر بائنری سیریلائزیشن ہونے کا دعویٰ کیا جاتا ہے، ان کے ساتھ جہنم میں، کسی بھی چیز کی توسیع کے ساتھ، یہاں تک کہ بولین ویلیوز اور سنگل کریکٹر سٹرنگز 4 بائٹس تک، کیا JSON اب بھی زیادہ موٹا ہوگا؟ دیکھو، غیر ضروری فیلڈز کو بھی بٹ فلیگ کے ذریعے چھوڑا جا سکتا ہے، سب کچھ کافی اچھا ہے، اور مستقبل کے لیے بھی قابل توسیع، تو کیوں نہ بعد میں کنسٹرکٹر میں نئے اختیاری فیلڈز شامل کیے جائیں؟...

لیکن نہیں، اگر آپ میری مختصر تفصیل نہیں بلکہ مکمل دستاویزات پڑھیں، اور عمل درآمد کے بارے میں سوچیں۔ سب سے پہلے، کنسٹرکٹر کے CRC32 کا حساب اسکیم کے متن کی وضاحت کی نارمل لائن کے مطابق کیا جاتا ہے (اضافی وائٹ اسپیس کو ہٹا دیں، وغیرہ) - لہذا اگر کوئی نیا فیلڈ شامل کیا جاتا ہے، تو قسم کی تفصیل کی لائن بدل جائے گی، اور اس وجہ سے اس کی CRC32 اور ، اس کے نتیجے میں، سیریلائزیشن۔ اور پرانا کلائنٹ کیا کرے گا اگر اسے نئے جھنڈوں کے ساتھ کوئی فیلڈ موصول ہو، اور وہ نہیں جانتا کہ ان کے ساتھ آگے کیا کرنا ہے؟

دوسری بات، آئیے یاد رکھیں CRC32، جو یہاں بنیادی طور پر بطور استعمال ہوتا ہے۔ ہیش کے افعال منفرد طور پر اس بات کا تعین کرنے کے لیے کہ کس قسم کو (ڈی) سیریلائز کیا جا رہا ہے۔ یہاں ہمیں تصادم کے مسئلے کا سامنا ہے - اور نہیں، امکان 232 میں سے ایک نہیں ہے، بلکہ بہت زیادہ ہے۔ کس کو یاد ہے کہ CRC32 کو مواصلاتی چینل میں غلطیوں کا پتہ لگانے (اور درست کرنے) کے لیے ڈیزائن کیا گیا ہے، اور اس کے مطابق ان خصوصیات کو دوسروں کے نقصان کے لیے بہتر بناتا ہے؟ مثال کے طور پر، اسے بائٹس کو دوبارہ ترتیب دینے کی کوئی پرواہ نہیں ہے: اگر آپ دو لائنوں سے CRC32 کا حساب لگاتے ہیں، تو دوسری میں آپ پہلے 4 بائٹس کو اگلے 4 بائٹس کے ساتھ تبدیل کرتے ہیں - یہ ایک جیسا ہوگا۔ جب ہمارا ان پٹ لاطینی حروف تہجی (اور تھوڑا سا اوقاف) سے ٹیکسٹ سٹرنگ ہوتا ہے، اور یہ نام خاص طور پر بے ترتیب نہیں ہوتے ہیں، تو اس طرح کی دوبارہ ترتیب کا امکان بہت بڑھ جاتا ہے۔

ویسے کس نے چیک کیا وہاں کیا تھا؟ واقعی CRC32؟ ابتدائی سورس کوڈز میں سے ایک (والٹ مین سے پہلے بھی) ایک ہیش فنکشن تھا جس نے ہر کریکٹر کو 239 نمبر سے ضرب کیا، ان لوگوں کو بہت پیارا، ہا ہا!

آخر میں، ٹھیک ہے، ہم نے محسوس کیا کہ فیلڈ کی قسم کے ساتھ کنسٹرکٹرز Vector<int> и Vector<PolymorType> مختلف CRC32 ہوں گے۔ آن لائن کارکردگی کے بارے میں کیا خیال ہے؟ اور نظریاتی نقطہ نظر سے، کیا یہ قسم کا حصہ بن جاتا ہے؟? ہم کہتے ہیں کہ ہم دس ہزار نمبروں کی ایک صف کو پاس کرتے ہیں، اس کے ساتھ Vector<int> سب کچھ واضح ہے، لمبائی اور ایک اور 40000 بائٹس۔ اور اگر یہ Vector<Type2>، جو صرف ایک فیلڈ پر مشتمل ہے۔ int اور یہ قسم میں اکیلا ہے - کیا ہمیں 10000xabcdef0 34 بار اور پھر 4 بائٹس کو دہرانے کی ضرورت ہے int، یا زبان ہمارے لیے اسے کنسٹرکٹر سے آزاد کرنے کے قابل ہے۔ fixedVec اور 80000 بائٹس کے بجائے صرف 40000 دوبارہ منتقل کریں؟

یہ بالکل بھی بیکار نظریاتی سوال نہیں ہے - تصور کریں کہ آپ کو گروپ صارفین کی ایک فہرست موصول ہوئی ہے، جن میں سے ہر ایک کی شناخت، پہلا نام، آخری نام ہے - موبائل کنکشن پر منتقل کیے گئے ڈیٹا کی مقدار میں فرق نمایاں ہو سکتا ہے۔ یہ بالکل ٹیلیگرام سیریلائزیشن کی تاثیر ہے جس کی تشہیر ہمارے سامنے کی جاتی ہے۔

تو…

ویکٹر، جو کبھی جاری نہیں ہوا تھا۔

اگر آپ combinators اور اسی طرح کی تفصیل کے صفحات کو دیکھنے کی کوشش کرتے ہیں، تو آپ دیکھیں گے کہ ایک ویکٹر (اور یہاں تک کہ ایک میٹرکس بھی) باضابطہ طور پر کئی شیٹس کے ٹوپلس کے ذریعے آؤٹ پٹ ہونے کی کوشش کر رہا ہے۔ لیکن آخر میں وہ بھول جاتے ہیں، حتمی مرحلہ چھوڑ دیا جاتا ہے، اور ایک ویکٹر کی تعریف صرف دی جاتی ہے، جو ابھی تک کسی قسم سے منسلک نہیں ہے۔ کیا معاملہ ہے؟ زبانوں میں پروگرامنگخاص طور پر فنکشنل میں، ساخت کو بار بار بیان کرنا کافی عام ہے - اس کی سست تشخیص کے ساتھ مرتب کرنے والا سب کچھ خود سمجھے گا اور کرے گا۔ زبان میں ڈیٹا سیریلائزیشن جس چیز کی ضرورت ہے وہ ہے افادیت: یہ صرف بیان کرنا کافی ہے۔ فہرست، یعنی دو عناصر کی ساخت - پہلا ایک ڈیٹا عنصر ہے، دوسرا وہی ڈھانچہ ہے یا دم کے لیے خالی جگہ ہے (پیک (cons) لِسپ میں)۔ لیکن ظاہر ہے اس کی ضرورت ہوگی۔ ہر ایک عنصر اپنی قسم کو بیان کرنے کے لیے اضافی 4 بائٹس (TL میں کیس میں CRC32) خرچ کرتا ہے۔ ایک صف کو بھی آسانی سے بیان کیا جا سکتا ہے۔ مقررہ سائز، لیکن پہلے سے نامعلوم لمبائی کی ایک صف کی صورت میں، ہم ٹوٹ جاتے ہیں۔

لہذا، چونکہ TL کسی ویکٹر کو آؤٹ پٹ کرنے کی اجازت نہیں دیتا ہے، اس لیے اسے سائیڈ پر شامل کرنا پڑا۔ بالآخر دستاویزات کہتی ہیں:

سیریلائزیشن ہمیشہ ایک ہی کنسٹرکٹر "ویکٹر" کا استعمال کرتی ہے (const 0x1cb5c415 = crc32("ویکٹر t:Type # [ t ] = Vector t") جو قسم t کے متغیر کی مخصوص قدر پر منحصر نہیں ہے۔

اختیاری پیرامیٹر t کی قدر سیریلائزیشن میں شامل نہیں ہے کیونکہ یہ نتیجہ کی قسم سے ماخوذ ہے (ہمیشہ ڈیسیریلائزیشن سے پہلے جانا جاتا ہے)۔

قریب سے دیکھیں: vector {t:Type} # [ t ] = Vector t - لیکن کہیں نہیں یہ تعریف خود یہ نہیں کہتی کہ پہلا نمبر ویکٹر کی لمبائی کے برابر ہونا چاہیے! اور یہ کہیں سے نہیں آتا۔ یہ ایک ایسی چیز ہے جسے ذہن میں رکھنے اور اپنے ہاتھوں سے نافذ کرنے کی ضرورت ہے۔ کہیں اور، دستاویزات یہاں تک کہ ایمانداری سے ذکر کرتی ہیں کہ قسم حقیقی نہیں ہے:

ویکٹر ٹی پولیمورفک سیوڈوٹائپ ایک "قسم" ہے جس کی قدر کسی بھی قسم کی قدروں کی ترتیب ہے، یا تو باکسڈ یا برہ۔

... لیکن اس پر توجہ نہیں دیتا۔ جب آپ ریاضی کی کھینچا تانی سے تھک جاتے ہیں (شاید آپ کو یونیورسٹی کے کورس سے بھی معلوم ہوتا ہے)، ترک کرنے کا فیصلہ کرتے ہیں اور حقیقت میں اس کے ساتھ عملی طور پر کام کرنے کا طریقہ دیکھتے ہیں، تو آپ کے دماغ میں یہ تاثر باقی رہ جاتا ہے کہ یہ سنجیدہ ہے۔ بنیادی طور پر ریاضی، یہ واضح طور پر ٹھنڈے لوگوں (دو ریاضی دانوں - ACM فاتح) نے ایجاد کیا تھا، اور نہ صرف کسی نے۔ مقصد - دکھاوا کرنا - حاصل کر لیا گیا ہے۔

ویسے، تعداد کے بارے میں. آئیے آپ کو یاد دلاتے ہیں۔ # یہ ایک مترادف ہے natقدرتی نمبر:

قسم کے تاثرات ہیں (type-expr) اور عددی اظہار (nat-expr)۔ تاہم، ان کی تعریف اسی طرح کی گئی ہے۔

type-expr ::= expr
nat-expr ::= expr

لیکن گرامر میں انہیں اسی طرح بیان کیا گیا ہے، یعنی اس فرق کو دوبارہ یاد رکھنا چاہیے اور اسے ہاتھ سے نافذ کرنا چاہیے۔

ٹھیک ہے، ہاں، ٹیمپلیٹ کی اقسام (vector<int>, vector<User>) ایک مشترکہ شناخت کنندہ ہے (#1cb5c415) یعنی اگر آپ جانتے ہیں کہ کال کا اعلان کیا گیا ہے۔

users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;

پھر آپ کو صرف ایک ویکٹر کا نہیں بلکہ صارفین کے ایک ویکٹر کا انتظار ہے۔ زیادہ واضح طور پر، چاہئے انتظار کریں - اصلی کوڈ میں، ہر عنصر، اگر ننگی قسم نہیں ہے، ایک کنسٹرکٹر ہوگا، اور عمل درآمد میں اچھے طریقے سے اسے چیک کرنا ضروری ہوگا - لیکن ہمیں اس ویکٹر کے ہر عنصر میں بالکل بھیجا گیا تھا۔ اس قسم? کیا ہوگا اگر یہ کسی قسم کی پی ایچ پی تھی، جس میں ایک صف مختلف عناصر میں مختلف اقسام پر مشتمل ہو سکتی ہے؟

اس وقت آپ سوچنے لگتے ہیں - کیا ایسا TL ضروری ہے؟ ہو سکتا ہے کہ کارٹ کے لیے انسانی سیریلائزر کا استعمال ممکن ہو، وہی پروٹوبف جو اس وقت پہلے سے موجود تھا؟ یہ تھیوری تھی، آئیے پریکٹس دیکھیں۔

کوڈ میں موجودہ TL نفاذ

TL VKontakte کی گہرائیوں میں دوروف کے حصہ کی فروخت کے ساتھ مشہور واقعات سے پہلے بھی پیدا ہوا تھا اور (ضرورٹیلیگرام کی ترقی شروع ہونے سے پہلے ہی۔ اور اوپن سورس میں پہلے نفاذ کا ماخذ کوڈ آپ کو بہت ساری مضحکہ خیز بیساکھی مل سکتی ہے۔ اور زبان خود ٹیلیگرام میں اس سے کہیں زیادہ مکمل طور پر نافذ کی گئی تھی۔ مثال کے طور پر، اسکیم میں ہیش کا استعمال بالکل نہیں کیا جاتا ہے (جس کا مطلب ہے ایک بلٹ ان سیڈو ٹائپ (جیسے ویکٹر) منحرف رویے کے ساتھ)۔ یا

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 لکھ سکتے ہیں، لیکن آپ کو الفا، بیٹا لکھنا چاہیے... لیکن 8 پیرامیٹرز سے زیادہ نہیں، یہیں سے فنتاسی ختم ہوتی ہے۔ ایسا لگتا ہے کہ کسی زمانے میں سینٹ پیٹرزبرگ میں کچھ مکالمے ہوئے تھے:

-- Надо сделать в TL шаблоны
-- Бл... Ну пусть параметры зовут альфа, бета,... Какие там ещё буквы есть... О, тэта!
-- Грамматика? Ну потом напишем

-- Смотрите, какой я синтаксис придумал для шаблонов и вектора!
-- Ты долбанулся, как мы это парсить будем?
-- Да не ссыте, он там один в схеме, захаркодить -- и ок

لیکن یہ "عام طور پر" TL کے پہلے شائع شدہ نفاذ کے بارے میں تھا۔ آئیے خود ٹیلیگرام کلائنٹس میں نفاذ پر غور کرتے ہیں۔

واسیلی کے لیے لفظ:

واسیلی، [09.10.18 17:07] سب سے زیادہ، گدا گرم ہے کیونکہ انہوں نے تجرید کا ایک گروپ بنایا، اور پھر ان پر ایک بولٹ مارا، اور کوڈ جنریٹر کو بیساکھیوں سے ڈھانپ دیا۔
نتیجے کے طور پر، سب سے پہلے dock pilot.jpg سے
پھر dzhekichan.webp کوڈ سے

یقیناً، الگورتھم اور ریاضی سے واقف لوگوں سے، ہم یہ توقع کر سکتے ہیں کہ انہوں نے Aho، Ullmann کو پڑھا ہے، اور وہ ان ٹولز سے واقف ہیں جو اپنے DSL کمپائلرز کو لکھنے کے لیے دہائیوں کے دوران صنعت میں ڈی فیکٹو سٹینڈرڈ بن چکے ہیں، ٹھیک ہے؟

کی طرف سے telegram-cli Vitaly Valtman ہے، جیسا کہ TLO فارمیٹ کے اس کی (cli) حدود سے باہر ہونے سے سمجھا جا سکتا ہے، ٹیم کا ایک رکن - اب TL پارسنگ کے لیے ایک لائبریری مختص کی گئی ہے۔ الگ الگاس کا کیا تاثر ہے TL تجزیہ کار؟ ..

16.12 04:18 واسیلی: میرے خیال میں کسی نے lex+yacc میں مہارت حاصل نہیں کی
16.12 04:18 واسیلی: میں اسے دوسری صورت میں بیان نہیں کر سکتا
16.12 04:18 واسیلی: ٹھیک ہے، یا انہیں VK میں لائنوں کی تعداد کے لیے ادائیگی کی گئی تھی۔
16.12 04:19 واسیلی: 3k+ لائنز وغیرہ۔<censored> تجزیہ کار کے بجائے

شاید ایک استثناء؟ آئیے دیکھتے ہیں کہ کیسے کرتا ہے یہ آفیشل کلائنٹ ہے - ٹیلیگرام ڈیسک ٹاپ:

    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);

Python میں 1100+ لائنیں، ریگولر ایکسپریشنز کے ایک جوڑے + ایک ویکٹر جیسے خصوصی کیسز، جو یقیناً اسکیم میں قرار دیا گیا ہے جیسا کہ اسے TL نحو کے مطابق ہونا چاہیے، لیکن انہوں نے اس کو پارس کرنے کے لیے اس نحو پر انحصار کیا... سوال یہ پیدا ہوتا ہے کہ یہ سب معجزہ کیوں تھا؟иیہ زیادہ پرتوں والا ہے اگر کوئی بھی دستاویزات کے مطابق اس کی تجزیہ نہیں کر رہا ہے؟!

ویسے... یاد ہے ہم نے CRC32 چیکنگ کے بارے میں بات کی تھی؟ لہذا، ٹیلیگرام ڈیسک ٹاپ کوڈ جنریٹر میں ان اقسام کے لیے مستثنیات کی ایک فہرست ہے جس میں CRC32 کا حساب لگایا گیا ہے۔ ملتا جلتا نہیں ہے خاکہ میں اشارہ کے ساتھ!

واسیلی، [18.12/22 49:XNUMX] اور یہاں میں سوچوں گا کہ کیا ایسی TL کی ضرورت ہے
اگر میں متبادل نفاذ کے ساتھ گڑبڑ کرنا چاہتا ہوں، تو میں لائن بریک ڈالنا شروع کر دوں گا، نصف پارسر ملٹی لائن ڈیفینیشنز پر ٹوٹ جائیں گے۔
tdesktop، تاہم، بھی

ون لائنر کے بارے میں نقطہ یاد رکھیں، ہم تھوڑی دیر بعد اس پر واپس جائیں گے.

ٹھیک ہے، ٹیلیگرام-کلی غیر سرکاری ہے، ٹیلیگرام ڈیسک ٹاپ آفیشل ہے، لیکن دوسروں کا کیا ہوگا؟ کون جانتا ہے؟... اینڈرائیڈ کلائنٹ کوڈ میں کوئی سکیما پارسر بالکل نہیں تھا (جو اوپن سورس کے بارے میں سوالات اٹھاتا ہے، لیکن یہ دوسرے حصے کے لیے ہے)، لیکن کوڈ کے کئی دوسرے مضحکہ خیز ٹکڑے تھے، لیکن ان پر مزید ذیل میں ذیلی سیکشن.

سیریلائزیشن عملی طور پر کون سے دوسرے سوالات اٹھاتی ہے؟ مثال کے طور پر، انہوں نے بہت ساری چیزیں کیں، یقیناً، بٹ فیلڈز اور مشروط فیلڈز کے ساتھ:

واسیلی: flags.0? true
اس کا مطلب ہے کہ فیلڈ موجود ہے اور اگر جھنڈا سیٹ کیا گیا ہے تو یہ سچ ہے۔

واسیلی: flags.1? int
اس کا مطلب ہے کہ فیلڈ موجود ہے اور اسے ڈی سیریلائز کرنے کی ضرورت ہے۔

واسیلی: گدا، تم کیا کر رہے ہو اس کی فکر نہ کرو!
واسیلی: دستاویز میں کہیں یہ ذکر ہے کہ یہ سچ ہے کہ بالکل صفر لمبائی کی قسم ہے، لیکن ان کی دستاویز سے کچھ بھی جمع کرنا ناممکن ہے۔
واسیلی: اوپن سورس کے نفاذ میں بھی ایسا نہیں ہے، لیکن بیساکھیوں اور سپورٹوں کا ایک گروپ موجود ہے۔

ٹیلی تھون کے بارے میں کیا خیال ہے؟ MTProto کے موضوع کو آگے دیکھتے ہوئے، ایک مثال - دستاویزات میں ایسے ٹکڑے ہیں، لیکن نشان % اسے صرف "دی گئی ننگی قسم کے مطابق" کے طور پر بیان کیا گیا ہے، یعنی ذیل کی مثالوں میں یا تو کوئی غلطی ہے یا کچھ غیر دستاویزی:

واسیلی، [22.06.18 18:38] ایک جگہ:

msg_container#73f1f8dc messages:vector message = MessageContainer;

ایک مختلف میں:

msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;

اور یہ دو بڑے فرق ہیں، حقیقی زندگی میں کسی نہ کسی طرح کا ننگا ویکٹر آتا ہے۔

میں نے ایک ننگی ویکٹر تعریف نہیں دیکھی ہے اور ایک میں نہیں آیا ہوں۔

تجزیہ ٹیلی تھون میں ہاتھ سے لکھا جاتا ہے۔

اس کے خاکے میں تعریف بیان کی گئی ہے۔ msg_container

ایک بار پھر، سوال % کے بارے میں رہتا ہے۔ یہ بیان نہیں کیا گیا ہے۔

Vadim Goncharov، [22.06.18 19:22] اور tdesktop میں؟

واسیلی، [22.06.18 19:23] لیکن ریگولر انجنوں پر ان کے TL پارسر غالباً یہ بھی نہیں کھائیں گے۔

// parsed manually

TL ایک خوبصورت خلاصہ ہے، کوئی بھی اسے مکمل طور پر نافذ نہیں کرتا ہے۔

اور % اسکیم کے ان کے ورژن میں نہیں ہے۔

لیکن یہاں دستاویزات خود سے متصادم ہیں، لہذا idk

یہ گرامر میں پایا گیا تھا، وہ محض الفاظ کی وضاحت کرنا بھول سکتے تھے۔

آپ نے 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
                [wd<>#.?!]+  # 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
            ([wd<>#.?]+)     # 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 کے فریم ورک کے اندر ایک پوسٹولٹ ہے۔ اس کی بنیاد پر، زبان کو ہمارے لیے ہر طرح کے چیک فراہم کرنا چاہیے۔ ٹھیک ہے، ٹھیک ہے، شاید وہ خود نہیں، لیکن عمل درآمد، لیکن اسے کم از کم ان کی وضاحت کرنا چاہئے. اور ہم کس قسم کے مواقع چاہتے ہیں؟

سب سے پہلے، رکاوٹیں. یہاں ہم فائلوں کو اپ لوڈ کرنے کے لیے دستاویزات میں دیکھتے ہیں:

فائل کے بائنری مواد کو پھر حصوں میں تقسیم کیا جاتا ہے۔ تمام حصوں کا سائز ایک ہی ہونا چاہیے ( part_size ) اور درج ذیل شرائط کو پورا کرنا ضروری ہے:

  • part_size % 1024 = 0 (1KB سے تقسیم)
  • 524288 % part_size = 0 (512KB حصہ_سائز کے لحاظ سے یکساں طور پر قابل تقسیم ہونا چاہیے)

آخری حصے کو ان شرائط کو پورا کرنے کی ضرورت نہیں ہے، بشرطیکہ اس کا سائز part_size سے کم ہو۔

ہر حصے کا ایک ترتیب نمبر ہونا چاہیے، فائل_پارٹ0 سے 2,999 تک کی قدر کے ساتھ۔

فائل کو تقسیم کرنے کے بعد آپ کو اسے سرور پر محفوظ کرنے کا طریقہ منتخب کرنا ہوگا۔ استعمال کریں۔ upload.saveBigFilePart فائل کا فل سائز 10 ایم بی سے زیادہ ہونے کی صورت میں اور upload.saveFilePart چھوٹی فائلوں کے لیے۔
مندرجہ ذیل ڈیٹا ان پٹ کی غلطیوں میں سے ایک واپس آ سکتی ہے:

  • FILE_PARTS_INVALID — حصوں کی غلط تعداد۔ قدر کے درمیان نہیں ہے۔ 1..3000

کیا اس میں سے کوئی خاکہ میں ہے؟ کیا یہ کسی طرح TL کا استعمال کرتے ہوئے قابل اظہار ہے؟ نہیں. لیکن معاف کیجئے گا، یہاں تک کہ دادا کا ٹربو پاسکل بھی مخصوص اقسام کو بیان کرنے کے قابل تھا۔ حدود. اور وہ ایک اور چیز جانتا تھا، جسے اب زیادہ جانا جاتا ہے۔ enum - ایک قسم جس میں قدروں کی ایک مقررہ (چھوٹی) تعداد کی گنتی ہوتی ہے۔ C - عددی جیسی زبانوں میں، نوٹ کریں کہ اب تک ہم نے صرف اقسام کے بارے میں بات کی ہے۔ نمبر. لیکن یہاں ارے، سٹرنگز بھی ہیں... مثال کے طور پر، یہ بتانا اچھا ہو گا کہ اس سٹرنگ میں صرف ایک فون نمبر ہو سکتا ہے، ٹھیک ہے؟

اس میں سے کوئی بھی TL میں نہیں ہے۔ لیکن وہاں ہے، مثال کے طور پر، JSON اسکیما میں۔ اور اگر کوئی اور 512 KB کی تقسیم کے بارے میں بحث کر سکتا ہے، کہ اسے ابھی بھی کوڈ میں چیک کرنے کی ضرورت ہے، تو یقینی بنائیں کہ کلائنٹ صرف نہیں کر سکا حد سے باہر ایک نمبر بھیجیں۔ 1..3000 (اور متعلقہ غلطی پیدا نہیں ہو سکتی تھی) یہ ممکن تھا، ٹھیک ہے؟

ویسے، غلطیوں اور واپسی کی اقدار کے بارے میں۔ یہاں تک کہ جنہوں نے TL کے ساتھ کام کیا ہے وہ اپنی آنکھیں دھندلا دیتے ہیں - یہ فوری طور پر ہم پر نہیں ہوا۔ ہر ایک TL میں ایک فنکشن دراصل نہ صرف بیان کردہ واپسی کی قسم کو واپس کر سکتا ہے بلکہ ایک غلطی بھی۔ لیکن خود TL کا استعمال کرتے ہوئے کسی بھی طرح سے اس کا اندازہ نہیں لگایا جا سکتا۔ یقینا، یہ پہلے ہی واضح ہے اور عملی طور پر کسی چیز کی ضرورت نہیں ہے (حالانکہ حقیقت میں، RPC مختلف طریقوں سے کیا جا سکتا ہے، ہم اس پر بعد میں واپس آئیں گے) - لیکن ریاضی کے خلاصہ کی اقسام کے تصورات کی پاکیزگی کا کیا ہوگا؟ آسمانی دنیا سے؟.. میں نے ٹگ اٹھایا - تو اس سے ملاؤ۔

اور آخر میں، پڑھنے کی اہلیت کے بارے میں کیا خیال ہے؟ ٹھیک ہے، وہاں، عام طور پر، میں چاہوں گا تفصیل کیا یہ اسکیما میں ٹھیک ہے (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. یا اس کے برعکس. لیکن اس نے کام کیا! یعنی سرور نے قسم کی پرواہ نہیں کی۔ یہ کیسے ہو سکتا ہے؟ ٹیلیگرام-کلی کے کوڈ کے ٹکڑوں کے ذریعے ہمیں جواب دیا جا سکتا ہے:

  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);

دوسرے الفاظ میں، یہ وہ جگہ ہے جہاں سیریلائزیشن کی جاتی ہے۔ دستی طور پر، کوڈ پیدا نہیں ہوا! ہوسکتا ہے کہ سرور کو اسی طرح لاگو کیا گیا ہو؟... اصولی طور پر، اگر ایک بار کیا جائے تو یہ کام کرے گا، لیکن بعد میں اپ ڈیٹس کے دوران اس کی حمایت کیسے کی جاسکتی ہے؟ کیا اسکیم اسی لیے ایجاد ہوئی؟ اور یہاں ہم اگلے سوال کی طرف بڑھتے ہیں۔

ورژننگ تہیں

اسکیمیٹک ورژن کو پرتیں کیوں کہا جاتا ہے صرف شائع شدہ اسکیمیٹکس کی تاریخ کی بنیاد پر قیاس کیا جاسکتا ہے۔ بظاہر، پہلے مصنفین کا خیال تھا کہ بنیادی چیزیں غیر تبدیل شدہ اسکیم کا استعمال کرتے ہوئے کی جا سکتی ہیں، اور صرف جہاں ضروری ہو، مخصوص درخواستوں کے لیے، اس بات کی نشاندہی کرتے ہیں کہ وہ ایک مختلف ورژن کا استعمال کرتے ہوئے کیے جا رہے ہیں۔ اصولی طور پر، یہاں تک کہ ایک اچھا خیال - اور نیا ہوگا، جیسا کہ یہ تھا، "مخلوط"، پرانے کے اوپر پرتوں والا۔ لیکن آئیے دیکھتے ہیں کہ یہ کیسے ہوا۔ یہ سچ ہے کہ میں اسے شروع سے ہی نہیں دیکھ سکتا تھا - یہ مضحکہ خیز ہے، لیکن بیس پرت کا خاکہ صرف موجود نہیں ہے۔ پرتیں 2 سے شروع ہوئیں۔ دستاویزات ہمیں ایک خاص TL خصوصیت کے بارے میں بتاتی ہیں:

اگر کوئی کلائنٹ لیئر 2 کو سپورٹ کرتا ہے، تو درج ذیل کنسٹرکٹر کو استعمال کرنا چاہیے:

invokeWithLayer2#289dd1f6 {X:Type} query:!X = X;

عملی طور پر، اس کا مطلب ہے کہ ہر API کال سے پہلے، قدر کے ساتھ ایک int 0x289dd1f6 طریقہ نمبر سے پہلے شامل کرنا ضروری ہے۔

نارمل لگتا ہے۔ لیکن آگے کیا ہوا؟ پھر ظاہر ہوا۔

invokeWithLayer3#b7475268 query:!X = X;

تو آگے کیا ہے؟ جیسا کہ آپ اندازہ لگا سکتے ہیں،

invokeWithLayer4#dea0d430 query:!X = X;

مضحکہ خیز؟ نہیں، ہنسنا بہت جلدی ہے، اس حقیقت کے بارے میں سوچیں۔ ہر کسی اور پرت کی درخواست کو اس طرح کے ایک خاص قسم میں لپیٹنے کی ضرورت ہے - اگر وہ سب آپ کے لیے مختلف ہیں، تو آپ ان میں فرق کیسے کر سکتے ہیں؟ اور سامنے صرف 4 بائٹس شامل کرنا ایک بہت ہی موثر طریقہ ہے۔ تو،

invokeWithLayer5#417a57ae query:!X = X;

لیکن یہ ظاہر ہے کہ کچھ عرصے بعد یہ ایک قسم کا بچنالیا بن جائے گا۔ اور حل آیا:

اپ ڈیٹ: پرت 9 سے شروع، مددگار طریقے invokeWithLayerN کے ساتھ صرف استعمال کیا جا سکتا ہے initConnection

ہورے! 9 ورژن کے بعد، ہم آخر کار اس پر پہنچے جو 80 کی دہائی میں انٹرنیٹ پروٹوکولز میں کیا گیا تھا - کنکشن کے آغاز میں ایک بار ورژن پر اتفاق کرتے ہوئے!

تو آگے کیا ہے؟...

invokeWithLayer10#39620c41 query:!X = X;
...
invokeWithLayer18#1c900537 query:!X = X;

لیکن اب آپ ہنس سکتے ہیں۔ صرف ایک اور 9 تہوں کے بعد، آخر کار ورژن نمبر کے ساتھ ایک عالمگیر کنسٹرکٹر شامل کیا گیا، جس کو کنکشن کے آغاز میں صرف ایک بار کال کرنے کی ضرورت ہے، اور پرتوں کا مفہوم غائب ہو گیا، اب یہ صرف ایک مشروط ورژن ہے، جیسے ہر جگہ. مشکل حل ہو گئی.

بالکل؟...

واسیلی، [16.07.18 14:01] جمعہ کو بھی میں نے سوچا:
ٹیلی سرور بغیر کسی درخواست کے واقعات بھیجتا ہے۔ درخواستوں کو InvokeWithLayer میں لپیٹنا ضروری ہے۔ سرور اپ ڈیٹس کو لپیٹ نہیں کرتا؛ جوابات اور اپ ڈیٹس کو لپیٹنے کے لیے کوئی ڈھانچہ نہیں ہے۔

وہ. کلائنٹ اس پرت کی وضاحت نہیں کر سکتا جس میں وہ اپ ڈیٹس چاہتا ہے۔

Vadim Goncharov, [16.07.18 14:02] کیا InvokeWithLayer اصولی طور پر ایک بیساکھی نہیں ہے؟

واسیلی، [16.07.18 14:02] یہ واحد راستہ ہے۔

Vadim Goncharov, [16.07.18 14:02] جس کا بنیادی مطلب سیشن کے آغاز میں پرت پر اتفاق ہونا چاہیے۔

ویسے، یہ مندرجہ ذیل ہے کہ کلائنٹ ڈاؤن گریڈ فراہم نہیں کیا گیا ہے

اپ ڈیٹس، یعنی قسم Updates اسکیم میں، سرور کلائنٹ کو API کی درخواست کے جواب میں نہیں بلکہ آزادانہ طور پر بھیجتا ہے جب کوئی واقعہ پیش آتا ہے۔ یہ ایک پیچیدہ موضوع ہے جس پر کسی اور پوسٹ میں بحث کی جائے گی، لیکن فی الحال یہ جاننا ضروری ہے کہ سرور اپڈیٹس کو محفوظ کرتا ہے تب بھی جب کلائنٹ آف لائن ہو۔

اس طرح، اگر آپ لپیٹنے سے انکار کرتے ہیں ہر ایک پیکیج کو اس کے ورژن کی نشاندہی کرنے کے لئے، یہ منطقی طور پر درج ذیل ممکنہ مسائل کی طرف جاتا ہے:

  • سرور کلائنٹ کو اپ ڈیٹ بھیجتا ہے اس سے پہلے کہ کلائنٹ یہ بتا دے کہ وہ کس ورژن کو سپورٹ کرتا ہے۔
  • کلائنٹ کو اپ گریڈ کرنے کے بعد مجھے کیا کرنا چاہیے؟
  • کون گارنٹیکہ لیئر نمبر کے بارے میں سرور کی رائے اس عمل کے دوران تبدیل نہیں ہوگی؟

کیا آپ کے خیال میں یہ خالصتاً نظریاتی قیاس ہے، اور عملی طور پر ایسا نہیں ہو سکتا، کیونکہ سرور درست لکھا گیا ہے (کم از کم، اس کی اچھی طرح جانچ کی گئی ہے)؟ ہا! اس سے کوئی فرق نہیں پڑتا ہے کہ یہ کیسے ہے!

یہ بالکل وہی ہے جس میں ہم اگست میں بھاگے تھے۔ 14 اگست کو یہ پیغامات تھے کہ ٹیلی گرام سرورز پر کچھ اپ ڈیٹ کیا جا رہا ہے... اور پھر لاگز میں:

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 پر کام کیا ہے۔ ہم لاگز کو غور سے دیکھتے ہیں - دو مختلف اسکیموں کے شناخت کنندگان ہیں!

شاید مسئلہ خالصتاً ہمارے غیر سرکاری مؤکل میں ہے؟ نہیں۔

ٹیلیگرام کے پروٹوکول اور تنظیمی طریقوں پر تنقید۔ حصہ 1، تکنیکی: ایک کلائنٹ کو شروع سے لکھنے کا تجربہ - TL, MT

گوگل نے ظاہر کیا کہ غیر سرکاری کلائنٹس میں سے ایک کے ساتھ بھی ایسا ہی مسئلہ پیش آچکا تھا، لیکن پھر ورژن نمبرز اور، اس کے مطابق، مفروضے مختلف تھے...

تو ہمیں کیا کرنا چاہیے؟ واسیلی اور میں الگ ہو گئے: اس نے سرکٹ کو 91 پر اپ ڈیٹ کرنے کی کوشش کی، میں نے کچھ دن انتظار کرنے اور 73 پر آزمانے کا فیصلہ کیا۔ دونوں طریقوں نے کام کیا، لیکن چونکہ وہ تجرباتی ہیں، اس لیے آپ کو اس بات کی کوئی سمجھ نہیں ہے کہ آپ کو کتنے ورژن اوپر یا نیچے کی ضرورت ہے۔ چھلانگ لگانے کے لیے، یا آپ کو کتنی دیر انتظار کرنے کی ضرورت ہے۔

بعد میں میں صورتحال کو دوبارہ پیش کرنے میں کامیاب ہوگیا: ہم کلائنٹ کو لانچ کرتے ہیں، اسے آف کرتے ہیں، سرکٹ کو دوسری پرت میں دوبارہ مرتب کرتے ہیں، دوبارہ شروع کرتے ہیں، مسئلہ کو دوبارہ پکڑتے ہیں، پچھلے والے پر واپس آتے ہیں - افوہ، سرکٹ سوئچنگ کی کوئی مقدار نہیں اور کلائنٹ دوبارہ شروع ہوتا ہے۔ چند منٹ مدد کریں گے. آپ کو مختلف پرتوں سے ڈیٹا ڈھانچے کا مرکب ملے گا۔

وضاحت؟ جیسا کہ آپ مختلف بالواسطہ علامات سے اندازہ لگا سکتے ہیں، سرور مختلف مشینوں پر مختلف اقسام کے بہت سے عمل پر مشتمل ہوتا ہے۔ غالباً، سرور جو "بفرنگ" کے لیے ذمہ دار ہے، وہ اس قطار میں ڈالتا ہے جو اس کے اعلیٰ افسران نے اسے دیا تھا، اور انہوں نے اسے اس اسکیم میں دیا جو نسل کے وقت موجود تھی۔ اور جب تک یہ قطار "سڑی" نہ ہو، اس کے بارے میں کچھ نہیں کیا جا سکتا تھا۔

شاید... لیکن یہ ایک خوفناک بیساکھی ہے؟!.. نہیں، پاگل خیالات کے بارے میں سوچنے سے پہلے، آئیے آفیشل کلائنٹس کے کوڈ کو دیکھتے ہیں۔ اینڈرائیڈ ورژن میں ہمیں کوئی TL پارسر نہیں ملتا ہے، لیکن ہمیں (de) سیریلائزیشن کے ساتھ ایک بھاری فائل (GitHub اسے چھونے سے انکار کرتا ہے) تلاش کرتے ہیں۔ یہاں کوڈ کے ٹکڑے ہیں:

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

دوستو، کیا آپ یہ بھی فیصلہ نہیں کر سکتے کہ ایک پرت کے اندر کیا ہے؟! ٹھیک ہے، ٹھیک ہے، چلو کہتے ہیں کہ "دو" کو ایک غلطی کے ساتھ جاری کیا گیا تھا، ٹھیک ہے، ایسا ہوتا ہے، لیکن تین؟.. فورا، وہی ریک دوبارہ؟ یہ کیسی فحاشی ہے، معذرت؟...

ٹیلیگرام ڈیسک ٹاپ کے سورس کوڈ میں، ویسے بھی، ایسا ہی ہوتا ہے - اگر ایسا ہے تو، اسکیم کے لیے لگاتار کئی کمٹ اس کی پرت نمبر کو تبدیل نہیں کرتے، بلکہ کچھ ٹھیک کرتے ہیں۔ ایسے حالات میں جہاں اسکیم کے لیے ڈیٹا کا کوئی سرکاری ذریعہ نہیں ہے، اسے سرکاری کلائنٹ کے سورس کوڈ کے علاوہ کہاں سے حاصل کیا جاسکتا ہے؟ اور اگر آپ اسے وہاں سے لیتے ہیں، تو آپ اس بات کا یقین نہیں کر سکتے کہ سکیم مکمل طور پر درست ہے جب تک کہ آپ تمام طریقوں کی جانچ نہیں کر لیتے۔

یہ بھی کیسے آزمایا جا سکتا ہے؟ مجھے امید ہے کہ یونٹ، فنکشنل اور دیگر ٹیسٹ کے شائقین تبصروں میں اشتراک کریں گے۔

ٹھیک ہے، آئیے کوڈ کے ایک اور ٹکڑے کو دیکھتے ہیں:

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;

یہ تبصرہ "دستی طور پر بنایا گیا" بتاتا ہے کہ اس فائل کا صرف ایک حصہ دستی طور پر لکھا گیا تھا (کیا آپ دیکھ بھال کے پورے ڈراؤنے خواب کا تصور کر سکتے ہیں؟)، اور باقی مشین سے تیار کیا گیا تھا۔ تاہم، پھر ایک اور سوال پیدا ہوتا ہے - کہ ذرائع دستیاب ہیں؟ مکمل طور پر نہیں (لینکس کرنل میں ایک لا جی پی ایل بلابس)، لیکن یہ پہلے ہی دوسرے حصے کا موضوع ہے۔

لیکن کافی ہے۔ آئیے اس پروٹوکول کی طرف بڑھتے ہیں جس کے اوپر یہ ساری سیریلائزیشن چلتی ہے۔

ایم ٹی پروٹو

تو، چلو کھولتے ہیں عمومی وضاحت и پروٹوکول کی تفصیلی وضاحت اور پہلی چیز جس پر ہم ٹھوکر کھاتے ہیں وہ ہے اصطلاحات۔ اور ہر چیز کی کثرت کے ساتھ۔ عام طور پر، یہ ٹیلیگرام کی ملکیتی خصوصیت معلوم ہوتی ہے - مختلف جگہوں پر چیزوں کو مختلف طریقے سے کال کرنا، یا ایک لفظ کے ساتھ مختلف چیزوں کو، یا اس کے برعکس (مثال کے طور پر، ایک اعلیٰ سطحی API میں، اگر آپ کو ایک اسٹیکر پیک نظر آتا ہے، تو ایسا نہیں ہے۔ آپ نے کیا سوچا)۔

مثال کے طور پر، "پیغام" اور "سیشن" کا مطلب یہاں عام ٹیلیگرام کلائنٹ انٹرفیس سے کچھ مختلف ہے۔ ٹھیک ہے، پیغام کے ساتھ سب کچھ واضح ہے، اس کی تشریح OOP کی اصطلاحات میں کی جا سکتی ہے، یا صرف لفظ "پیکٹ" کہا جا سکتا ہے - یہ ایک کم، ٹرانسپورٹ لیول ہے، یہاں انٹرفیس کی طرح پیغامات نہیں ہیں، بہت سارے سروس میسجز ہیں۔ . لیکن سیشن... لیکن پہلی چیزیں پہلے۔

ٹرانسپورٹ پرت۔

پہلی چیز ٹرانسپورٹ ہے۔ وہ ہمیں 5 اختیارات کے بارے میں بتائیں گے:

  • ٹی سی پی
  • ویبسکیٹ
  • HTTPS پر ویب ساکٹ
  • HTTP
  • HTTPS

واسیلی، [15.06.18 15:04] یو ڈی پی ٹرانسپورٹ بھی ہے، لیکن یہ دستاویزی نہیں ہے

اور TCP تین مختلف حالتوں میں

پہلا ٹی سی پی پر UDP سے ملتا جلتا ہے، ہر پیکٹ میں ایک ترتیب نمبر اور crc شامل ہوتا ہے۔
کارٹ پر دستاویزات پڑھنا اتنا تکلیف دہ کیوں ہے؟

ٹھیک ہے، یہ اب وہاں ہے TCP پہلے ہی 4 مختلف حالتوں میں ہے۔:

  • مختصر
  • انٹرمیڈیٹ
  • بولڈ انٹرمیڈیٹ
  • مکمل

ٹھیک ہے، ٹھیک ہے، پیڈڈ انٹرمیڈیٹ برائے MTProxy، اسے بعد میں معروف واقعات کی وجہ سے شامل کیا گیا۔ لیکن جب آپ ایک کے ساتھ مل سکتے ہیں تو دو اور ورژن (مجموعی طور پر تین) کیوں؟ چاروں بنیادی طور پر صرف اس بات میں مختلف ہیں کہ مین ایم ٹی پروٹو کی لمبائی اور پے لوڈ کو کیسے ترتیب دیا جائے، جس پر مزید بحث کی جائے گی:

  • مختصر میں یہ 1 یا 4 بائٹس ہے، لیکن 0xef نہیں، پھر باڈی
  • انٹرمیڈیٹ میں یہ 4 بائٹس کی لمبائی اور ایک فیلڈ ہے، اور کلائنٹ کو پہلی بار بھیجنا ضروری ہے۔ 0xeeeeeeee یہ بتانے کے لیے کہ یہ انٹرمیڈیٹ ہے۔
  • نیٹ ورکر کے نقطہ نظر سے، مکمل طور پر سب سے زیادہ لت لگانے والا: لمبائی، ترتیب نمبر، اور وہ نہیں جو بنیادی طور پر MTProto، body، CRC32 ہے۔ ہاں، یہ سب TCP کے اوپر ہے۔ جو ہمیں ایک ترتیب وار بائٹ سٹریم کی شکل میں قابل اعتماد ٹرانسپورٹ فراہم کرتا ہے؛ کسی ترتیب کی ضرورت نہیں ہے، خاص طور پر چیکسم۔ ٹھیک ہے، اب کوئی مجھ پر اعتراض کرے گا کہ TCP میں 16 بٹ چیکسم ہے، اس لیے ڈیٹا کرپٹ ہوتا ہے۔ بہت اچھا، لیکن ہمارے پاس اصل میں ایک کرپٹوگرافک پروٹوکول ہے جس میں 16 بائٹس سے زیادہ لمبی ہیشز ہیں، یہ تمام غلطیاں - اور اس سے بھی زیادہ - اعلی سطح پر SHA کی مماثلت سے پکڑی جائیں گی۔ اس کے اوپر CRC32 میں کوئی نقطہ نہیں ہے۔

آئیے ابریجڈ کا موازنہ کریں، جس میں لمبائی کا ایک بائٹ ممکن ہے، انٹرمیڈیٹ کے ساتھ، جو کہ جواز پیش کرتا ہے کہ "اگر 4 بائٹ ڈیٹا الائنمنٹ کی ضرورت ہو،" جو کہ بالکل بکواس ہے۔ کیا، یہ خیال کیا جاتا ہے کہ ٹیلیگرام پروگرامرز اتنے نااہل ہیں کہ وہ ساکٹ سے ڈیٹا کو ایک منسلک بفر میں نہیں پڑھ سکتے؟ آپ کو ابھی بھی یہ کرنا ہے، کیونکہ پڑھنے سے آپ کو کسی بھی تعداد میں بائٹس واپس مل سکتی ہیں (اور پراکسی سرورز بھی ہیں، مثال کے طور پر...)۔ یا دوسری طرف، کیوں بلاک مختصر کیا گیا اگر ہمارے پاس اب بھی 16 بائٹس کے اوپر بھاری بھرتی ہوگی - 3 بائٹس بچائیں کبھی کبھی ?

کسی کو یہ تاثر ملتا ہے کہ نکولائی دوروف واقعی بغیر کسی عملی ضرورت کے نیٹ ورک پروٹوکول سمیت پہیوں کو دوبارہ ایجاد کرنا پسند کرتے ہیں۔

دیگر نقل و حمل کے اختیارات، بشمول ویب اور MTProxy، ہم ابھی غور نہیں کریں گے، شاید کسی اور پوسٹ میں، اگر کوئی درخواست ہو۔ اسی MTProxy کے بارے میں، ہمیں ابھی یاد رکھنا چاہیے کہ 2018 میں اس کی ریلیز کے فوراً بعد، فراہم کنندگان نے اسے فوری طور پر بلاک کرنا سیکھ لیا، جس کا مقصد بائی پاس بلاک کرنابذریعہ پیکیج کے سائز! اور یہ حقیقت بھی کہ MTProxy سرور (دوبارہ Waltman کے ذریعے) C میں لکھا گیا تھا، لینکس کی تفصیلات سے زیادہ جڑا ہوا تھا، حالانکہ اس کی بالکل بھی ضرورت نہیں تھی (فل کولن تصدیق کرے گا)، اور یہ کہ Go یا Node.js میں بھی ایسا ہی سرور ہوگا۔ سو سے کم لائنوں میں فٹ۔

لیکن ہم دوسرے مسائل پر غور کرنے کے بعد سیکشن کے آخر میں ان لوگوں کی تکنیکی خواندگی کے بارے میں نتیجہ اخذ کریں گے۔ ابھی کے لیے، آئیے OSI پرت 5، سیشن پر چلتے ہیں - جس پر انہوں نے MTProto سیشن رکھا تھا۔

کلیدیں، پیغامات، سیشنز، ڈفی-ہیل مین

انہوں نے اسے وہاں بالکل درست نہیں رکھا... ایک سیشن وہی سیشن نہیں ہے جو ایکٹیو سیشن کے تحت انٹرفیس میں نظر آتا ہے۔ لیکن ترتیب میں۔

ٹیلیگرام کے پروٹوکول اور تنظیمی طریقوں پر تنقید۔ حصہ 1، تکنیکی: ایک کلائنٹ کو شروع سے لکھنے کا تجربہ - TL, MT

لہذا ہمیں نقل و حمل کی پرت سے معلوم لمبائی کی بائٹ سٹرنگ موصول ہوئی۔ یہ یا تو ایک خفیہ کردہ پیغام ہے یا سادہ متن - اگر ہم ابھی بھی اہم معاہدے کے مرحلے پر ہیں اور حقیقت میں یہ کر رہے ہیں۔ ہم "کلید" کہلانے والے تصورات کے کس گروپ کے بارے میں بات کر رہے ہیں؟ آئیے ٹیلیگرام ٹیم کے لیے اس مسئلے کو خود واضح کرتے ہیں (میں صبح 4 بجے تھکے ہوئے دماغ کے ساتھ اپنی دستاویزات کا انگریزی سے ترجمہ کرنے کے لیے معذرت خواہ ہوں، کچھ فقرے ایسے ہی چھوڑنا آسان تھا):

دو اداروں کو کہا جاتا ہے اجلاس - "موجودہ سیشنز" کے تحت آفیشل کلائنٹس کے UI میں سے ایک، جہاں ہر سیشن پورے ڈیوائس/OS سے مطابقت رکھتا ہے۔
دوسرا - ایم ٹی پروٹو سیشن، جس میں پیغام کی ترتیب نمبر ہے (کم درجے کے معنی میں)، اور کون سا مختلف TCP کنکشن کے درمیان چل سکتا ہے۔ ایک ہی وقت میں کئی MTProto سیشنز انسٹال کیے جا سکتے ہیں، مثال کے طور پر، فائل ڈاؤن لوڈنگ کو تیز کرنے کے لیے۔

ان دونوں کے درمیان سیشن ایک تصور ہے اجازت. انحطاط کے معاملے میں ہم یہ کہہ سکتے ہیں۔ UI سیشن ویسا ہی ہے جیسا اجازتلیکن افسوس، سب کچھ پیچیدہ ہے۔ آئیں دیکھیں:

  • نئے ڈیوائس پر صارف سب سے پہلے پیدا کرتا ہے۔ auth_key اور اسے اکاؤنٹ سے منسلک کرتا ہے، مثال کے طور پر SMS کے ذریعے - اسی لیے اجازت
  • یہ پہلے کے اندر ہوا۔ ایم ٹی پروٹو سیشن، جس کے پاس ہے session_id اپنے اندر.
  • اس مرحلے پر، مجموعہ اجازت и session_id بلایا جا سکتا ہے مثال کے طور پر - یہ لفظ کچھ کلائنٹس کے دستاویزات اور کوڈ میں ظاہر ہوتا ہے۔
  • اس کے بعد، کلائنٹ کھول سکتا ہے کچھ ایم ٹی پروٹو سیشنز اسی کے تحت auth_key - اسی ڈی سی کو۔
  • پھر، ایک دن کلائنٹ کو فائل کی درخواست کرنے کی ضرورت ہوگی۔ ایک اور ڈی سی - اور اس کے لیے ایک نیا ڈی سی تیار کیا جائے گا۔ auth_key !
  • سسٹم کو مطلع کرنا کہ یہ کوئی نیا صارف نہیں ہے جو رجسٹر ہو رہا ہے بلکہ وہی ہے۔ اجازت (UI سیشن)، کلائنٹ API کالز استعمال کرتا ہے۔ auth.exportAuthorization گھر کے ڈی سی میں auth.importAuthorization نئے ڈی سی میں
  • سب کچھ ایک جیسا ہے، کئی کھلے ہو سکتے ہیں۔ ایم ٹی پروٹو سیشنز (ہر ایک اپنے ساتھ session_id) اس نئے ڈی سی کے تحت، یہ auth_key.
  • آخر میں، کلائنٹ پرفیکٹ فارورڈ سیکریسی چاہتا ہے۔ ہر کوئی auth_key تھا مستقل کلید - فی ڈی سی - اور کلائنٹ کال کرسکتا ہے۔ auth.bindTempAuthKey استعمال کیلئے عارضی auth_key - اور دوبارہ، صرف ایک temp_auth_key فی ڈی سی، سب کے لیے عام ایم ٹی پروٹو سیشنز اس ڈی سی کو

نوٹ کریں نمک (اور مستقبل کے نمکیات) بھی ایک پر ہے۔ auth_key وہ سب کے درمیان مشترکہ ایم ٹی پروٹو سیشنز اسی ڈی سی کو

"مختلف TCP کنکشنز کے درمیان" کا کیا مطلب ہے؟ تو اس کا مطلب ہے۔ کی طرح کچھ ایک ویب سائٹ پر اجازت دینے والی کوکی - یہ ایک دیے گئے سرور سے بہت سے TCP کنکشن برقرار رہتی ہے (بچا جاتی ہے)، لیکن ایک دن یہ خراب ہو جاتی ہے۔ صرف HTTP کے برعکس، MTProto میں سیشن کے اندر آنے والے پیغامات کو ترتیب وار نمبر دیا جاتا ہے اور اس کی تصدیق ہوتی ہے؛ اگر وہ سرنگ میں داخل ہوتے ہیں، تو کنکشن ٹوٹ گیا تھا - نیا کنکشن قائم کرنے کے بعد، سرور مہربانی کرکے اس سیشن میں وہ سب کچھ بھیجے گا جو اس نے پچھلے میں نہیں دیا تھا۔ TCP کنکشن۔

تاہم، مندرجہ بالا معلومات کا خلاصہ کئی مہینوں کی تفتیش کے بعد کیا گیا ہے۔ اس دوران، کیا ہم اپنے کلائنٹ کو شروع سے لاگو کر رہے ہیں؟ - آئیے شروع کی طرف واپس چلتے ہیں۔

تو آئیے پیدا کرتے ہیں۔ auth_key پر ٹیلیگرام سے Diffie-Hellman ورژن. آئیے دستاویزات کو سمجھنے کی کوشش کریں...

واسیلی، [19.06.18 20:05] data_with_hash := SHA1(ڈیٹا) + ڈیٹا + (کوئی بھی بے ترتیب بائٹس)؛ اس طرح کہ لمبائی 255 بائٹس کے برابر ہو۔
خفیہ کردہ_ڈیٹا := RSA(data_with_hash, server_public_key)؛ ایک 255 بائٹ لمبا نمبر (بڑا اینڈین) مطلوبہ ماڈیولس پر مطلوبہ طاقت تک بڑھایا جاتا ہے، اور نتیجہ 256 بائٹ نمبر کے طور پر محفوظ کیا جاتا ہے۔

ان کے پاس کچھ ڈوپ ڈی ایچ ہے۔

صحت مند شخص کے ڈی ایچ کی طرح نہیں لگتا
dx میں کوئی دو عوامی کلیدیں نہیں ہیں۔

ٹھیک ہے، آخر میں یہ حل ہو گیا، لیکن ایک باقی رہ گیا - کام کا ثبوت کلائنٹ کی طرف سے کیا گیا ہے کہ وہ نمبر کو فیکٹر کرنے کے قابل تھا. DoS حملوں کے خلاف تحفظ کی قسم۔ اور RSA کلید صرف ایک ہی سمت میں استعمال ہوتی ہے، بنیادی طور پر خفیہ کاری کے لیے new_nonce. لیکن جب کہ یہ بظاہر آسان آپریشن کامیاب ہو جائے گا، آپ کو کس چیز کا سامنا کرنا پڑے گا؟

واسیلی، [20.06.18/00/26 XNUMX:XNUMX] میں ابھی تک ایپڈ درخواست پر نہیں پہنچا

میں نے یہ درخواست ڈی ایچ کو بھیجی۔

اور، ٹرانسپورٹ ڈاک میں یہ کہتا ہے کہ یہ ایرر کوڈ کے 4 بائٹس کے ساتھ جواب دے سکتا ہے۔ بس

ٹھیک ہے، اس نے مجھے بتایا -404، تو کیا؟

تو میں نے اس سے کہا: "اس طرح کے فنگر پرنٹ کے ساتھ سرور کلید کے ساتھ انکرپٹ شدہ اپنی بکواس پکڑو، مجھے DH چاہیے" اور اس نے احمقانہ 404 کے ساتھ جواب دیا۔

آپ اس سرور کے جواب کے بارے میں کیا سوچیں گے؟ کیا کرنا ہے؟ کوئی پوچھنے والا نہیں ہے (لیکن دوسرے حصے میں اس پر مزید)۔

یہاں ساری دلچسپی گودی پر کی جاتی ہے۔

میرے پاس اور کچھ نہیں ہے، میں نے صرف نمبروں کو آگے پیچھے کرنے کا خواب دیکھا

دو 32 بٹ نمبر۔ میں نے انہیں سب کی طرح پیک کیا۔

لیکن نہیں، ان دونوں کو پہلے BE کے طور پر لائن میں شامل کرنے کی ضرورت ہے۔

Vadim Goncharov, [20.06.18 15:49] اور اس 404 کی وجہ سے؟

واسیلی، [20.06.18 15:49] ہاں!

Vadim Goncharov, [20.06.18 15:50] تو میں سمجھ نہیں پا رہا کہ وہ کیا "نہیں ملا"

واسیلی، [20.06.18 15:50] تقریبا

مجھے بنیادی عوامل میں ایسی سڑن نہیں ملی۔)

ہم نے غلطی کی اطلاع دینے کا انتظام بھی نہیں کیا۔

واسیلی، [20.06.18 20:18] اوہ، ایم ڈی5 بھی ہے۔ پہلے ہی تین مختلف ہیشز

کلیدی فنگر پرنٹ کی گنتی اس طرح کی جاتی ہے:

digest = md5(key + iv)
fingerprint = substr(digest, 0, 4) XOR substr(digest, 4, 4)

SHA1 اور sha2

تو آئیے ڈال دیں۔ auth_key ہمیں Diffie-Hellman کا استعمال کرتے ہوئے سائز میں 2048 بٹس موصول ہوئے۔ اس کے بعد کیا ہے؟ اس کے بعد ہم نے دریافت کیا کہ اس کلید کے نچلے 1024 بٹس کسی بھی طرح سے استعمال نہیں ہوتے ہیں... لیکن آئیے ابھی اس کے بارے میں سوچتے ہیں۔ اس مرحلے پر، ہمارے پاس سرور کے ساتھ ایک مشترکہ راز ہے۔ TLS سیشن کا ایک اینالاگ قائم کیا گیا ہے، جو ایک بہت مہنگا طریقہ کار ہے۔ لیکن سرور ابھی تک کچھ نہیں جانتا کہ ہم کون ہیں! ابھی تک نہیں، اصل میں۔ اجازت. وہ. اگر آپ "لاگ ان پاس ورڈ" کے لحاظ سے سوچتے ہیں، جیسا کہ آپ نے ایک بار ICQ میں کیا تھا، یا کم از کم "لاگ ان کی"، جیسا کہ SSH میں (مثال کے طور پر، کچھ gitlab/github پر)۔ ہمیں ایک گمنام موصول ہوا۔ کیا ہوگا اگر سرور ہمیں بتائے کہ "یہ فون نمبرز کسی اور ڈی سی کے ذریعہ فراہم کیے گئے ہیں"؟ یا یہاں تک کہ "آپ کے فون نمبر پر پابندی لگا دی گئی ہے"؟ ہم سب سے بہتر یہ کر سکتے ہیں کہ کلید کو اس امید کے ساتھ رکھیں کہ یہ کارآمد ثابت ہو گی اور تب تک بوسیدہ نہیں ہو گی۔

ویسے، ہم نے اسے تحفظات کے ساتھ "وصول" کیا۔ مثال کے طور پر، کیا ہم سرور پر بھروسہ کرتے ہیں؟ اگر یہ جعلی ہے تو کیا ہوگا؟ کرپٹوگرافک چیک کی ضرورت ہوگی:

واسیلی، [21.06.18 17:53] وہ موبائل کلائنٹس کو پیش کرتے ہیں کہ وہ 2kbit نمبر کو پرائمالٹی فیصد چیک کریں)

لیکن یہ بالکل واضح نہیں ہے، nafeijoa

واسیلی، [21.06.18 18:02] دستاویز میں یہ نہیں بتایا گیا ہے کہ اگر یہ آسان نہ ہو تو کیا کرنا ہے

نہیں کہا۔ دیکھتے ہیں سرکاری اینڈرائیڈ کلائنٹ اس معاملے میں کیا کرتا ہے؟ اے یہی ہے (اور ہاں، پوری فائل دلچسپ ہے) - جیسا کہ وہ کہتے ہیں، میں اسے یہاں چھوڑ دوں گا:

278     static const char *goodPrime = "c71caeb9c6b1c9048e6c522f70f13f73980d40238e3e21c14934d037563d930f48198a0aa7c14058229493d22530f4dbfa336f6e0ac925139543aed44cce7c3720fd51f69458705ac68cd4fe6b6b13abdc9746512969328454f18faf8c595f642477fe96bb2a941d5bcd1d4ac8cc49880708fa9b378e3c4f3a9060bee67cf9a4a4a695811051907e162753b56b0f6b410dba74d8a84b2a14b3144e0ef1284754fd17ed950d5965b4b9dd46582db1178d169c6bc465b0d6ff9ca3928fef5b9ae4e418fc15e83ebea0f87fa9ff5eed70050ded2849f47bf959d956850ce929851f0d8115f635b105ee2e4e15d04b2454bf6f4fadf034b10403119cd8e3b92fcc5b";
279   if (!strcasecmp(prime, goodPrime)) {

نہیں، یقیناً یہ اب بھی موجود ہے۔ کچھ کسی نمبر کی ابتدائی حیثیت کے لیے ٹیسٹ ہوتے ہیں، لیکن ذاتی طور پر مجھے اب ریاضی کا کافی علم نہیں ہے۔

ٹھیک ہے، ہمیں ماسٹر چابی مل گئی ہے۔ لاگ ان کرنے کے لیے، یعنی درخواستیں بھیجیں، آپ کو AES کا استعمال کرتے ہوئے مزید خفیہ کاری انجام دینے کی ضرورت ہے۔

میسج کلید کو میسج باڈی کے SHA128 کے 256 درمیانی بٹس کے طور پر بیان کیا گیا ہے (بشمول سیشن، میسج آئی ڈی وغیرہ)، پیڈنگ بائٹس سمیت، اجازت کی کلید سے لیے گئے 32 بائٹس کے ذریعے پہلے سے تیار کردہ۔

واسیلی، [22.06.18 14:08] اوسط، کتیا، بٹس

مل گیا auth_key. تمام ان سے آگے... یہ دستاویز سے واضح نہیں ہے۔ اوپن سورس کوڈ کا مطالعہ کرنے کے لیے آزاد محسوس کریں۔

نوٹ کریں کہ MTProto 2.0 کو 12 سے 1024 بائٹس تک پیڈنگ کی ضرورت ہوتی ہے، پھر بھی اس شرط کے ساتھ مشروط ہے کہ نتیجے میں آنے والے پیغام کی لمبائی 16 بائٹس سے تقسیم ہو۔

تو آپ کو کتنا پیڈنگ شامل کرنا چاہئے؟

اور ہاں، غلطی کی صورت میں 404 بھی ہے۔

اگر کسی نے دستاویزات کے خاکے اور متن کا بغور مطالعہ کیا تو اس نے دیکھا کہ وہاں کوئی MAC نہیں ہے۔ اور یہ کہ AES ایک مخصوص IGE موڈ میں استعمال ہوتا ہے جو کہیں اور استعمال نہیں ہوتا ہے۔ وہ یقیناً اپنے اکثر پوچھے گئے سوالات میں اس کے بارے میں لکھتے ہیں... یہاں، جیسا کہ، میسج کی کلید خود بھی ڈکرپٹڈ ڈیٹا کی SHA ہیش ہے، جو سالمیت کو چیک کرنے کے لیے استعمال ہوتی ہے - اور کسی وجہ سے مماثلت نہ ہونے کی صورت میں دستاویزات خاموشی سے ان کو نظر انداز کرنے کی سفارش کرتا ہے (لیکن سیکورٹی کا کیا ہوگا، اگر وہ ہمیں توڑ دیں؟)

میں ایک کرپٹوگرافر نہیں ہوں، ہو سکتا ہے کہ نظریاتی نقطہ نظر سے اس معاملے میں اس موڈ میں کچھ غلط نہ ہو۔ لیکن میں ٹیلیگرام ڈیسک ٹاپ کو بطور مثال استعمال کرتے ہوئے واضح طور پر ایک عملی مسئلہ کا نام دے سکتا ہوں۔ یہ مقامی کیشے (یہ تمام D877F783D5D3EF8C) کو اسی طرح انکرپٹ کرتا ہے جس طرح MTProto میں پیغامات (صرف اس صورت میں ورژن 1.0 میں)، یعنی پہلے میسج کی کلید، پھر ڈیٹا خود (اور کہیں ایک طرف اہم بڑا auth_key 256 بائٹس، جس کے بغیر msg_key بیکار)۔ لہذا، مسئلہ بڑی فائلوں پر نمایاں ہو جاتا ہے۔ یعنی، آپ کو ڈیٹا کی دو کاپیاں رکھنے کی ضرورت ہے - انکرپٹڈ اور ڈکرپٹڈ۔ اور اگر میگا بائٹس، یا سٹریمنگ ویڈیو، مثال کے طور پر؟... سائفر ٹیکسٹ کے بعد MAC کے ساتھ کلاسیکی اسکیمیں آپ کو اسے پڑھنے کی اجازت دیتی ہیں، فوری طور پر اسے منتقل کرتے ہیں۔ لیکن MTProto کے ساتھ آپ کو کرنا پڑے گا۔ سب سے پہلے پورے پیغام کو خفیہ یا ڈکرپٹ کریں، تب ہی اسے نیٹ ورک یا ڈسک پر منتقل کریں۔ لہذا، ٹیلیگرام ڈیسک ٹاپ کے تازہ ترین ورژن میں کیشے میں user_data ایک اور فارمیٹ بھی استعمال کیا جاتا ہے - CTR موڈ میں AES کے ساتھ۔

واسیلی، [21.06.18 01:27] اوہ، مجھے پتہ چلا کہ آئی جی ای کیا ہے: آئی جی ای اصل میں کربروس کے لیے "توثیق کرنے والے انکرپشن موڈ" کی پہلی کوشش تھی۔ یہ ایک ناکام کوشش تھی (یہ سالمیت کا تحفظ فراہم نہیں کرتی ہے)، اور اسے ہٹانا پڑا۔ یہ ایک مستند خفیہ کاری موڈ کے لیے 20 سالہ جستجو کا آغاز تھا جو کام کرتا ہے، جو حال ہی میں OCB اور GCM جیسے طریقوں پر منتج ہوا۔

اور اب کارٹ کی طرف سے دلائل:

ٹیلی گرام کے پیچھے کی ٹیم، جس کی قیادت نکولائی ڈوروف کر رہے ہیں، چھ ACM چیمپئنز پر مشتمل ہے، جن میں سے آدھے ریاضی میں پی ایچ ڈی ہیں۔ MTProto کے موجودہ ورژن کو متعارف کرانے میں انہیں تقریباً دو سال لگے۔

کہ عجیب بات ہے. دو سال نچلی سطح پر

یا آپ صرف tls لے سکتے ہیں۔

ٹھیک ہے، ہم کہتے ہیں کہ ہم نے خفیہ کاری اور دیگر باریکیاں کر لی ہیں۔ کیا آخر کار TL میں سیریلائزڈ درخواستیں بھیجنا اور جوابات کو ڈی سیریلائز کرنا ممکن ہے؟ تو آپ کو کیا اور کیسے بھیجنا چاہئے؟ یہاں، طریقہ بتاتے ہیں۔ initConnection، شاید یہ ہے؟

واسیلی، [25.06.18 18:46] کنکشن شروع کرتا ہے اور صارف کے ڈیوائس اور ایپلیکیشن پر معلومات محفوظ کرتا ہے۔

یہ app_id، device_model، system_version، app_version اور lang_code کو قبول کرتا ہے۔

اور کچھ استفسار

ہمیشہ کی طرح دستاویزات۔ اوپن سورس کا مطالعہ کرنے کے لیے آزاد محسوس کریں۔

اگر invokeWithLayer کے ساتھ سب کچھ تقریباً واضح تھا، تو پھر یہاں کیا غلط ہے؟ یہ پتہ چلتا ہے، ہم کہتے ہیں کہ ہمارے پاس ہے - کلائنٹ کے پاس سرور سے پہلے ہی کچھ پوچھنا تھا - ایک درخواست ہے جسے ہم بھیجنا چاہتے ہیں:

واسیلی، [25.06.18 19:13] ضابطہ کے مطابق، پہلی کال اس گھٹیا پن میں لپٹی ہوئی ہے، اور گھٹیا خود ہی invokewithlayer میں لپٹا ہوا ہے۔

initConnection ایک الگ کال کیوں نہیں ہو سکتا، لیکن ایک ریپر ہونا چاہیے؟ جی ہاں، جیسا کہ یہ نکلا، یہ ہر بار ہر سیشن کے شروع میں ہونا چاہیے، اور ایک بار نہیں، جیسا کہ مرکزی کلید کے ساتھ ہے۔ لیکن! اسے کسی غیر مجاز صارف کے ذریعہ نہیں بلایا جاسکتا ہے! اب ہم اس مرحلے پر پہنچ چکے ہیں جہاں اس کا اطلاق ہوتا ہے۔ یہ والا دستاویزات کا صفحہ - اور یہ ہمیں بتاتا ہے کہ...

API کے طریقوں کا صرف ایک چھوٹا سا حصہ غیر مجاز صارفین کے لیے دستیاب ہے:

  • 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 کے نمبر کے ساتھ ایک غلطی موصول ہوگی۔ یہ جاننے کے لیے کہ آپ کو DC نمبر کے ذریعے کس IP ایڈریس سے جڑنا ہے، ہماری مدد کریں۔ help.getConfig. ایک وقت میں صرف 5 اندراجات تھے لیکن 2018 کے مشہور واقعات کے بعد اس تعداد میں نمایاں اضافہ ہوا ہے۔

اب یاد رکھیں کہ ہم گمنام طور پر سرور پر اس مرحلے پر پہنچے ہیں۔ کیا صرف ایک IP ایڈریس حاصل کرنا بہت مہنگا نہیں ہے؟ یہ اور دیگر کارروائیاں MTProto کے غیر خفیہ کردہ حصے میں کیوں نہیں کرتے؟ میں نے اعتراض سنا: "ہم یہ کیسے یقینی بنا سکتے ہیں کہ یہ RKN نہیں ہے جو جھوٹے پتوں کے ساتھ جواب دے گا؟" اس کے لیے ہمیں یاد ہے کہ عام طور پر سرکاری کلائنٹس RSA کیز سرایت شدہ ہیں۔، یعنی کیا تم بس نشان یہ معلومات. دراصل، یہ پہلے سے ہی بائی پاس بلاکنگ کے بارے میں معلومات کے لیے کیا جا رہا ہے جو کلائنٹس دوسرے چینلز کے ذریعے وصول کرتے ہیں (منطقی طور پر، یہ خود MTProto میں نہیں کیا جا سکتا؛ آپ کو یہ بھی جاننے کی ضرورت ہے کہ کہاں سے جڑنا ہے)۔

ٹھیک ہے. کلائنٹ کی اجازت کے اس مرحلے پر، ہم ابھی تک مجاز نہیں ہیں اور ہم نے اپنی درخواست رجسٹر نہیں کی ہے۔ ہم ابھی یہ دیکھنا چاہتے ہیں کہ سرور کسی غیر مجاز صارف کے لیے دستیاب طریقوں کا کیا جواب دیتا ہے۔ اور یہاں…

واسیلی، [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 موضوع میں کچھ یاد کیا؟ کوئی تعجب نہیں:

واسیلی، [28.06.18 02:04] ایم ایم، وہ e2e پر کچھ الگورتھم کے ذریعے گڑبڑ کر رہے ہیں

Mtproto دونوں ڈومینز کے لیے انکرپشن الگورتھم اور کلیدوں کے ساتھ ساتھ تھوڑا سا ریپر ڈھانچہ کی وضاحت کرتا ہے۔

لیکن وہ مسلسل اسٹیک کی مختلف سطحوں کو ملاتے ہیں، لہذا یہ ہمیشہ واضح نہیں ہوتا ہے کہ mtproto کہاں ختم ہوا اور اگلی سطح کہاں سے شروع ہوئی

وہ کیسے مکس کرتے ہیں؟ ٹھیک ہے، یہاں PFS کے لیے وہی عارضی کلید ہے، مثال کے طور پر (ویسے، ٹیلیگرام ڈیسک ٹاپ یہ نہیں کر سکتا)۔ یہ API کی درخواست کے ذریعہ عمل میں لایا جاتا ہے۔ auth.bindTempAuthKey، یعنی اوپر کی سطح سے. لیکن ایک ہی وقت میں یہ نچلی سطح پر خفیہ کاری میں مداخلت کرتا ہے - اس کے بعد، مثال کے طور پر، آپ کو اسے دوبارہ کرنے کی ضرورت ہے initConnection وغیرہ، یہ نہیں ہے صرف عام درخواست. یہ بھی خاص بات ہے کہ آپ کے پاس فی ڈی سی صرف ایک عارضی کلید ہو سکتی ہے، حالانکہ فیلڈ auth_key_id ہر پیغام میں آپ کو کم از کم ہر پیغام کی کلید کو تبدیل کرنے کی اجازت دیتا ہے، اور یہ کہ سرور کو کسی بھی وقت عارضی کلید کو "بھولنے" کا حق حاصل ہے - دستاویزات یہ نہیں بتاتی ہیں کہ اس معاملے میں کیا کرنا ہے... ٹھیک ہے، کیوں 'تمہارے پاس کئی چابیاں نہیں ہیں، جیسا کہ مستقبل کے نمکیات کے سیٹ کے ساتھ، اور؟

MTProto تھیم کے بارے میں کچھ اور چیزیں قابل توجہ ہیں۔

پیغامات کے پیغامات، msg_id، msg_seqno، تصدیقات، غلط سمت میں پنگ اور دیگر محاورات

آپ کو ان کے بارے میں جاننے کی ضرورت کیوں ہے؟ کیونکہ وہ اعلی سطح پر "لیک" کرتے ہیں، اور API کے ساتھ کام کرتے وقت آپ کو ان سے آگاہ ہونا ضروری ہے۔ آئیے فرض کریں کہ ہمیں msg_key میں دلچسپی نہیں ہے؛ نچلی سطح نے ہمارے لیے سب کچھ ڈیکرپٹ کر دیا ہے۔ لیکن ڈکرپٹڈ ڈیٹا کے اندر ہمارے پاس درج ذیل فیلڈز ہیں (ڈیٹا کی لمبائی بھی، اس لیے ہم جانتے ہیں کہ پیڈنگ کہاں ہے، لیکن یہ اہم نہیں ہے):

  • نمک - int64
  • سیشن_آئی ڈی - int64
  • پیغام_آئی ڈی - int64
  • seq_no - int32

ہم آپ کو یاد دلاتے ہیں کہ پورے ڈی سی کے لیے صرف ایک نمک ہے۔ اس کے بارے میں کیوں جانتے ہیں؟ صرف اس لیے نہیں کہ ایک درخواست ہے۔ get_future_salts، جو آپ کو بتاتا ہے کہ کون سے وقفے درست ہوں گے، لیکن اس وجہ سے بھی کہ اگر آپ کا نمک "سڑا ہوا" ہے، تو پیغام (درخواست) صرف ضائع ہو جائے گا۔ سرور بلاشبہ جاری کرکے نئے نمک کی اطلاع دے گا۔ new_session_created - لیکن پرانے کے ساتھ آپ کو اسے کسی نہ کسی طرح دوبارہ بھیجنا پڑے گا، مثال کے طور پر۔ اور یہ مسئلہ درخواست کے فن تعمیر کو متاثر کرتا ہے۔

سرور کو بہت سی وجوہات کی بنا پر سیشن کو مکمل طور پر چھوڑنے اور اس طرح جواب دینے کی اجازت ہے۔ دراصل، کلائنٹ کی طرف سے MTProto سیشن کیا ہے؟ یہ دو نمبر ہیں۔ session_id и seq_no اس سیشن کے اندر پیغامات۔ ٹھیک ہے، اور بنیادی TCP کنکشن، یقیناً۔ ہم کہتے ہیں کہ ہمارا کلائنٹ ابھی تک نہیں جانتا کہ بہت سی چیزیں کیسے کی جائیں، اس نے رابطہ منقطع کر دیا، دوبارہ رابطہ قائم کر لیا۔ اگر یہ جلدی ہوا تو - نئے TCP کنکشن میں پرانا سیشن جاری رہا، اضافہ کریں۔ seq_no مزید. اگر اس میں زیادہ وقت لگتا ہے، تو سرور اسے حذف کر سکتا ہے، کیونکہ اس کی طرف یہ بھی ایک قطار ہے، جیسا کہ ہمیں معلوم ہوا ہے۔

یہ کیا ہونا چاہئے seq_no? اوہ، یہ ایک مشکل سوال ہے۔ ایمانداری سے سمجھنے کی کوشش کریں کہ کیا مطلب تھا:

مواد سے متعلق پیغام

ایک پیغام جس میں واضح اعتراف کی ضرورت ہے۔ ان میں تمام صارف اور بہت سے سروس پیغامات شامل ہیں، عملی طور پر تمام کنٹینرز اور اعترافات کے علاوہ۔

پیغام کی ترتیب نمبر (msg_seqno)

ایک 32 بٹ نمبر جو "مواد سے متعلق" پیغامات کی دگنی تعداد کے برابر ہے (جن کو تسلیم کرنے کی ضرورت ہوتی ہے، اور خاص طور پر وہ جو کنٹینرز نہیں ہیں) اس پیغام سے پہلے بھیجنے والے کے ذریعہ بنائے گئے تھے اور اس کے بعد اگر موجودہ پیغام ایک ہے مواد سے متعلق پیغام۔ ایک کنٹینر ہمیشہ اس کے پورے مواد کے بعد تیار کیا جاتا ہے۔ لہذا، اس کی ترتیب نمبر اس میں موجود پیغامات کی ترتیب نمبروں سے زیادہ یا برابر ہے۔

یہ کس قسم کا سرکس ہے جس میں 1 کا اضافہ ہوتا ہے، اور پھر دوسرا 2 ہوتا ہے؟... مجھے شک ہے کہ ابتدا میں ان کا مطلب تھا "ACK کے لیے سب سے کم اہم بٹ، باقی ایک نمبر ہے"، لیکن نتیجہ بالکل ایک جیسا نہیں ہے - خاص طور پر، یہ باہر آتا ہے، بھیجا جا سکتا ہے کچھ ایک جیسی ہونے کی تصدیق seq_no! کیسے؟ ٹھیک ہے، مثال کے طور پر، سرور ہمیں کچھ بھیجتا ہے، بھیجتا ہے، اور ہم خود خاموش رہتے ہیں، صرف سروس پیغامات کے ساتھ جواب دیتے ہیں جو اس کے پیغامات کی وصولی کی تصدیق کرتے ہیں۔ اس صورت میں، ہماری آؤٹ گوئنگ کنفرمیشنز میں وہی آؤٹ گوئنگ نمبر ہوگا۔ اگر آپ TCP سے واقف ہیں اور سوچتے ہیں کہ یہ کسی طرح سے جنگلی لگتا ہے، لیکن یہ زیادہ جنگلی نہیں لگتا ہے، کیونکہ TCP میں seq_no تبدیل نہیں ہوتا ہے، لیکن تصدیق کو جاتا ہے seq_no دوسری طرف، میں آپ کو پریشان کرنے میں جلدی کروں گا۔ تصدیقات MTProto میں فراہم کی جاتی ہیں۔ NOT پر seq_noجیسا کہ TCP میں ہے، لیکن بذریعہ msg_id !

یہ کیا ہے msg_id، ان شعبوں میں سے سب سے اہم؟ ایک منفرد پیغام شناخت کنندہ، جیسا کہ نام سے پتہ چلتا ہے۔ اس کی تعریف 64 بٹ نمبر کے طور پر کی گئی ہے، جس میں سے سب سے کم بٹس میں پھر سے "سرور نہیں-سرور" کا جادو ہوتا ہے، اور باقی ایک یونکس ٹائم اسٹیمپ ہے، جس میں فریکشنل حصہ بھی شامل ہے، 32 بٹس کو بائیں طرف منتقل کر دیا گیا ہے۔ وہ. ٹائم اسٹیمپ فی سی (اور ایسے پیغامات جن میں بہت زیادہ فرق ہوتا ہے سرور کی طرف سے مسترد کر دیا جائے گا)۔ اس سے یہ پتہ چلتا ہے کہ عام طور پر یہ ایک شناخت کنندہ ہے جو کلائنٹ کے لیے عالمی ہے۔ اس کو دیکھتے ہوئے - آئیے یاد رکھیں session_id - ہمیں ضمانت دی گئی ہے: کسی بھی صورت میں ایک سیشن کے لیے پیغام کو دوسرے سیشن میں نہیں بھیجا جا سکتا. یہ ہے، یہ پتہ چلتا ہے کہ پہلے سے ہی ہے تین سطح - سیشن، سیشن نمبر، پیغام کی شناخت۔ اتنی زیادہ پیچیدگی کیوں، یہ معمہ بہت بڑا ہے۔

اس طرح، msg_id کے لیے ضروری ہے...

RPC: درخواستیں، جوابات، غلطیاں۔ تصدیقات۔

جیسا کہ آپ نے دیکھا ہوگا، خاکہ میں کہیں بھی کوئی خاص "آر پی سی کی درخواست کریں" کی قسم یا فنکشن نہیں ہے، حالانکہ جوابات موجود ہیں۔ سب کے بعد، ہمارے پاس مواد سے متعلق پیغامات ہیں! یہ ہے کہ، کوئی پیغام ایک درخواست ہو سکتا ہے! یا نہ ہونا۔ سب کے بعد، ہر ایک وہاں ہے msg_id. لیکن جوابات ہیں:

rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult;

یہ وہ جگہ ہے جہاں یہ اشارہ کیا جاتا ہے کہ یہ کس پیغام کا جواب ہے۔ لہذا، API کے اوپری سطح پر، آپ کو یاد رکھنا ہوگا کہ آپ کی درخواست کا نمبر کیا تھا - میرے خیال میں اس بات کی وضاحت کرنے کی ضرورت نہیں ہے کہ کام غیر مطابقت پذیر ہے، اور ایک ہی وقت میں کئی درخواستیں پیشرفت میں ہوسکتی ہیں، جن کے جوابات کسی بھی ترتیب میں واپس کیے جا سکتے ہیں؟ اصولی طور پر، اس اور غلطی کے پیغامات سے جیسے کہ کوئی کارکن نہیں، اس کے پیچھے موجود فن تعمیر کا پتہ لگایا جا سکتا ہے: وہ سرور جو آپ کے ساتھ 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 غلطیاں (اچھی طرح سے، جوابات کے الفاظ کا احترام نہیں کیا جاتا ہے، کچھ جگہوں پر وہ کوڈز کے درمیان تصادفی طور پر تقسیم کیے جاتے ہیں)، اور لائن اس طرح دکھائی دیتی ہے CAPITAL_LETTERS_AND_NUMBERS. مثال کے طور پر، PHONE_NUMBER_OCCUPIED یا FILE_PART_Х_MISSING۔ ٹھیک ہے، یعنی، آپ کو اب بھی اس لائن کی ضرورت ہوگی۔ تجزیہ. مثال کے طور پر FLOOD_WAIT_3600 اس کا مطلب ہے کہ آپ کو ایک گھنٹہ انتظار کرنا پڑے گا، اور PHONE_MIGRATE_5, کہ اس سابقہ ​​کے ساتھ ایک ٹیلی فون نمبر 5th DC میں رجسٹرڈ ہونا ضروری ہے۔ ہمارے پاس ایک قسم کی زبان ہے، ٹھیک ہے؟ ہمیں سٹرنگ سے دلیل کی ضرورت نہیں ہے، باقاعدہ لوگ کریں گے، ٹھیک ہے۔

ایک بار پھر، یہ سروس پیغامات کے صفحے پر نہیں ہے، لیکن، جیسا کہ اس منصوبے کے ساتھ پہلے سے ہی معمول ہے، معلومات مل سکتی ہے ایک اور دستاویزی صفحہ پر. یا شک کا اظہار. سب سے پہلے، دیکھو، ٹائپنگ/پرت کی خلاف ورزی - RpcError میں گھونسلا جا سکتا ہے RpcResult. باہر کیوں نہیں؟ ہم نے کس چیز کو مدنظر نہیں رکھا؟... اس کے مطابق، اس کی ضمانت کہاں ہے؟ RpcError میں سرایت نہیں ہو سکتا RpcResult، لیکن براہ راست یا کسی اور قسم میں گھوںسلا ہو؟... اور اگر یہ نہیں ہوسکتا ہے، تو یہ اعلی سطح پر کیوں نہیں ہے، یعنی یہ غائب ہے req_msg_id ؟ ..

لیکن آئیے سروس پیغامات کے بارے میں جاری رکھیں۔ کلائنٹ سوچ سکتا ہے کہ سرور طویل عرصے سے سوچ رہا ہے اور یہ شاندار درخواست کر سکتا ہے:

rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer;

اس سوال کے تین ممکنہ جوابات ہیں، ایک بار پھر تصدیق کے طریقہ کار سے جڑے ہوئے ہیں؛ یہ سمجھنے کی کوشش کر رہے ہیں کہ انہیں کیا ہونا چاہیے (اور کن اقسام کی عمومی فہرست جن کی تصدیق کی ضرورت نہیں ہے) کو ہوم ورک کے طور پر قاری پر چھوڑ دیا جاتا ہے (نوٹ: معلومات میں ٹیلیگرام ڈیسک ٹاپ سورس کوڈ مکمل نہیں ہے)۔

منشیات کی لت: پیغام کے حالات

عام طور پر، TL، MTProto اور Telegram میں عام طور پر بہت سی جگہیں ضد کا احساس چھوڑتی ہیں، لیکن شائستگی، تدبیر اور دیگر چیزوں سے ہٹ کر نرم مہارت ہم نے شائستگی سے اس پر خاموشی اختیار کی، اور مکالموں میں فحاشی کو سنسر کیا۔ تاہم، اس جگہОزیادہ تر صفحہ کے بارے میں ہے پیغامات کے بارے میں پیغامات یہ میرے لیے بھی چونکا دینے والا ہے، جو ایک طویل عرصے سے نیٹ ورک پروٹوکول کے ساتھ کام کر رہا ہے اور اس نے مختلف درجوں کی ٹیڑھی سائیکلیں دیکھی ہیں۔

یہ تصدیق کے ساتھ، معصومانہ طور پر شروع ہوتا ہے۔ آگے وہ ہمیں بتاتے ہیں۔

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 کے ساتھ کام کرنا شروع کرتا ہے، ان سے نمٹنا پڑے گا؛ "تصحیح شدہ - دوبارہ مرتب کردہ - لانچ" کے چکر میں، نمبر کی غلطیاں یا نمکیات جو ترمیم کے دوران خراب ہونے میں کامیاب ہو گئے ہیں، ایک عام بات ہے۔ تاہم، یہاں دو نکات ہیں:

  1. اس کا مطلب ہے کہ اصل پیغام گم ہو گیا ہے۔ ہمیں کچھ قطاریں بنانے کی ضرورت ہے، ہم اسے بعد میں دیکھیں گے۔
  2. یہ عجیب ایرر نمبرز کیا ہیں؟ 16، 17، 18، 19، 20، 32، 33، 34، 35، 48، 64... دوسرے نمبر کہاں ہیں، ٹومی؟

دستاویزات میں کہا گیا ہے:

ارادہ یہ ہے کہ error_code قدروں کو گروپ کیا گیا ہے (error_code >> 4): مثال کے طور پر، کوڈز 0x40 - 0x4f کنٹینر کے گلنے کی غلطیوں سے مطابقت رکھتے ہیں۔

لیکن، سب سے پہلے، دوسری سمت میں تبدیلی، اور دوم، اس سے کوئی فرق نہیں پڑتا، دوسرے کوڈ کہاں ہیں؟ مصنف کے سر میں؟... تاہم، یہ چھوٹی چھوٹی باتیں ہیں۔

پیغام کی حالتوں اور پیغام کی کاپیوں کے بارے میں پیغامات میں لت شروع ہوتی ہے:

  • پیغام کی حیثیت کی معلومات کے لیے درخواست
    اگر کسی بھی فریق کو تھوڑی دیر کے لیے اپنے باہر جانے والے پیغامات کی حیثیت کے بارے میں معلومات نہیں ملی ہیں، تو وہ واضح طور پر دوسرے فریق سے اس کی درخواست کر سکتا ہے:
    msgs_state_req#da69fb52 msg_ids:Vector long = MsgsStateReq;
  • پیغامات کی حیثیت سے متعلق معلوماتی پیغام
    msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo;
    یہاں، info ایک سٹرنگ ہے جس میں آنے والی msg_ids فہرست سے ہر پیغام کے لیے پیغام کی حیثیت کا بالکل ایک بائٹ ہوتا ہے:

    • 1 = پیغام کے بارے میں کچھ معلوم نہیں ہے (msg_id بہت کم ہے، دوسرا فریق اسے بھول گیا ہے)
    • 2 = پیغام موصول نہیں ہوا (msg_id ذخیرہ شدہ شناخت کنندگان کی حد میں آتا ہے؛ تاہم، دوسرے فریق کو یقینی طور پر اس طرح کا پیغام نہیں ملا ہے)
    • 3 = پیغام موصول نہیں ہوا (msg_id بہت زیادہ؛ تاہم، دوسرے فریق کو یقینی طور پر ابھی تک موصول نہیں ہوا ہے)
    • 4 = پیغام موصول ہوا (نوٹ کریں کہ یہ جواب بھی ایک ہی وقت میں ایک رسید کا اعتراف ہے)
    • +8 = پیغام پہلے ہی تسلیم شدہ ہے۔
    • +16 = پیغام جس کو تسلیم کرنے کی ضرورت نہیں ہے۔
    • +32 = آر پی سی استفسار جو کہ پیغام پر کارروائی ہو رہا ہے یا پہلے ہی مکمل ہو چکا ہے۔
    • +64 = پہلے سے تیار کردہ پیغام پر مواد سے متعلق جواب
    • +128 = دوسرا فریق اس حقیقت کے لیے جانتا ہے کہ پیغام پہلے ہی موصول ہو چکا ہے۔
      اس جواب کو تسلیم کرنے کی ضرورت نہیں ہے۔ یہ متعلقہ msgs_state_req کا خود اور خود ایک اعتراف ہے۔
      نوٹ کریں کہ اگر یہ اچانک پتہ چلتا ہے کہ دوسرے فریق کے پاس ایسا پیغام نہیں ہے جو ایسا لگتا ہے کہ اسے بھیجا گیا ہے، تو پیغام آسانی سے دوبارہ بھیجا جا سکتا ہے۔ یہاں تک کہ اگر دوسرے فریق کو ایک ہی وقت میں پیغام کی دو کاپیاں موصول ہو جائیں، تب بھی نقل کو نظر انداز کر دیا جائے گا۔ (اگر بہت زیادہ وقت گزر گیا ہے، اور اصل msg_id اب درست نہیں ہے، تو پیغام کو msg_copy میں لپیٹ دیا جائے گا)۔
  • پیغامات کی حیثیت کا رضاکارانہ مواصلت
    کوئی بھی فریق رضاکارانہ طور پر دوسرے فریق کو دوسرے فریق کے ذریعے بھیجے گئے پیغامات کی حیثیت سے آگاہ کر سکتا ہے۔
    msgs_all_info#8cc0d131 msg_ids:Vector long info:string = MsgsAllInfo
  • ایک پیغام کی حیثیت کی توسیع شدہ رضاکارانہ مواصلات
    ...
    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;
  • پیغامات کو دوبارہ بھیجنے کی واضح درخواست
    msg_resend_req#7d861a08 msg_ids:Vector long = MsgResendReq;
    ریموٹ پارٹی فوری طور پر درخواست کردہ پیغامات کو دوبارہ بھیج کر جواب دیتی ہے […]
  • جوابات دوبارہ بھیجنے کی واضح درخواست
    msg_resend_ans_req#8610baeb msg_ids:Vector long = MsgResendReq;
    ریموٹ پارٹی فوری طور پر دوبارہ بھیج کر جواب دیتی ہے۔ جواب درخواست کردہ پیغامات کو […]
  • پیغام کی کاپیاں
    کچھ حالات میں، msg_id کے ساتھ ایک پرانا پیغام جو اب درست نہیں ہے اسے دوبارہ بھیجنے کی ضرورت ہے۔ پھر، اسے ایک کاپی کنٹینر میں لپیٹ دیا جاتا ہے:
    msg_copy#e06046b2 orig_message:Message = MessageCopy;
    ایک بار موصول ہونے کے بعد، پیغام پر اس طرح کارروائی کی جاتی ہے جیسے ریپر موجود نہ ہو۔ تاہم، اگر یہ یقینی طور پر جانا جاتا ہے کہ پیغام orig_message.msg_id موصول ہوا ہے، تو نئے پیغام پر کارروائی نہیں کی جاتی ہے (جبکہ ایک ہی وقت میں، یہ اور orig_message.msg_id کو تسلیم کیا جاتا ہے)۔ orig_message.msg_id کی قدر کنٹینر کے msg_id سے کم ہونی چاہیے۔

چلو کس بات پر بھی چپ رہو msgs_state_info ایک بار پھر نامکمل TL کے کان چپک رہے ہیں (ہمیں بائٹس کے ایک ویکٹر کی ضرورت تھی، اور نچلے دو بٹس میں ایک اینوم تھا، اور اوپر کے دو بٹس میں جھنڈے تھے)۔ بات الگ ہے۔ کیا کوئی سمجھتا ہے کہ یہ سب عملی طور پر کیوں ہے؟ ایک حقیقی کلائنٹ میں ضروری ہے؟... مشکل کے ساتھ، لیکن اگر کوئی شخص ڈیبگنگ میں مصروف ہے، اور انٹرایکٹو موڈ میں ہے تو کوئی کچھ فائدہ کا تصور کر سکتا ہے - سرور سے پوچھیں کہ کیا اور کیسے؟ لیکن یہاں درخواستیں بیان کی گئی ہیں۔ راؤنڈ ٹرپ.

اس کے بعد ہر فریق کو نہ صرف انکرپٹ اور پیغامات بھیجنے چاہئیں، بلکہ اپنے بارے میں، ان کے جوابات کے بارے میں، نامعلوم وقت کے لیے ڈیٹا کو ذخیرہ کرنا چاہیے۔ دستاویزات میں ان خصوصیات کے اوقات یا عملی اطلاق کی وضاحت نہیں کی گئی ہے۔ کرتا ہے. سب سے زیادہ حیرت انگیز بات یہ ہے کہ وہ اصل میں سرکاری گاہکوں کے کوڈ میں استعمال ہوتے ہیں! بظاہر انہیں کچھ بتایا گیا تھا جو عوامی دستاویزات میں شامل نہیں تھا۔ کوڈ سے سمجھیں۔ کیوں، اب اتنا آسان نہیں ہے جتنا TL کے معاملے میں - یہ (نسبتا) منطقی طور پر الگ تھلگ حصہ نہیں ہے، بلکہ ایپلیکیشن فن تعمیر سے منسلک ایک ٹکڑا ہے، یعنی ایپلیکیشن کوڈ کو سمجھنے کے لیے کافی زیادہ وقت درکار ہوگا۔

پنگ اور اوقات۔ قطاریں

ہر چیز سے، اگر ہم سرور کے فن تعمیر (بیک اینڈز میں درخواستوں کی تقسیم) کے بارے میں اندازے کو یاد رکھتے ہیں، تو ایک افسوسناک چیز اس کے بعد آتی ہے - ٹی سی پی میں تمام ترسیل کی ضمانتوں کے باوجود (یا تو ڈیٹا ڈیلیور کر دیا جائے گا، یا آپ کو اس فرق کے بارے میں مطلع کیا جائے گا، لیکن مسئلہ پیدا ہونے سے پہلے ڈیٹا ڈیلیور کر دیا جائے گا)، اس کی تصدیق خود MTProto میں ہوتی ہے۔ کوئی ضمانت نہیں. سرور آپ کے پیغام کو آسانی سے کھو سکتا ہے یا پھینک سکتا ہے، اور اس کے بارے میں کچھ نہیں کیا جا سکتا، بس مختلف قسم کی بیساکھیوں کا استعمال کریں۔

اور سب سے پہلے - پیغام کی قطاریں. ٹھیک ہے، ایک چیز کے ساتھ سب کچھ شروع سے ہی واضح تھا - ایک غیر مصدقہ پیغام کو ذخیرہ کرنا اور ناراض ہونا ضروری ہے۔ اور کس وقت کے بعد؟ اور مکار اسے جانتا ہے۔ شاید یہ عادی سروس پیغامات کسی نہ کسی طرح بیساکھیوں سے اس مسئلے کو حل کر دیتے ہیں، کہتے ہیں کہ ٹیلیگرام ڈیسک ٹاپ میں تقریباً 4 قطاریں ان سے ملتی جلتی ہیں (شاید مزید، جیسا کہ پہلے ذکر کیا جا چکا ہے، اس کے لیے آپ کو اس کے کوڈ اور فن تعمیر کو زیادہ سنجیدگی سے تلاش کرنے کی ضرورت ہے؛ اسی طرح وقت، ہم جانتے ہیں کہ اسے نمونے کے طور پر نہیں لیا جا سکتا؛ MTProto اسکیم کی مخصوص تعداد اس میں استعمال نہیں کی گئی ہے)۔

ایسا کیوں ہو رہا ہے؟ شاید، سرور پروگرامرز کلسٹر کے اندر قابل اعتمادی کو یقینی بنانے میں ناکام رہے، یا سامنے والے بیلنس پر بفرنگ بھی کر سکے، اور اس مسئلے کو کلائنٹ کو منتقل کر دیا۔ مایوسی کے عالم میں، واسیلی نے ایک متبادل آپشن کو نافذ کرنے کی کوشش کی، صرف دو قطاروں کے ساتھ، TCP سے الگورتھم کا استعمال کرتے ہوئے - سرور پر RTT کی پیمائش کرنا اور غیر مصدقہ درخواستوں کی تعداد کے لحاظ سے "ونڈو" (پیغامات میں) کے سائز کو ایڈجسٹ کرنا۔ یعنی، سرور کے بوجھ کا اندازہ لگانے کے لیے اس طرح کا ایک موٹا طریقہ یہ ہے کہ یہ ہماری کتنی درخواستیں ایک ہی وقت میں چبا سکتا ہے اور کھو نہیں سکتا۔

ٹھیک ہے، یہ ہے، آپ سمجھتے ہیں، ٹھیک ہے؟ اگر آپ کو TCP پر چلنے والے پروٹوکول کے اوپر دوبارہ TCP لاگو کرنا ہے، تو یہ ایک انتہائی خراب ڈیزائن کردہ پروٹوکول کی نشاندہی کرتا ہے۔

اوہ ہاں، آپ کو ایک سے زیادہ قطار کی ضرورت کیوں ہے، اور ویسے بھی ایک اعلیٰ سطحی API کے ساتھ کام کرنے والے شخص کے لیے اس کا کیا مطلب ہے؟ دیکھو، آپ ایک درخواست کرتے ہیں، اسے سیریلائز کرتے ہیں، لیکن اکثر آپ اسے فوری طور پر نہیں بھیج سکتے ہیں۔ کیوں؟ کیونکہ جواب ملے گا۔ msg_idجو کہ عارضی ہے۔аمیں ایک لیبل ہوں، جس کی تفویض کو جتنی دیر ہو سکے ملتوی کر دیا جاتا ہے - اگر سرور اسے ہمارے اور اس کے درمیان وقت کی مماثلت کی وجہ سے مسترد کر دیتا ہے (یقیناً، ہم ایک بیساکھی بنا سکتے ہیں جو ہمارے وقت کو موجودہ وقت سے بدل دیتا ہے۔ سرور میں ڈیلٹا شامل کرکے سرور کے جوابات سے حساب کیا جاتا ہے - سرکاری کلائنٹس ایسا کرتے ہیں، لیکن بفرنگ کی وجہ سے یہ خام اور غلط ہے)۔ لہذا، جب آپ لائبریری سے مقامی فنکشن کال کے ساتھ درخواست کرتے ہیں، تو پیغام درج ذیل مراحل سے گزرتا ہے:

  1. یہ ایک قطار میں ہے اور خفیہ کاری کا انتظار کر رہا ہے۔
  2. تعینات msg_id اور پیغام دوسری قطار میں چلا گیا - ممکنہ فارورڈنگ؛ ساکٹ پر بھیجیں.
  3. a) سرور نے MsgsAck کا جواب دیا - پیغام پہنچا دیا گیا تھا، ہم اسے "دوسری قطار" سے حذف کر دیتے ہیں۔
    ب) یا اس کے برعکس، اسے کچھ پسند نہیں آیا، اس نے جواب دیا badmsg - "دوسری قطار" سے دوبارہ بھیجیں
    c) کچھ معلوم نہیں ہے، پیغام کو دوسری قطار سے بھیجنے کی ضرورت ہے - لیکن یہ بالکل معلوم نہیں ہے کہ کب۔
  4. سرور نے آخر کار جواب دیا۔ RpcResult - اصل جواب (یا غلطی) - نہ صرف ڈیلیور کیا گیا بلکہ اس پر عملدرآمد بھی کیا گیا۔

شاید، کنٹینرز کا استعمال جزوی طور پر مسئلہ حل کرسکتا ہے۔ یہ تب ہوتا ہے جب پیغامات کا ایک گروپ ایک میں پیک کیا جاتا ہے، اور سرور نے ایک ہی وقت میں ان سب کی تصدیق کے ساتھ جواب دیا۔ msg_id. لیکن وہ اس پیک کو بھی مسترد کر دے گا، اگر کچھ غلط ہوا تو، مکمل طور پر۔

اور اس مقام پر غیر تکنیکی تحفظات کام میں آتے ہیں۔ تجربے سے، ہم نے بہت سی بیساکھییں دیکھی ہیں، اور اس کے علاوہ، اب ہم بری نصیحت اور فن تعمیر کی مزید مثالیں دیکھیں گے - ایسے حالات میں، کیا اس طرح کے فیصلے پر بھروسہ کرنا اور کرنا مناسب ہے؟ سوال بیاناتی ہے (یقیناً نہیں)۔

ہم کیا بات کر رہے ہیں؟ اگر "پیغامات کے بارے میں منشیات کے پیغامات" کے عنوان پر آپ اب بھی اعتراضات کے ساتھ قیاس کر سکتے ہیں جیسے "آپ بیوقوف ہیں، آپ نے ہمارے شاندار منصوبے کو نہیں سمجھا!" (لہذا پہلے دستاویزات لکھیں، جیسا کہ عام لوگوں کو چاہیے، معقولیت اور پیکٹ ایکسچینج کی مثالوں کے ساتھ، پھر ہم بات کریں گے)، پھر ٹائمنگ/ٹائم آؤٹ ایک خالصتاً عملی اور مخصوص سوال ہے، یہاں سب کچھ عرصہ دراز سے معلوم ہے۔ دستاویزات ہمیں ٹائم آؤٹ کے بارے میں کیا بتاتی ہیں؟

ایک سرور عام طور پر ایک RPC جواب کا استعمال کرتے ہوئے کلائنٹ (عام طور پر، ایک RPC استفسار) سے پیغام کی وصولی کو تسلیم کرتا ہے۔ اگر جواب آنے میں کافی وقت ہے، تو سرور پہلے ایک رسید کی تصدیق بھیج سکتا ہے، اور کچھ دیر بعد، RPC جواب خود بھیج سکتا ہے۔

ایک کلائنٹ عام طور پر سرور سے پیغام کی وصولی کو تسلیم کرتا ہے (عام طور پر، ایک RPC جواب) اگلی RPC استفسار میں ایک اعتراف شامل کرکے اگر اسے بہت دیر سے منتقل نہیں کیا جاتا ہے (اگر یہ پیدا ہوتا ہے تو، رسید کے 60-120 سیکنڈ بعد) سرور سے ایک پیغام)۔ تاہم، اگر لمبے عرصے کے لیے سرور کو پیغامات بھیجنے کی کوئی وجہ نہیں ہے یا اگر سرور سے غیر تسلیم شدہ پیغامات کی ایک بڑی تعداد موجود ہے (کہیں، 16 سے زیادہ)، کلائنٹ اسٹینڈ اکیلے اعتراف منتقل کرتا ہے۔

... میں ترجمہ کرتا ہوں: ہم خود نہیں جانتے کہ ہمیں اس کی کتنی اور کس طرح ضرورت ہے، تو آئیے مان لیتے ہیں کہ اسے ایسا ہی رہنے دیں۔

اور پنگ کے بارے میں:

پنگ پیغامات (PING/PONG)

ping#7abe77ec ping_id:long = Pong;

جواب عام طور پر اسی کنکشن پر واپس آتا ہے:

pong#347773c5 msg_id:long ping_id:long = Pong;

ان پیغامات کو تسلیمات کی ضرورت نہیں ہے۔ ایک پونگ صرف پنگ کے جواب میں منتقل ہوتا ہے جبکہ پنگ دونوں طرف سے شروع کیا جاسکتا ہے۔

موخر کنکشن بندش + پنگ

ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;

پنگ کی طرح کام کرتا ہے۔ اس کے علاوہ، اس کے موصول ہونے کے بعد، سرور ایک ٹائمر شروع کرتا ہے جو موجودہ کنکشن کو بند کر دے گا disconnect_delay سیکنڈ بعد جب تک کہ اسے اسی قسم کا نیا پیغام موصول نہ ہو جو خود بخود تمام پچھلے ٹائمرز کو دوبارہ ترتیب دے دیتا ہے۔ اگر کلائنٹ ہر 60 سیکنڈ میں ایک بار یہ پنگ بھیجتا ہے، مثال کے طور پر، یہ disconnect_delay کو 75 سیکنڈ کے برابر سیٹ کر سکتا ہے۔

کیا تم پاگل ہو؟! 60 سیکنڈ میں، ٹرین اسٹیشن میں داخل ہو جائے گی، مسافروں کو اتارے گی اور اٹھائے گی، اور دوبارہ سرنگ میں رابطہ منقطع ہو جائے گی۔ 120 سیکنڈ میں، جب آپ اسے سنیں گے، یہ ایک اور پر پہنچ جائے گا، اور کنکشن ٹوٹ جائے گا۔ ٹھیک ہے، یہ واضح ہے کہ ٹانگیں کہاں سے آرہی ہیں - "میں نے گھنٹی کی آواز سنی، لیکن نہیں معلوم کہ یہ کہاں ہے"، یہاں Nagl کا الگورتھم اور TCP_NODELAY آپشن ہے، جس کا مقصد انٹرایکٹو کام کرنا ہے۔ لیکن، معاف کیجئے گا، اس کی ڈیفالٹ ویلیو - 200 کو برقرار رکھیں ملیسیکنڈ اگر آپ واقعی کچھ ایسی ہی تصویر کشی کرنا چاہتے ہیں اور ممکنہ دو پیکٹوں پر محفوظ کرنا چاہتے ہیں، تو اسے 5 سیکنڈ کے لیے بند کر دیں، یا جو کچھ بھی ہو "صارف ٹائپ کر رہا ہے..." پیغام کا ٹائم آؤٹ اب ہے۔ لیکن مزید نہیں۔

اور آخر میں، پنگ. یعنی، TCP کنکشن کی جاندار جانچنا۔ یہ مضحکہ خیز ہے، لیکن تقریباً 10 سال پہلے میں نے اپنی فیکلٹی کے چھاترالی کے میسنجر کے بارے میں ایک تنقیدی تحریر لکھی تھی - وہاں کے مصنفین نے کلائنٹ سے سرور کو پنگ بھی کیا، نہ کہ اس کے برعکس۔ لیکن تیسرے سال کے طلباء ایک چیز ہیں، اور بین الاقوامی دفتر دوسری چیز ہے، ٹھیک ہے؟

سب سے پہلے، ایک چھوٹا سا تعلیمی پروگرام. ایک TCP کنکشن، پیکٹ ایکسچینج کی غیر موجودگی میں، ہفتوں تک زندہ رہ سکتا ہے۔ مقصد پر منحصر ہے، یہ اچھا اور برا دونوں ہے. یہ اچھا ہے اگر آپ کے پاس سرور سے ایس ایس ایچ کنکشن کھلا ہوا تھا، آپ کمپیوٹر سے اٹھے، راؤٹر کو ریبوٹ کیا، اپنی جگہ پر واپس آئے - اس سرور کے ذریعے ہونے والا سیشن پھٹا نہیں تھا (آپ نے کچھ بھی ٹائپ نہیں کیا، کوئی پیکٹ نہیں تھے) ، یہ آسان ہے. یہ برا ہے اگر سرور پر ہزاروں کلائنٹس ہیں، ہر ایک وسائل اٹھا رہا ہے (ہیلو، پوسٹگریس!)، اور کلائنٹ کے میزبان نے بہت عرصہ پہلے ریبوٹ کیا ہو گا - لیکن ہم اس کے بارے میں نہیں جان پائیں گے۔

چیٹ/IM سسٹم ایک اضافی وجہ سے دوسرے کیس میں آتے ہیں - آن لائن سٹیٹس۔ اگر صارف "گر گیا"، تو آپ کو اس کے بارے میں بات کرنے والوں کو مطلع کرنے کی ضرورت ہے۔ بصورت دیگر، آپ سے ایک غلطی ہو جائے گی جو جابر کے تخلیق کاروں نے کی تھی (اور اسے 20 سال تک درست کیا گیا تھا) - صارف نے رابطہ منقطع کر دیا ہے، لیکن وہ اسے پیغامات لکھتے رہتے ہیں، یہ مانتے ہوئے کہ وہ آن لائن ہے (جو ان میں بھی مکمل طور پر گم ہو گئے تھے۔ رابطہ منقطع ہونے سے چند منٹ پہلے)۔ نہیں، TCP_KEEPALIVE آپشن، جسے بہت سے لوگ نہیں سمجھتے ہیں کہ TCP ٹائمرز کیسے کام کرتے ہیں تصادفی طور پر (دسیوں سیکنڈز جیسی جنگلی قدریں ترتیب دے کر)، یہاں مدد نہیں کرے گا - آپ کو یہ یقینی بنانا ہوگا کہ نہ صرف OS کرنل صارف کی مشین زندہ ہے، لیکن عام طور پر کام کر رہی ہے، جواب دینے کے قابل ہے، اور ایپلیکیشن خود بھی (کیا آپ کو لگتا ہے کہ یہ منجمد نہیں ہو سکتی؟ Ubuntu 18.04 پر ٹیلیگرام ڈیسک ٹاپ میرے لیے ایک سے زیادہ بار منجمد ہو گیا)۔

اس لیے آپ کو پنگ لگانی ہوگی۔ سرور کلائنٹ، اور اس کے برعکس نہیں - اگر کلائنٹ ایسا کرتا ہے، اگر کنکشن ٹوٹ جاتا ہے، پنگ کی فراہمی نہیں ہوگی، مقصد حاصل نہیں ہوگا۔

ہم ٹیلیگرام پر کیا دیکھتے ہیں؟ یہ بالکل برعکس ہے! ٹھیک ہے، یہ ہے. رسمی طور پر، یقیناً، دونوں فریق ایک دوسرے کو پنگ دے سکتے ہیں۔ عملی طور پر، کلائنٹ ایک بیساکھی استعمال کرتے ہیں ping_delay_disconnect، جو سرور پر ٹائمر سیٹ کرتا ہے۔ ٹھیک ہے، معاف کیجئے گا، یہ کلائنٹ پر منحصر نہیں ہے کہ وہ پنگ کے بغیر وہاں کتنی دیر تک رہنا چاہتا ہے۔ سرور، اس کے بوجھ کی بنیاد پر، بہتر جانتا ہے۔ لیکن، یقیناً، اگر آپ کو وسائل پر کوئی اعتراض نہیں ہے، تو آپ اپنے ہی برے پنوچیو ہوں گے، اور ایک بیساکھی کرے گی...

اسے کیسے ڈیزائن کیا جانا چاہیے تھا؟

مجھے یقین ہے کہ مندرجہ بالا حقائق واضح طور پر اس بات کی نشاندہی کرتے ہیں کہ ٹیلیگرام/VKontakte ٹیم کمپیوٹر نیٹ ورکس کی نقل و حمل (اور نچلی) سطح اور متعلقہ معاملات میں ان کی کم قابلیت کے شعبے میں زیادہ قابل نہیں ہے۔

یہ اتنا پیچیدہ کیوں نکلا، اور ٹیلیگرام کے معمار کس طرح اعتراض کرنے کی کوشش کر سکتے ہیں؟ حقیقت یہ ہے کہ انہوں نے ایسا سیشن بنانے کی کوشش کی جو TCP کنکشن ٹوٹنے سے بچ جائے، یعنی جو ابھی ڈیلیور نہیں ہوا، ہم بعد میں ڈیلیور کریں گے۔ انہوں نے شاید UDP ٹرانسپورٹ بنانے کی بھی کوشش کی، لیکن انہیں مشکلات کا سامنا کرنا پڑا اور انہوں نے اسے ترک کر دیا (اسی وجہ سے دستاویزات خالی ہیں - شیخی مارنے کے لیے کچھ نہیں تھا)۔ لیکن عام طور پر نیٹ ورکس اور خاص طور پر TCP کس طرح کام کرتے ہیں، آپ اس پر کہاں بھروسہ کر سکتے ہیں، اور آپ کو خود یہ کہاں کرنے کی ضرورت ہے (اور کیسے)، اور اسے خفیہ نگاری کے ساتھ جوڑنے کی کوشش کی وجہ سے "دو پرندے" ایک پتھر"، یہ نتیجہ ہے.

یہ کیسا ضروری تھا؟ اس حقیقت کی بنیاد پر msg_id ری پلے حملوں کو روکنے کے لیے کرپٹوگرافک نقطہ نظر سے ٹائم اسٹیمپ ضروری ہے، اس کے ساتھ ایک منفرد شناخت کنندہ فنکشن منسلک کرنا غلطی ہے۔ لہذا، موجودہ فن تعمیر کو بنیادی طور پر تبدیل کیے بغیر (جب اپ ڈیٹس کا سلسلہ تیار ہوتا ہے، یہ پوسٹس کی اس سیریز کے دوسرے حصے کے لیے ایک اعلیٰ سطح کا API موضوع ہے)، کسی کو یہ کرنے کی ضرورت ہوگی:

  1. کلائنٹ کے ساتھ TCP کنکشن رکھنے والا سرور ذمہ داری لیتا ہے - اگر اس نے ساکٹ سے پڑھا ہے، تو براہ کرم غلطی کو تسلیم کریں، کارروائی کریں یا واپس کریں، کوئی نقصان نہیں۔ پھر تصدیق ids کا ویکٹر نہیں ہے، بلکہ صرف "آخری موصول شدہ seq_no" - صرف ایک نمبر، جیسا کہ TCP میں ہے (دو نمبر - آپ کا seq اور تصدیق شدہ ایک)۔ ہم ہمیشہ سیشن کے اندر رہتے ہیں، کیا ہم نہیں ہیں؟
  2. ری پلے حملوں کو روکنے کے لیے ٹائم اسٹیمپ ایک الگ فیلڈ بن جاتا ہے، ایک لا نونس۔ یہ چیک کیا جاتا ہے، لیکن کسی اور چیز کو متاثر نہیں کرتا. کافی اور uint32 - اگر ہمارا نمک کم از کم ہر آدھے دن میں تبدیل ہوتا ہے، تو ہم موجودہ وقت کے ایک عددی حصے کے کم ترتیب والے بٹس کے لیے 16 بٹس مختص کر سکتے ہیں، باقی - ایک سیکنڈ کے جزوی حصے میں (جیسا کہ اب)۔
  3. ہٹا دیا گیا۔ msg_id بالکل - بیک اینڈ پر درخواستوں کو الگ کرنے کے نقطہ نظر سے، سب سے پہلے، کلائنٹ آئی ڈی، اور دوم، سیشن آئی ڈی، ان کو جوڑتا ہے۔ اس کے مطابق، درخواست کے شناخت کنندہ کے طور پر صرف ایک چیز کافی ہے۔ seq_no.

یہ بھی سب سے کامیاب آپشن نہیں ہے؛ ایک مکمل رینڈم ایک شناخت کنندہ کے طور پر کام کر سکتا ہے - ویسے، پیغام بھیجتے وقت یہ اعلیٰ سطحی API میں پہلے ہی ہو چکا ہے۔ بہتر ہو گا کہ فن تعمیر کو مکمل طور پر رشتہ دار سے مطلق تک دوبارہ بنایا جائے، لیکن یہ اس پوسٹ کا نہیں بلکہ دوسرے حصے کا موضوع ہے۔

API؟

تا دام! لہذا، درد اور بیساکھیوں سے بھرے راستے سے جدوجہد کرنے کے بعد، ہم آخر کار سرور کو کوئی بھی درخواست بھیجنے اور ان کے جوابات حاصل کرنے کے ساتھ ساتھ سرور سے اپ ڈیٹس حاصل کرنے میں کامیاب ہوئے (کسی درخواست کے جواب میں نہیں، بلکہ یہ خود ہمیں بھیجتا ہے، جیسے PUSH، اگر کوئی اس طرح واضح ہے)۔

توجہ، اب مضمون میں پرل میں واحد مثال ہو گی! (ان کے لیے جو نحو سے واقف نہیں ہیں، برکت کی پہلی دلیل آبجیکٹ کا ڈیٹا ڈھانچہ ہے، دوسری اس کی کلاس ہے):

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' )
};

جی ہاں، جان بوجھ کر خراب کرنے والا نہیں - اگر آپ نے اسے ابھی تک نہیں پڑھا ہے، تو آگے بڑھیں اور اسے کریں!

اوہ، وائی~~... یہ کیسا لگتا ہے؟ کچھ بہت مانوس... ہو سکتا ہے یہ JSON میں ایک عام ویب API کا ڈیٹا سٹرکچر ہے، سوائے اس کے کہ کلاسز بھی اشیاء سے منسلک ہیں؟...

تو یہ اس طرح ہوتا ہے... یہ سب کیا ہے، کامریڈز؟... اتنی کوشش - اور ہم ویب پروگرامرز کی جگہ آرام کرنے کے لیے رک گئے۔ ابھی شروع ہو رہا ہے۔کیا صرف JSON HTTPS پر آسان نہیں ہوگا؟! بدلے میں ہمیں کیا ملا؟ کیا کوشش اس کے قابل تھی؟

آئیے جائزہ لیں کہ TL+MTProto نے ہمیں کیا دیا اور کون سے متبادل ممکن ہیں۔ ٹھیک ہے، HTTP، جو درخواست کے جواب کے ماڈل پر توجہ مرکوز کرتا ہے، ایک خراب فٹ ہے، لیکن کم از کم TLS کے اوپر کچھ ہے؟

کومپیکٹ سیریلائزیشن۔ اس ڈیٹا سٹرکچر کو دیکھ کر، JSON کی طرح، مجھے یاد آیا کہ اس کے بائنری ورژن موجود ہیں۔ آئیے MsgPack کو ناکافی طور پر قابل توسیع کے طور پر نشان زد کریں، لیکن وہاں ہے، مثال کے طور پر، CBOR - ویسے، ایک معیار بیان کیا گیا ہے آر ایف سی 7049. یہ اس حقیقت کے لئے قابل ذکر ہے کہ یہ وضاحت کرتا ہے۔ ٹیگزایک توسیعی طریقہ کار کے طور پر، اور درمیان پہلے سے ہی معیاری دستیاب:

  • 25 + 256 - بار بار لائنوں کو لائن نمبر کے حوالے سے تبدیل کرنا، ایسا کمپریشن طریقہ
  • 26 - کلاس کے نام اور کنسٹرکٹر کے دلائل کے ساتھ سیریلائزڈ پرل آبجیکٹ
  • 27 - قسم کے نام اور تعمیر کنندہ کے دلائل کے ساتھ سیریلائزڈ زبان سے آزاد آبجیکٹ

ٹھیک ہے، میں نے اسی ڈیٹا کو TL اور CBOR میں سٹرنگ اور آبجیکٹ پیکنگ کے ساتھ سیریلائز کرنے کی کوشش کی۔ نتیجہ ایک میگا بائٹ سے کہیں CBOR کے حق میں مختلف ہونا شروع ہوا:

cborlen=1039673 tl_len=1095092

اس طرح، نتیجہ: کافی حد تک آسان فارمیٹس ہیں جو مطابقت پذیری کی ناکامی یا نامعلوم شناخت کنندہ کے مسئلے سے مشروط نہیں ہیں، موازنہ کارکردگی کے ساتھ۔

تیز رفتار کنکشن کا قیام. اس کا مطلب ہے دوبارہ کنکشن کے بعد صفر RTT (جب کلید پہلے ہی ایک بار تیار ہو چکی ہے) - پہلے ہی MTProto پیغام سے لاگو ہوتا ہے، لیکن کچھ تحفظات کے ساتھ - ایک ہی نمک مارو، سیشن بوسیدہ نہیں ہے، وغیرہ۔ اس کے بجائے TLS ہمیں کیا پیش کرتا ہے؟ موضوع پر اقتباس:

TLS میں PFS استعمال کرتے وقت، TLS سیشن ٹکٹ (آر ایف سی 5077) کیز پر دوبارہ گفت و شنید کیے بغیر اور کلیدی معلومات کو سرور پر محفوظ کیے بغیر ایک خفیہ کردہ سیشن کو دوبارہ شروع کرنا۔ پہلا کنکشن کھولنے اور چابیاں بناتے وقت، سرور کنکشن کی حالت کو خفیہ کرتا ہے اور اسے کلائنٹ تک پہنچاتا ہے (سیشن ٹکٹ کی شکل میں)۔ اس کے مطابق، جب کنکشن دوبارہ شروع کیا جاتا ہے، کلائنٹ ایک سیشن ٹکٹ بشمول سیشن کی کو واپس سرور کو بھیجتا ہے۔ ٹکٹ خود ایک عارضی کلید (سیشن ٹکٹ کی کلید) کے ساتھ انکرپٹ کیا جاتا ہے، جو سرور پر محفوظ ہوتا ہے اور اسے کلسٹرڈ سلوشنز میں SSL پروسیس کرنے والے تمام فرنٹ اینڈ سرورز میں تقسیم کیا جانا چاہیے۔[10]۔ اس طرح، سیشن ٹکٹ کا تعارف PFS کی خلاف ورزی کر سکتا ہے اگر عارضی سرور کیز سے سمجھوتہ کیا جاتا ہے، مثال کے طور پر، جب وہ لمبے عرصے تک محفوظ رہتی ہیں (OpenSSL، nginx، Apache انہیں پروگرام کی پوری مدت کے لیے بطور ڈیفالٹ اسٹور کرتی ہیں؛ مقبول سائٹس استعمال کرتی ہیں کئی گھنٹوں کی کلید، دنوں تک)۔

یہاں RTT صفر نہیں ہے، آپ کو کم از کم ClientHello اور ServerHello کا تبادلہ کرنا ہوگا، جس کے بعد کلائنٹ Finished کے ساتھ ڈیٹا بھیج سکتا ہے۔ لیکن یہاں ہمیں یاد رکھنا چاہیے کہ ہمارے پاس ویب نہیں ہے، جس کے نئے کھولے گئے کنکشن ہیں، بلکہ ایک میسنجر ہے، جس کا کنکشن اکثر ایک یا زیادہ یا کم طویل عرصے تک ہوتا ہے، ویب صفحات کے لیے نسبتاً مختصر درخواستیں - ہر چیز ملٹی پلیکس ہوتی ہے۔ اندرونی طور پر یعنی، یہ کافی قابل قبول ہے اگر ہم واقعی خراب سب وے سیکشن میں نہ آئے۔

کچھ اور بھول گئے؟ کمنٹس میں لکھیں۔

جاری ہے!

پوسٹس کے اس سلسلے کے دوسرے حصے میں ہم تکنیکی نہیں بلکہ تنظیمی مسائل پر غور کریں گے - نقطہ نظر، نظریہ، انٹرفیس، صارفین کے تئیں رویہ وغیرہ۔ تاہم، اس تکنیکی معلومات کی بنیاد پر جو یہاں پیش کی گئی تھی۔

تیسرا حصہ تکنیکی اجزاء/ترقیاتی تجربے کا تجزیہ کرتا رہے گا۔ آپ سیکھیں گے، خاص طور پر:

  • مختلف قسم کی TL اقسام کے ساتھ پنڈمونیم کا تسلسل
  • چینلز اور سپر گروپس کے بارے میں نامعلوم چیزیں
  • ڈائیلاگ روسٹر سے بدتر کیوں ہیں۔
  • مطلق بمقابلہ رشتہ دار پیغام ایڈریسنگ کے بارے میں
  • تصویر اور تصویر میں کیا فرق ہے؟
  • ایموجی کس طرح ترچھے متن میں مداخلت کرتے ہیں۔

اور دیگر بیساکھی! دیکھتے رہنا!

ماخذ: www.habr.com

نیا تبصرہ شامل کریں