
مكتبة Go لاستخدام واجهة برمجة تطبيقات WebSocket الخاصة بـ zeek broker
تنفّذ هذه المكتبة واجهة WebSocket الخاصة بـ Zeek Broker.
تُوفَّر دوال مساعدة مع تعيينات معقولة بين أنواع Zeek وأنواع Go.
تحتوي المكتبة على حزمتين:
encodingيُمثّل encoding بنية البيانات العودية المعتمدة على JSON لتمثيل أنواع Zeek (بنية Data)، بالإضافة إلى ترميز Broker لأحداث Zeek ورسائل الأخطاء (بنية DataMessage). يمكن استخدام هذه البنى مباشرة (وفي بعض الحالات يجب ذلك) (انظر مثال الاشتراك في القسم التالي)، لكن بعض الدوال المساعدة تجعل بناء الرسائل أكثر ملاءمة. لإنشاء سلسلة string في Zeek يدويًا:
zeekString := encoding.Data{
DataType: encoding.TypeString,
DataValue: "foo",
}
...أو عبر الدالة المساعدة:
zeekString := encoding.String("foo")
دالة vector المساعدة على وجه الخصوص هي دالة متغيرة عدد الوسائط تقبل encoding.Data:
zeekVector := encoding.Vector(encoding.Count(1), encoding.Count(2), encoding.Count(3))
أخيرًا، يمكن إنشاء الأحداث مباشرة:
zeekEvent := encoding.NewEvent("some_event_name", zeekVector, zeekString)
clientتوفّر client الطبقة الرابطة لـ WebSocket للتواصل مع واجهة Broker WS، وهي تغلّف github.com/gorilla/websocket:
لنشر حدث:
broker, err := client.NewClient(...)
err := broker.PublishEvent("/the/topic", zeekEvent)
تُمرَّر اشتراكات المواضيع كشريحة من السلاسل إلى client.Newclient(). تُعيد طريقة ReadEvent() الخاصة بالعميل حدثًا واحدًا من Broker (على أي من المواضيع المشترك بها)، أو خطأً قد يحدث في المكتبة نفسها أو خطأً مستلَمًا من Broker):
broker, err := client.NewClient(..., []string{"/the/topic"})
topic, zeekEvent, err := broker.ReadEvent()
إذا أُغلق اتصال Broker بشكل طبيعي، يمكن استخدام دالة client.IsNormalWebsocketClose() للتحقق من الخطأ المُعاد.
يجب على كود العميل الوصول إلى قيم وسائط الحدث عبر تأكيدات الأنواع (type assertions):
if len(evt.Arguments) < someConstantGreaterOrEqualToOne {
// handle too few arguments case
}
if evt.Arguments[0].DataType != encoding.TypeString {
// handle unexpected data type case
}
stringArgument0, ok := evt.Arguments[0].DataValue.(string)
if !ok {
// handle type assertion error - this would indicate a bug (we trust+verify).
}
// now we use stringArgument0
من الأفضل تنفيذ المعالجة اللاتزامنية وتوزيع الأحداث المستلمة عبر الاشتراكات كغلاف (wrapper) لـ Client.ReadEvent(). يُوفَّر تنفيذ بسيط في client.AsyncSubscription().
أما المعالجة الأكثر تقدمًا لاتصال WebSocket (مثل ضبط المهلات، والتعامل مع إعادة الاتصال، وما إلى ذلك) فمن الأفضل تنفيذها كغلاف لـ client.Client، أو كتنفيذ جديد/بديل يستخدم حزمة encoding (المساهمات وطلبات السحب PRs مرحّب بها!).
تُفعّل اتصالات شبكة Broker (سواء الأصلية أو واجهة WebSocket) بروتوكول TLS افتراضيًا بإعداد غير اعتيادي يعطّل التحقق من المضيف ويختار مجموعة من خوارزميات التشفير التي تسمح بالتشفير دون شهادات (Diffie-Hellman مجهول / AECDH). لاستخدام هذا الوضع، يجب تمرير weirdtls.BrokerDefaultTLSDialer كوسيطة دالة المُنشئ (dialer) إلى encoding.NewClient. لاحظ أن هذا يستدعي OpenSSL كاعتماديّة.
بدلاً من ذلك، يمكن استخدام تنفيذ المكتبة القياسية crypto/tls إذا كان الطرفان (العميل وzeek/broker) مهيَّأين لاستخدام TLS مع الشهادات. توفر هذه المكتبة دالة مساعدة ملائمة (securetls.MakeSecureDialer()) تُعيد دالة مُنشئ (dialer) عند تمرير ملفات PEM الخاصة بالمرجع المصدق (CA) وشهادة/مفتاح العميل. انظر حالة btest هذه كمثال على هذا الإعداد.
أخيرًا، يمكن إيقاف تشغيل TLS لاتصالات broker باستخدام redef Broker::disable_ssl = T;. انظر حالة btest هذه كمثال على استدعاء encoding.NewClient بوسائط للتشغيل غير الآمن.
في zeek 7.2، ستُنتقل واجهة WebSocket من broker إلى إطار Cluster، وسيكون الإعداد الافتراضي هو إيقاف تشغيل TLS. تستخدم حالة btest هذه الدوال الجديدة في طرف zeek وتوضح استخدام هذه المكتبة عبر استدعاء encoding.NewClient() مع ضبط وسيطة secure إلى false.
عندما يصبح zeek 7.2 هو الإصدار طويل الدعم (LTS)، سيتخلى إصدار رئيسي جديد من هذه المكتبة عن دعم وضع AECDH TLS الموصوف في القسم أعلاه، مع إزالة الاعتماد على OpenSSL.
تشغيل سكربت broker في طرف zeek:
$ cd example/
$ zeek listen.zeek
الآن شغّل المثال:
$ cd example/
$ go build && ./example
2023/05/05 12:56:55 connected to remote endpoint with UUID=c9b0bfd6-3b8d-5de2-a51c-9af7b81aaad3 version=2.5.0-dev
2023/05/05 12:56:55 > topic=/topic/test | event ping("my-message": string, "1": count)
2023/05/05 12:56:55 < topic=/topic/test | event pong("my-message": string, "2": count)
2023/05/05 12:56:56 > topic=/topic/test | event ping("my-message": string, "2": count)
2023/05/05 12:56:56 < topic=/topic/test | event pong("my-message": string, "3": count)
...وفي الوقت نفسه، سكربت zeek:
peer added, [id=e537f8b4-de32-52ea-9587-4e6e15bdfe20, network=[address=127.0.0.1, bound_port=50690/tcp]]
receiver got ping: my-message, 1
receiver got ping: my-message, 2
معظم الدوال المساعدة وبنى البيانات الأساسية في حزمة encoding لديها اختبارات وحدة (شغّل go test ./...).
اختبارات النهاية إلى النهاية منفَّذة كحالتين من btest (شغّل cd tests/; btest).