ترويض WebSocket مع القرمزي

كيف قمنا بتطوير Scarlet ، مكتبة Kotlin المعلنة ، لتسهيل تكامل WebSocket على Android.

في تطبيقات الهاتف المحمول ، طبقة البيانات هي مصدر الحقيقة لما يتم عرضه على الشاشة. ومع ذلك ، أصبح الحفاظ على ذلك بمثابة صداع عندما قمنا بدمج واجهات برمجة تطبيقات WebSocket في Tinder في وقت سابق من هذا العام. لتسهيل تكامل WebSocket على Android ، قمنا بتطوير Scarlet ، مكتبة Kotlin معلنة.

WebSocket هي أداة قوية لإنشاء تطبيقات في الوقت الفعلي مثل الدردشة ولعبة متعددة اللاعبين عبر الإنترنت وخلاصة في الوقت الفعلي. يؤسس اتصال ثنائي الاتجاه بين العميل والخادم. أثناء فتح الاتصال ، يمكنهم إرسال الرسائل النصية والثنائية ذهابًا وإيابًا مع انخفاض النفقات العامة. في ما يلي مثال على كيفية إنشاء اتصال WebSocket في جافا سكريبت عادي.

WebSocket مع القرمزي

من السهل إعداد وصيانة Scarlet: الإعلان عن عميل واجهة برمجة تطبيقات WebSocket بسيط مثل الإعلان عن الطرق على واجهة. عندما تمرر الواجهة الخاصة بك إلى Scarlet ، فإنها ستؤدي إلى تنفيذ. على سبيل المثال ، تأخذ GDAX WebSocket Feed API ، التي تقدم أسعار العملات الرقمية في الوقت الحقيقي عبر WebSocket ، 9 أسطر من التعليمات البرمجية للتكامل مع Scarlet ، بينما تتطلب مكتبات WebSocket الأخرى مئات الأسطر من التعليمات البرمجية.

القرمزي يفسر الطرق في GdaxService باستخدام الانعكاس.

  • يأخذ أسلوب إرسال التعليقات التوضيحية @ معلمة واحدة. عند استدعاء ، يرسل رسالة صادرة إلى الخادم.
  • من ناحية أخرى ، تُرجع طريقة التعليقات المُعلَّقةRive تدفقًا من الرسائل أو الأحداث الواردة حول حالة الاتصال الحالية. تحتاج إلى الاشتراك في الدفق لمراقبة القيم.

وفقًا لوثائق GDAX API ، لبدء تلقي السعر في الوقت الفعلي Tickerfrom GDAX ، يجب على العميل أولاً إرسال رسالة اشتراك إلى الخادم تشير إلى القنوات والمنتجات التي يرغب في تلقيها.

يمكن الإعلان عن الرسائل على أنها فئات البيانات. في هذا المثال ، نحن مهتمون بسعر Bitcoin بالدولار الأمريكي. لذا نريد الاشتراك في قناة "BTC-USD".

أرسل رسالة اشتراك عند فتح الاتصال وسيبدأ الخادم في دفق المؤشرات التي تحتوي على أحدث سعر.

إلى جانب وجود واجهة برمجة تطبيقات تعريفية ، فإن Scarlet هي أيضًا وحدات قابلة للتخصيص وقابلة للتوسيع بسهولة لأنها تتبع بنية البرنامج المساعد. يتم تغليف سلوكياتها بواسطة تجريدات مفيدة يمكن استبدالها بسهولة مثل الإضافات. بالإضافة إلى الاختيار من بين مجموعة متنوعة من المكونات الإضافية المضمنة ، فأنت مفوض لتوفير المكونات الإضافية الخاصة بك عند بناء مثيل Scarlet.

يتطلب مثال GDAX ثلاثة مكونات إضافية مضمنة:

  • تطبيق WebSocket مبني على OkHttp.
  • A MoshiMessageAdapter.Factory ، والذي يستخدم موشي لتسلسل البيانات. يدعم Scarlet أيضًا Gson و protobuf. إذا لم تحدد أي MessageAdapter.Factory ، يمكنك استخدام String أو ByteArray.
  • يتم استخدام RxJava2StreamAdapter.Factory لدعم RxJava2. يدعم Scarlet أيضًا RxJava1. إذا لم تقدم أي StreamAdapter.Factory ، يمكنك استخدام البث المدمج.

التكامل مع Android

عندما يكون الاتصال مفتوحًا ، يكون WebSocket واضحًا. ومع ذلك ، فإنه يتطلب جهودًا إضافية على الهاتف المحمول بسبب طبيعته ذات الحالة. قد يتم إغلاق اتصال WebSocket لأسباب عديدة:

  • شبكة غير مستقرة
  • إغلاق الخادم لتحرير الموارد
  • يدخل التطبيق الخلفية للحفاظ على البطارية

عند إغلاق الاتصال ، يحتاج العميل إلى تحديد موعد إعادة المحاولة. بينما تحمل مكتبات WebSocket الأخرى المطور مسؤولية إبقاء الاتصال مفتوحًا ، يدير Scarlet عمليات إعادة المحاولة ويجعل حالة الاتصال شفافة للمطور. يتم تحقيق ذلك بمساعدة اثنين من التجريدات: Lifecycleand و BackoffStr Strategy.

تُعلم دورة الحياة سكارليت بموعد الاتصال بالخادم والاستمرار في إعادة المحاولة إذا انقطع الخادم. كتدفق من Lifecycle.State (بدء وإيقاف) ، فإنه يغلف نطاق اتصال WebSocket. دورة الحياة مفيدة بشكل خاص على Android لأنها قابلة لإعادة الاستخدام والتركيب ؛ مثل:

  • لإبقاء الاتصال مفتوحًا فقط عندما يكون التطبيق في المقدمة ، يمكنك كتابة دورة حياة لنطاق مقدمة التطبيق. (يأتي Scarlet مزودًا بنظام AndroidLifecycleplugin بحيث لا تضطر إلى كتابة واحد.)
  • لإبقاء الاتصال مفتوحًا فقط عندما يقوم المستخدم بتسجيل الدخول ، يمكنك إنشاء دورة حياة لنطاق تسجيل الدخول.
  • لتلبية كلا الشرطين ، يمكنك ببساطة الجمع بين دورات الحياة الخاصة بهم لإنشاء مقدمة التطبيق ونطاق تسجيل دخول المستخدم.

عند بدء تشغيل Lifecycle.State الحالية ، يستخدم Scarlet إستراتيجية BackoffStrUCTION لتحديد عدد مرات إعادة المحاولة بعد كل فشل في الاتصال. يأتي Scarlet مع ثلاث استراتيجيات للتراجع: LinearBackoffStr Strategy و ExponentialBackoffStr Strategy و ExponentialWithJitterBackoffStrategy. لمزيد من المعلومات حول اختيار استراتيجيات التراجع ، يرجى الاطلاع على التراجع الأسي والارتعاش.

مع تحديد دورة الحياة و BackoffStr Strategy المرغوبة ، يعالج Scarlet فشل الاتصال بأمان.

اختبارات الكتابة للقرمزي

بعد إنشاء مثيل Scarlet ، يتم إدخال تغييرات دورة الحياة في جهاز الحالة الداخلية الذي يدير مكالمات الشبكة. لجعل انتقالات الحالة إعلانية وقابلة للقراءة ، اخترعنا Kotlin DSL لكتابة آلة حالة Scarlet. لمزيد من المعلومات ، يرجى الاطلاع على StateMachine على Github.

آلة الحالة ، مع الحالات والأحداث الثابتة ، ينتج عنها كود قابل للاختبار للغاية. بالإضافة إلى ذلك ، تأتي سكارليت مع أدوات اختبار إعلانية تجعل التأكيدات حول انتقالات الحالة قابلة للقراءة في اختبارات الوحدة.

ولكن ما يجعل اختبارات التكامل قابلة للقراءة حقًا هو الفصل من OkHttpClient. يؤكد اختبار التكامل التفاعلات بين عميل Scarlet WebSocket وخادم WebSocket وهمية. في البداية ، اقترن Scarlet بـ OkHttpClient وعمل فقط على جانب العميل. جعلت أدوات الاختبار التوضيحية الخاصة بنا الدول العميلة قابلة للتأكيد بسهولة. ولكن لتأكيد حالات الخادم ، كان علينا استخدام مجموعة مختلفة من واجهات برمجة التطبيقات حول MockWebServer. إن المزيج بين نمطين مختلفين للتأكيد جعل اختبارات التكامل مربكة.

لتوحيد واجهات برمجة التطبيقات للاختبار المستخدمة في اختبارات التكامل ، قمنا بعكس الاعتماد على OkHttpClient بحيث يعمل Scarlet أيضًا على جانب الخادم. لقد صنعنا مكونات OkHttpClient و MockWebServer من Scarlet. لم يعمل هذا التغيير على تحسين إمكانية قراءة اختبارات التكامل فحسب ، بل سمح أيضًا لـ Scarlet بالعمل مع أي مكتبات WebSocket في المستقبل.

شكرا للقراءة! يرجى تجربة سكارليت وإخبارنا برأيك. Scarlet هي إحدى الأدوات التي صنعناها داخليًا. يتم استخدامه حاليًا بواسطة تطبيق Tinder Android في الإنتاج ، حيث يخدم ملايين المستخدمين ويتعامل مع مليارات من رسائل WebSocket كل يوم. إذا كان جزءًا من هذا أمرًا مثيرًا للاهتمام بالنسبة لك ، فلا تتردد في التواصل معيzhxnlai ، أو يمكنك عرض الوظائف الشاغرة هنا في Tinder - نحن نبحث دائمًا عن مهندسين موهوبين للانضمام إلى فريقنا!