تنفيذ خادم المراسلة الغرفة التي تستخدم بروتوكول RPC ثنائي الاتجاه لتنفيذ اتصال يشبه الدردشة. تم تصميمه للتعامل مع مشاكل مراسلة الشبكة العامة الشائعة مثل التسليم الموثوق به ، واتصالات متعددة من مستخدم واحد ، وأذونات في الوقت الفعلي ووجودها. تطلب RPC المعالجة وتنسيق رسائل الغرفة قابلة للتخصيص عبر السنانير ، مما يسمح بتنفيذ أي شيء من خادم غرف الدردشة إلى تطبيق تعاوني مع دقة تعارض معقدة. يمكن أيضًا استخدام رسائل الغرف لإنشاء واجهات برمجة التطبيقات العامة أو لنفق الاتصالات M2M لأجهزة إنترنت الأشياء.
مراسلة غرفة موثوقة باستخدام تخزين تاريخ جانب الخادم وواجهة برمجة تطبيقات التزامن.
تنسيق الرسائل التعسفية عبر وظيفة التحقق من الصحة (الخطاف) فقط ، مما يسمح بتنسيقات الرسائل المخصصة/غير المخصصة (بما في ذلك البيانات الثنائية داخل الرسائل).
لكل غرفة واجهة برمجة تطبيقات وجود المستخدم مع الإخطارات.
إنشاء غرفة الوقت الحقيقي وواجهة برمجة تطبيقات إدارة أذونات المستخدمين في الغرفة. يدعم القائمة السوداء أو أوضاع الوصول القائمة على القائمة البيضاء ومجموعة المسؤولين الاختيارية.
دعم سلس لاتصالات المستخدمين المتعددين من مختلف الخلافات إلى أي مثيل خدمة.
يتم كتابة الخدمات المجهرية عديمة الجنسية ، ويستخدم Redis (يدعم أيضًا تكوينات الكتلة) كمتجر حكومي ، يمكن تحجيمها أفقياً عند الطلب.
دعم تخصيص واسع النطاق. يمكن إضافة وظيفة مخصصة عبر السنانير قبل/بعد أي معالجة طلب العميل. والطلبات (الأوامر) يمكن استدعاء جانب الخادم جانب الخادم عبر واجهة برمجة التطبيقات.
النقل الشبكات القابلة للمكونات. يتم الاتصال خادم العميل عبر بروتوكول RPC ثنائي الاتجاه. يتم تضمين تنفيذ Socket.io للنقل.
متجر الدولة القابل للإضافات. يتم تضمين متاجر الذاكرة و Redis.
يدعم مستخدم خفيفة الوزن عبر الإنترنت لرسائل المستخدم عبر الإنترنت.
اقرأ هذه المقالة لمزيد من المعلومات الأساسية.
هذا المشروع عبارة عن وحدة عقدة متوفرة عبر NPM. اذهب إلى التحقق منها إذا لم يكن لديك تثبيت محليًا.
$ npm i chat-serviceحدد أولاً تكوين الخادم. على جانب الخادم ، حدد خطاف اتصال المقبس ، حيث تعتمد الخدمة على تطبيق مصادقة خارجي. يحتاج المستخدم فقط إلى تمرير التحقق من المصادقة ، ولا يلزم إضافة مستخدم صريح.
const ChatService = require ( 'chat-service' )
const port = 8000
function onConnect ( service , id ) {
// Assuming that auth data is passed in a query string.
let { query } = service . transport . getHandshakeData ( id )
let { userName } = query
// Actually check auth data.
// ...
// Return a promise that resolves with a login string.
return Promise . resolve ( userName )
} إنشاء خادم هو مثيل كائن بسيط. ملاحظة: يجب استدعاء طريقة close لإغلاق مثيل خدمة بشكل صحيح (انظر استرداد الفشل).
const chatService = new ChatService ( { port } , { onConnect } )
process . on ( 'SIGINT' , ( ) => chatService . close ( ) . finally ( ( ) => process . exit ( ) ) ) يعمل الخادم الآن على المنفذ 8000 ، باستخدام حالة memory . بشكل افتراضي '/chat-service' يتم استخدام مساحة اسم Socket.io. أضف غرفة مع مستخدم admin كمالك للغرفة. يجب إنشاء جميع الغرف بشكل صريح (يتم توفير خيار للسماح بإنشاء الغرف من جانب العميل أيضًا).
// The room configuration and messages will persist if redis state is
// used. addRoom will reject a promise if the room is already created.
chatService . hasRoom ( 'default' ) . then ( hasRoom => {
if ( ! hasRoom ) {
return chatService . addRoom ( 'default' , { owner : 'admin' } )
}
} ) على العميل ، هناك حاجة إلى تطبيق socket.io-client . لإرسال طلب (أمر) استخدم طريقة emit ، سيتم إرجاع النتيجة (أو خطأ) في رد الاتصال Socket.io ACK. للاستماع إلى رسائل الخادم ، استخدم on الطريقة.
const io = require ( 'socket.io-client' )
// Use https or wss in production.
let url = 'ws://localhost:8000/chat-service'
let userName = 'user' // for example and debug
let token = 'token' // auth token
let query = `userName= ${ userName } &token= ${ token } `
let opts = { query }
// Connect to a server.
let socket = io . connect ( url , opts )
// Rooms messages handler (own messages are here too).
socket . on ( 'roomMessage' , ( room , msg ) => {
console . log ( ` ${ msg . author } : ${ msg . textMessage } ` )
} )
// Auth success handler.
socket . on ( 'loginConfirmed' , userName => {
// Join room named 'default'.
socket . emit ( 'roomJoin' , 'default' , ( error , data ) => {
// Check for a command error.
if ( error ) { return }
// Now we will receive 'default' room messages in 'roomMessage' handler.
// Now we can also send a message to 'default' room:
socket . emit ( 'roomMessage' , 'default' , { textMessage : 'Hello!' } )
} )
} )
// Auth error handler.
socket . on ( 'loginRejected' , error => {
console . error ( error )
} ) إنه رمز قابل للتشغيل ، والملفات في دليل example .
من الممكن استخدام عمليات نقل أخرى غير Socket.io. هناك دليل على نقل المفاهيم ، يستخدم اتصال WebSocket مع بعض الحد الأدنى من طبقة تجريد API WS-Messaging ومساعد البوبسوب البسيط باعتباره تجريد مروحة الرسائل الخلفية.
فيما يلي الأشياء الرئيسية التي يجب أن يسمح بها النقل:
أرسل رسائل من خادم إلى مجموعات من العملاء (استنادًا إلى معايير مطابقة واحدة كاملة ، AKA Room Messaging).
قم بتنفيذ طلب الاتصالات من عميل إلى خادم.
قم بتنفيذ نوع من الاتصال المستمر (أو ما يعادله بشكل دلالي) ، وهو مطلوب لتتبع التواجد.
تستخدم خدمة الدردشة Redis كمتجر مشترك مع الثبات. في تطبيق حقيقي ، قد تكون هناك حاجة إلى بعض هذه المعلومات من قبل الخدمات الأخرى ، ولكن ليس من العملي إعادة تخزين المتجر الحكومي بالكامل. نهج بديل أفضل هو استخدام السنانير. على سبيل المثال ، لحفظ جميع رسائل الغرفة داخل قاعدة بيانات أخرى ، يمكن استخدام خطاف roomMessageAfter . يمكن أيضًا تعريض ServiceAPI من خلال حافلات المراسلة الخلفية إلى الخوادم الداخلية الأخرى.
في ظل الظروف العادية ، فإن جميع الأخطاء التي يتم إرجاعها إلى مستخدم خدمة (عبر ردود الطلب أو الرسائل loginConfirmed أو loginRejected ) هي مثيلات من ChatServiceError . تشير جميع الأخطاء الأخرى إلى وجود خطأ في البرنامج أو فشل في البنية التحتية للخدمة. لتمكين تسجيل تصحيح الأخطاء لمثل هذه الأخطاء ، استخدم export NODE_DEBUG=ChatService . تستخدم المكتبة BlueBird ^3.0.0 Promaintation ، لذلك لتمكين آثار المكدس الطويلة استخدام export BLUEBIRD_DEBUG=1 . يوصى بشدة باستخدام إصدارات الوعد من واجهات برمجة التطبيقات لخطافات ودردشة ChatServiceError لإرجاع الأخطاء المخصصة لسنانير.
وثيقة Server Side API و RPC متوفرة عبر الإنترنت.
تعمل الخدمة على ملخص تمامًا مفهوم اتصال من مفهوم المستخدم ، بحيث يمكن للمستخدم الواحد الحصول على أكثر من اتصال واحد (بما في ذلك الاتصالات عبر العقد المختلفة). لوجود المستخدم ، يجب أن يكون عدد المقابس المرتبطة أكبر من الصفر. جميع واجهات برمجة التطبيقات المصممة للعمل على مستوى المستخدم ، والتعامل مع اتصالات المستخدم المتعددة بسلاسة.
الاتصالات مستقلة تمامًا ، لا يلزم وجود دعم جانبي إضافي للعميل. ولكن هناك رسائل وأوامر معلومات يمكن استخدامها للحصول على معلومات حول اتصالات المستخدم الأخرى. يجعل من الممكن إدراك أنماط المزامنة من جانب العميل ، مثل الحفاظ على جميع الاتصالات المراد انضمامها إلى نفس الغرف.
كل غرفة لديها نظام أذونات. يوجد مستخدم مالك واحد ، يحتوي على جميع امتيازات المسؤولين ويمكنه تعيين المستخدمين لمجموعة المسؤولين. يمكن للمسؤولين إدارة أذونات وصول المستخدمين الآخرين. يتم دعم وضعين: القائمة السوداء وقائمة البيت. بعد تعديلات قوائم الوصول/الوضع ، تقوم الخدمة تلقائيًا بإزالة المستخدمين الذين فقدوا إذن الوصول.
إذا تم تمكين خيارات enableRoomsManagement ، فيمكن للمستخدمين إنشاء غرف عبر أمر roomCreate . سيكون منشئ الغرفة هو المالك ويمكنه أيضًا حذفه عبر أمر roomDelete .
قبل استخدام السنانير لتنفيذ أنظمة أذونات إضافية.
عندما يرسل المستخدم رسالة غرفة ، في RPC ، يتم إرجاع id الرسالة. وهذا يعني أن الرسالة قد تم حفظها في متجر (في إحدى البنية المشابهة فقط للهيكل الدائري). معرفات رسائل الغرفة هي تسلسل يبدأ من 1 ، ويزداد بنسبة واحدة لكل رسالة تم إرسالها بنجاح في الغرفة. يمكن للعميل دائمًا التحقق من آخر معرف رسالة الغرفة عبر أمر roomHistoryInfo ، واستخدام أمر roomHistoryGet للحصول على الرسائل المفقودة. يضمن هذا النهج استلام رسالة ، ما لم يتم حذفها بسبب الدوران.
بشكل افتراضي ، يمكن للعميل إرسال رسائل تقتصر على مجرد {textMessage: 'Some string'} . لتمكين تنسيق الرسائل المخصصة ، توفير السنانير directMessagesChecker أو roomMessagesChecker . عندما يحل الخطاف ، يتم قبول تنسيق الرسالة. يمكن أن تكون الرسائل بيانات تعسفية مع بعض القيود. يجب أن يكون المستوى الأعلى Object ، بدون حقول timestamp أو author أو id (ستملأ الخدمة هذه الحقول قبل إرسال الرسائل). يمكن أن تشمل المستويات المتداخلة أنواع البيانات التعسفية (حتى ثنائية) ، ولكن لا توجد كائنات متداخلة مع type حقل تم تعيينها على 'Buffer' (المستخدمة لمعالجة البيانات الثنائية).
يدعم كل أمر مستخدم قبل إضافة الخطاف وبعده ، ويتم دعم خطافات الاتصال/فصل العميل أيضًا. يتم تنفيذ الأوامر والسنانير بالتتابع: قبل الخطاف - الأمر - بعد الخطاف (سيتم استدعاؤه على أخطاء الأوامر أيضًا). إنهاء التسلسل قبل السنانير ممكن. يمكن للعملاء إرسال وسيطات قيادة إضافية ، ويمكن للسنانير قراءتها ، والرد مع وسيطات إضافية.
لتنفيذ جانب خادم أمر المستخدم يتم توفير execUserCommand . هناك أيضًا بعض الأساليب الأخرى التي توفرها ServiceAPI و TransportInterface . ابحث عن بعض حالات التخصيص في أمثلة التخصيص.
تبقي الخدمة وجود المستخدم وبيانات الاتصال في المتجر ، والتي قد تكون ثابتة أو مشتركة. لذلك إذا تم إيقاف تشغيل مثيل بشكل غير صحيح (دون الاتصال أو في انتظار طريقة close ) أو فقدان اتصال الشبكة بالكامل إلى المتجر ، فستصبح بيانات التواجد غير صحيحة. لإصلاح هذه الحالة ، يتم توفير طريقة instanceRecovery .
كما أن هناك المزيد من الحالات الدقيقة فيما يتعلق بتناسق بيانات الاعتماد على الاتصال. يمكن أن تواجه مثيلات اتصالات النقل وحالات المتجر نوعًا مختلفًا من فشل الشبكات أو البرامج أو الأجهزة. في بعض حالات الحواف (مثل التشغيل على عدة مستخدمين) ، يمكن أن تسبب هذه الإخفاقات تناقضات (في معظمها سيتم إرجاع الأخطاء إلى مصدري الأمر). يتم الإبلاغ عن هذه الأحداث عبر باعث مثيل (مثل حدث storeConsistencyFailure ) ، ويمكن مزامنة البيانات عبر طرق RecoveryAPI .
افتراضيًا ، يُفترض أن كل مستخدم لديه تسجيل دخول فريد (اسم المستخدم). بدلاً من إدارة توليد الأسماء ، يمكن استخدام تكامل مع نقل منفصل (أو اتصال متعدد الإرسال ، على سبيل المثال مساحة اسم Socket.io أخرى). يمكن إعادة توجيه رسائل الغرفة من roomMessage بعد ربط النقل ، ويمكن الوصول إليه دون تسجيل الدخول. ويمكن تنفيذ بعض أوامر الخدمة من قبل المستخدمين المجهولين عبر execUserCommand مع تشغيل خيار الأذونات الالتفافية.
يمكن أيضًا استخدام roomMessage بعد الخطاف لإعادة توجيه الرسائل من غرفة إلى أخرى. لذلك يمكن استخدام الغرف لتجميع الرسائل من غرف أخرى. نظرًا لأن السنانير هي مجرد وظائف ولديها وصول كامل إلى محتوى الرسائل ، فإنه يسمح بتنفيذ قواعد إعادة التوجيه التعسفية المستندة إلى المحتوى. بما في ذلك تنفيذ الأنظمة مع خلاصات محددة من المستخدمين (العميل) مخصصة للغاية.
افتراضيًا ، لا توجد طريقة للمستخدمين الآخرين لمعرفة عدد وتوصيلات المستخدمين المنضمة إلى غرفة. يمكن تمرير هذه المعلومات ، على سبيل المثال في سلسلة استعلام ثم حفظها عبر خطاف اتصال. يمكن إصدار الإعلان في خطاف onJoin و onLeave ، باستخدام طريقة sendToChannel مباشرة. كما ينبغي إرسال معلومات إضافية تتعلق بأنواع الأجهزة المرتبطة من roomGetAccessList بعد الخطاف (عندما يكون اسم القائمة مساوياً لـ 'userlist' ).
لا توجد عملية حذف أو تحرير ، لأنها ستجعل تناقضات داخل تاريخ الغرفة. يتمثل أحد البديل الشائع في حذف وتحرير إلى استخدام رسائل الغرف مع معنى خاص يستخدمه العملاء لإخفاء الرسائل أو تغييرها.
إذا واجهت خطأ في هذه الحزمة ، فيرجى إرسال تقرير الأخطاء إلى مشكلات Github Repo.
يتم قبول PRS أيضا.
معهد ماساتشوستس للتكنولوجيا