مراجعة: أضف غرف الفيديو والصوت بأسلوب ديسكورد إلى مجتمعك 🎙

يبدو أنه على الهاتف المحمول يمكن فقط إنشاء غرفة، لكن عند النقر مباشرة على غرفة تم إنشاؤها مسبقًا لا يمكن الدخول إليها. ومع ذلك، إذا قمت بالوصول مباشرة إلى /resenha/r/topic، فيمكن فتحها. هل هذا خطأ برمجي؟

يعمل بشكل جيد تماماً على هاتفي، هل قمت بتحديث مثيل Discourse الخاص بك هذا الأسبوع؟

الإضافات التجريبية تتطلب تحديثات متكررة

5 إعجابات

هناك الكثير من التحديثات هذا الشهر، لكن التحديث الرئيسي هو دعم اختياري ومخصص لكل غرفة لـ SFU عبر LiveKit.

لا يزال WebRTC P2P الكامل هو النقل المدعوم الرئيسي والافتراضي، ولكن تم الآن دعم SFU أيضًا للأشخاص الذين يحتاجون إلى دعم مئات المشاركين في غرفة واحدة.

كما أجرينا العديد من التحسينات، مثل منتقي أجهزة الصوت والفيديو في عناصر التحكم في الغرفة والمكون الإضافي، وجعل غرف Resenha قابلة للإشارة إليها عبر الإكمال التلقائي لـ # في الدردشة والمنشورات، وخيارات تخطيط الغرفة، والمزيد.

15 إعجابًا

شكرًا لك على هذا، كانت SFU هي القطعة الناقصة حقًا. إنها ما دفعني في البداية إلى الحفاظ على شتلة منفصلة؛ مع دعمها في المشروع الأصلي، يمكنني إيقاف الشتلة وتتبع resenha مباشرة.

كنت قد امتنعت عن السؤال عن LiveKit لأنني لم أكن أعرف ما إذا كنت تريد المضي في هذا الاتجاه. الآن وقد فعلت: هل أنت منفتح على طلبات السحب للميزات والتحسينات الصغيرة؟

4 إعجابات

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

1. واجهة المسؤول تتجاهل بصمت خاصية room_type مما يمنع الغرف من البقاء في وضع “المراحل” (stage)
يُستبعد :room_type من قائمة السماح في app/controllers/resenha/admin_rooms_controller.rb:65 (room_params)، كما لا يقوم admin_room_serializer.rb بتسلسله (serialize).

يتم تجاهل كل تعيين للمراحل يتم عبر واجهة المسؤول، وتُنشأ الغرف كـ “مفتوحة” وتعود إلى الوضع المفتوح عند أي تعديل لاحق من قبل المسؤول. تم التأكيد على ذلك عبر سجلات الإنتاج؛ متحكم واجهة المستخدم يسمح بذلك، لكن المسار الخاص بالمسؤول فقط هو الذي فقد هذه الخاصية.

# admin_rooms_controller.rb — أضف :room_type إلى قائمة السماح، ثم:
if permitted.key?(:room_type)
  value = Resenha::Room::ROOM_TYPES[permitted[:room_type].to_s]
  raise Discourse::InvalidParameters.new(:room_type) if value.nil?
  permitted[:room_type] = value
end
# admin_room_serializer.rb — سّلسل room_type بحيث تتهيأ النماذج بشكل صحيح

2. القيم غير الصالحة لـ room_type تعود بصمت إلى الوضع المفتوح
app/controllers/resenha/rooms_controller.rb:575ROOM_TYPES[...] || ROOM_TYPE_OPEN.

أي قيمة غير صحيحة أو قديمة لـ room_type في تعديل غرفة صحيح بخلاف ذلك، يقوم بصمت بتحويل غرفة المراحل إلى وضع مفتوح. إرجاع خطأ 400 يجعل المتصل الذي يتصرف بشكل خاطئ مرئياً بدلاً من إتلاف بيانات الغرفة.

value = Resenha::Room::ROOM_TYPES[permitted[:room_type].to_s]
raise Discourse::InvalidParameters.new(:room_type) if value.nil?
permitted[:room_type] = value

3. نبضات الحياة (Heartbeat) تعيد إحياء مستخدم غادر للتو (حضور شبحي)
rooms_controller.rb:234 (heartbeat) يعيد إضافة الحضور بشكل غير مشروط، لذا فإن نبضة حياة قيد المعالجة عندما تتم معالجة عملية المغادرة (:220) لاحقاً، تعيد إنشاء المستخدم المغادر.
يبقى هذا “الشبح” حتى يتم تنظيفه بناءً على انتهاء وقت البقاء (TTL)، وهو ما لا يُبثّ — فتظهر للعملاء وكأنه “في الغرفة” لمدة تصل إلى دقيقة.

تم تكرار المشكلة على الجهاز؛ ولأمر الطرد (kick) نفس التعرض للمشكلة.

# ParticipantTracker: حجر نصب مدته 15 ثانية
def mark_left(room_id, user_id)  = redis.setex(left_key(room_id, user_id), 15, "1")
def recently_left?(room_id, user_id) = redis.exists?(left_key(room_id, user_id))
# leave/kick → mark_left; join/livekit_token → clear_left; heartbeat:
return head :no_content if Resenha::ParticipantTracker.recently_left?(@room.id, current_user.id)

4. إشارة webhook قديمة لـ participant_left تطرد جلسة جديدة
livekit_webhooks_controller.rb:37/57 — يتم مطابقة المغادرات بناءً على هوية المستخدم فقط.
عند انقطاع سريع وإعادة انضمام، تصل إشارة participant_left الخاصة بالجلسة السابقة متأخرة وتُنتهي صلاحية حضور الجلسة الجديدة (يتم “طرد” المستخدم بعد ~3 ثوانٍ من إعادة الانضمام، ويعود بعد ~15 ثانية).
تم تكرار المشكلة على الجهاز؛ ولا يمكن لمعيار gone_at التمييز بين الجلسات عندما يسبق إعادة الانضمام انقطاع الجلسة القديمة.

# participant_joined → تسجيل SID المباشر
Resenha::ParticipantTracker.set_livekit_sid(room.id, user_id, event.dig("participant", "sid"))
# expire_participant → تخطي مغادرة الجلسة السابقة
known = Resenha::ParticipantTracker.livekit_sid(room.id, user_id)
return if sid.present? && known.present? && sid != known

5. خطأ 404 لـ DeleteRoom بعد مغادرة آخر مستخدم يفيض السجلات
lib/resenha/livekit/room_service_client.rb:84 يحذر عند أي استجابة غير 200.
يقوم SFU بإغلاق الغرفة تلقائياً في اللحظة التي تصبح فيها فارغة، لذا فإن طلب DeleteRoom الخاص بالمغادرة الأخيرة يتسابق معه بشكل روتيني — و"الغرفة المطلوبة غير موجودة" هي الحالة النهائية المطلوبة، وليست عطلاً.
يظهر هذا في Logster عند كل مغادرة للمستخدام الأخير.

elsif method == "DeleteRoom" && response.status == 404
  Rails.logger.debug("[resenha-livekit] DeleteRoom no-op for room #{room.id}: already gone")
  true

يمكنني إرسال طلب سحب (pull request) إذا رغبت في ذلك.

كما قلتُ سابقاً، لا أعرف اتجاهكم بالكامل، لكنكم يمكنكم الاطلاع على مساهماتي حيث قمتُ بنشر موضوع هنا → Discourse Desktop Mac App - #10 by nicolsdennis

إعجابَين (2)

سيكون ذلك رائعًا للغاية - سيكون من المنطقي ربطه بآلية البث المباشر، مما سيوفر قناة الدردشة المرتبطة كجزء من تجربة متكاملة جميلة

4 إعجابات

مرحباً، عند تغيير اسم الغرفة، لا يتم تحديث الرابط المختصر (slug). أيضاً، لا يسمح لي بحذف الغرف – أحصل على خطأ في الخادم.

سيكون من الجميل أيضاً القدرة على تغيير ترتيب الغرف بشكل مرئي وكيفية ظهورها.

شكراً لك على التقرير المفصل، لقد قمت بدمج طلب السحب (PR) الخاص بذلك:

6 إعجابات

لدي بعض الأمور البسيطة المتعلقة بواجهة المستخدم وتجربة المستخدم (UI/UX) بخصوص غرف الصوت الخاصة:

1. أيقونة القفل/الخصوصية صغيرة جداً.

من الرائع أن لدينا أيقونة تدل على حالة خصوصية الغرفة؛ لكن للأسف هي صغيرة جداً وتتداخل مع الأيقونة الأخرى. كما أنها غير متسقة مع باقي عناصر الشريط الجانبي:

image   image

2. قائمة المشاركين صعبة العثور عليها

لا يمكن الوصول إلى قائمة المشاركين في غرفة صوتية خاصة إلا من داخل المكالمة نفسها.

هذا ليس بديهيًا جدًا. أتوقع أن أتمكن من تعديل المشاركين/المُدعَين من خلال الإعدادات المتاحة حتى عندما تكون غرفة الصوت غير نشطة. هناك كثيرة من الإعدادات المتاحة عندما تكون غير نشطة (بما في ذلك العام مقابل الخاص، الحد الأقصى للمشاركين، إلخ)، باستثناء قائمة المشاركين الفعلية.

3 إعجابات

لقد قمت بإصلاح كلاهما، شكراً لك على الإبلاغ @nathank!

إعجابَين (2)

أتساءل عما إذا كان من الممكن ربط غرفة محددة من خلال روابط href؟ أريد إضافة اختصار لغرفة اختبار واحدة لتبسيط تجربة المستخدم لدينا.

نعم، أصبح ذلك ممكنًا الآن بهذا التنسيق

https://discourse-on-a-pi5.falco.dev/resenha/r/watercooler

4 إعجابات

يُجدر أيضاً تسليط الضوء على التحسينات الأخيرة:

دعم STUN/TURN الخاص عبر مصادقة coturn

يتيح لك هذا الإبقاء على مثيل coturn مقيداً بك، وهو سهل التكوين جداً باستخدام سر مشترك بين Discourse وCoturn.

دعم تسجيل الجلسات عند استخدام LiveKit

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

دعم الأعلام لمشاركين المكالمات

بينما سيخضع العلم لقلة السياق، يمكن للمستخدمين توفيره عبر منطقة النص

قائمة النقر بزر الماوس الأيمن على مربعات الفيديو

سهل تعديل حجم صوت النظير، أو طرده، إلخ.

جودة أعلى اختيارية للصوت والفيديو ومشاركة الشاشة

ميزة الأسبوع المفضلة لدي، تتيح للمستخدمين اختيار حدود معدل بت أعلى بكثير، والحصول على صوت/فيديو أفضل بكثير.

6 إعجابات

أفضل بكثير!!! شكراً لك على الاستماع (والتصرف)!!

image

إعجابَين (2)

هل هذه مشكلة خاصة بنسختي أم أنه هناك أمر يستحق التحقيق؟ أتلقى خطأ 500 عند محاولة إزالة غرف الصوت من لوحة الإدارة:

ActiveRecord::InvalidForeignKey (PG::ForeignKeyViolation: ERROR:  update or delete on table "resenha_rooms" violates foreign key constraint "fk_rails_ID" on table "resenha_sessions" DETAIL:  Key (id)=(1) is still referenced from table "resenha_sessions".
إعجاب واحد (1)

شكرًا لك على التقرير، تم دمج الإصلاح

إعجابَين (2)

شكرًا لك على هذا الإصلاح الفائق السرعة؛ لقد عمل كما هو متوقع.

ملاحظة صغيرة فقط، كتابع: لم يؤدي تغيير اسم الغرفة الافتراضي إلى تحديث المسار /resenha/r/watercooler، لكنني أصبحت الآن قادرًا على إزالة الغرفة الافتراضية السابقة وإضافة غرفة جديدة.

إعجاب واحد (1)

لقد جعلت الآن السلاغ (slug) قابلاً للتحرير بشكل صريح، لذا يعمل مثل التصنيفات

6 إعجابات

يمكنك أيضًا إضافة بعض معلمات URL لفتحها بطريقة محددة:

https://discourse-on-a-pi5.falco.dev/resenha/r/watercooler?join، يدخل الغرفة فقط، بدون زر “انضمام”

https://discourse-on-a-pi5.falco.dev/resenha/r/watercooler?join&widget (تمت إضافته في وقت سابق هذا الأسبوع)، يفتح ويتحول إلى وضع الويدجت

https://discourse-on-a-pi5.falco.dev/resenha/r/watercooler?join&chat يفتح في وضع الدردشة

إعجابَين (2)