microdot.websocket --- دعم WebSocket

WebSocket عبارة عن اتصال ثنائي الاتجاه ودائم عبر HTTP -- فبعد مصافحة الترقية، يرسل العميل والخادم ويستقبلان رسائل مؤطرة على المقبس نفسه. استخدمها عندما تحتاج الكاميرا وتطبيق على جانب المتصفح إلى حركة مرور ثنائية الاتجاه بالكامل لا تستطيع تقنية SSE (الدفع أحادي الاتجاه) ولا الاستقصاء العادي عبر HTTP توفيرها بتكلفة زهيدة.

class WebSocket

class microdot.websocket.WebSocket(request)

المقبض الذي يستقبله المسار. يُمرَّر إلى المعالِجات كوسيط ثانٍ عند استخدام with_websocket()؛ لا تُنشئه مباشرةً.

سمات الصنف

max_message_length: int

الحد الأقصى لحجم الحمولة الذي ستقبله receive(). الرسائل الأكبر من هذا الحد تُطلق WebSocketError وتُغلق الاتصال. القيمة 0 تُعطّل الفحص (انتبه لهجمات استنفاد الذاكرة إن ضبطت هذا). القيمة -1 (الافتراضية) تستخدم Request.max_body_length.

CONT: int

رمز عملية إطار المتابعة، 0x0. يُعلِّم إطارًا يكمّل حمولة الإطار السابق للرسالة نفسها. لا يولّد Microdot إطارات متابعة بنفسه (تخرج كل رسالة كإطار واحد) ويرفضها عند الاستقبال، لكن الثابت مكشوف للتطبيقات التي تطبّق تأطيرًا مخصصًا.

TEXT: int

رمز عملية إطار النص، 0x1. هو رمز العملية الذي تختاره send() تلقائيًا عندما تكون data من النوع str؛ تُرمَّز الحمولة بترميز UTF-8 عند الإرسال.

BINARY: int

رمز عملية الإطار الثنائي، 0x2. هو رمز العملية الذي تختاره send() تلقائيًا عندما تكون data من النوع bytes / bytearray؛ تُرسَل الحمولة كما هي.

CLOSE: int

رمز عملية إطار الإغلاق، 0x8. تُرسله close()؛ ويؤدي استقباله إلى إطلاق WebSocketError ("Websocket connection closed") من داخل receive().

PING: int

رمز عملية إطار Ping، 0x9. يردّ Microdot على رسائل Ping الواردة بـ PONG مطابق تلقائيًا داخل receive()؛ ولا يلاحظها التطبيق عادةً.

PONG: int

رمز عملية إطار Pong، 0xA. يُرسَل تلقائيًا ردًّا على PING. أما رسائل Pong الواردة فتُهمل بصمت.

سمات النسخة

request: microdot.Request

كائن microdot.Request الأصلي -- وهو الكائن نفسه الذي استقبله معالِج المسار.

closed: bool

تصبح True بمجرد تنفيذ close(). افحصها لتجنّب الإغلاق المزدوج في مسارات التنظيف.

الطرق

async receive()

ينتظر الرسالة التالية من العميل ويعيدها. يطابق نوع القيمة المُعادة رمز عملية الإطار: str لإطارات النص، وbytes للإطارات الثنائية. تُجاب إطارات ping تلقائيًا بـ pong؛ وتُهمل إطارات pong بصمت؛ ويطلق إطار close الاستثناء WebSocketError ("Websocket connection closed").

async send(data, opcode: int | None = None)

يرسل data إلى العميل. تُرسَل السلاسل النصية كإطارات نص، والبايتات كإطارات ثنائية؛ مرّر opcode صراحةً لتجاوز ذلك.

async close()

يرسل إطار إغلاق ويعلّم الاتصال كمُغلق. يُستدعى تلقائيًا عند خروج غلاف with_websocket().

class WebSocketError

exception microdot.websocket.WebSocketError

يُطلَق داخل WebSocket.receive() عندما ينتهي الاتصال أو يُنتهك البروتوكول. استخدمه في مسار لاكتشاف انقطاعات العميل الطبيعية:

try:
    message = await ws.receive()
except WebSocketError:
    # client closed the connection

مُزخرِفات على مستوى الوحدة

microdot.websocket.with_websocket(f)

مُزخرِف يحوّل مسارًا إلى نقطة نهاية WebSocket. يستقبل المعالِج الطلب وكائن WebSocket

from microdot import Microdot
from microdot.websocket import with_websocket

app = Microdot()

@app.get('/echo')
@with_websocket
async def echo(request, ws):
    while True:
        msg = await ws.receive()
        await ws.send(msg)

يساوي عمر المعالِج عمر الاتصال. ويؤدي الرجوع أو إطلاق استثناء أو انقطاع العميل إلى إغلاق WebSocket بنظافة.

async microdot.websocket.websocket_upgrade(request)

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

@app.get('/private')
async def private(request):
    if not authenticate(request):
        abort(401)
    ws = await websocket_upgrade(request)
    while True:
        msg = await ws.receive()
        await ws.send(msg.upper())

يعيد كائن WebSocket بعد الترقية. على المعالِج أن يعيد microdot.Response.already_handled (أو يطلق استثناءً) بمجرد انتهائه -- إذ تكون microdot قد تولّت المقبس بالفعل.

يدعم التنفيذ رموز العمليات النصية والثنائية القياسية، وping / pong، والإغلاق النظيف. أما الإطارات المجزّأة (إطارات المتابعة) فغير مدعومة -- تُرسَل كل رسالة كإطار واحد، وهو ما يناسب تطبيقات الكاميرا النموذجية ذات الرسائل الصغيرة.