maiden عبارة عن مجموعة من الأنظمة التي تساعدك على إنشاء التطبيقات والمكتبات التي تتفاعل مع خوادم الدردشة. يمكن أن يساعدك في إنشاء روبوت دردشة أو عميل دردشة عام. كما يقدم أيضًا مجموعة متنوعة من الأجزاء التي من شأنها أن تجعل من السهل جدًا كتابة عميل لبروتوكول دردشة جديد.
إذا كنت تهتم فقط باستخدام maiden لإعداد روبوت من نوع ما، فإن خطوات القيام بذلك واضحة إلى حد ما. أولاً، سنرغب في التحميل maiden وجميع الوحدات والمكونات التي ترغب في استخدامها في الروبوت الخاص بك.
(ql:quickload '( maiden maiden -irc maiden -commands maiden -silly))
وبعد ذلك سنقوم بإنشاء نواة تحتوي على مثيلات المستهلكين المضافة إليها كما نرغب في أن تكون.
(defvar *core* ( maiden :make-core
'(: maiden -irc :nickname " maiden Test" :host "irc.freenode.net" :channels ("##testing"))
: maiden -commands
: maiden -silly))
يأخذ الأمر make-core إما أسماء الحزم (كسلاسل أو رموز) للمستهلكين لإضافتها، أو اسم الفئة المباشر للمستهلك. في الحالة الأولى، سيحاول العثور على اسم فئة المستهلك المناسب بنفسه.
وهذا كل شيء. سيقوم make-core
بإنشاء نواة، وإنشاء مثيل لجميع المستهلكين، وإضافتهم إليه، وبدء كل شيء. ستستفيد نهب الوحدات المتوفرة maiden من نوع ما من التكوين أو التخزين المستمر. لإدارتها، راجع نظام التخزين الفرعي.
من أجل استخدام maiden كإطار عمل، ستحتاج أولاً إلى تحديد النظام الخاص بك والحزمة كالمعتاد للمشروع. في الوقت الحالي، سنستخدم حزمة maiden -user
فقط للتجول فيها. وبعد ذلك، سنرغب في تحديد المستهلك. يمكن القيام بذلك باستخدام define-consumer
.
(in-package #: maiden -user)
(define-consumer ping-notifier (agent)
())
عادة سوف ترغب في تحديد وكيل. يمكن للوكلاء أن يتواجدوا مرة واحدة فقط على النواة. سنستعرض مثالاً للعميل لاحقًا. الآن، من الآن فصاعدًا، يمكننا تحديد أساليبنا ووظائفنا التي تتخصص أو تعمل على فئة المستهلك كما اعتدت على برمجة CLOS العامة. بعد ذلك، سنحدد الحدث الخاص بنا الذي سنستخدمه لإرسال "طلبات ping" إلى النظام.
(define-event ping (passive-event)
())
يتم تعريف الحدث على أنه passive-event
لأنه لا يطلب بشكل مباشر اتخاذ إجراء ما، ولكنه يقوم بإبلاغ النظام بحدوث اختبار الاتصال (ping). الآن، من أجل جعل المستهلك يتفاعل فعليًا مع نظام الأحداث، سنرغب أيضًا في تحديد المعالجات. يمكن القيام بذلك باستخدام define-handler
.
(define-handler (ping-notifier ping-receiver ping) (c ev)
(v:info :ping "Received a ping: ~a" ev))
يحدد هذا معالجًا يسمى ping-receiver
على مستهلك ping-notifier
. ويحدد أيضًا أنه سيستمع للأحداث من النوع ping
. يقول arglist بعد ذلك أن مثيل المستهلك مرتبط بـ c
ومثيل الحدث بـ ev
. ثم يقوم الجسم ببساطة بتسجيل رسالة إعلامية باستخدام Verbose.
دعونا نختبر هذا بسرعة كبيرة.
(defvar *core* (make-core 'ping-notifier))
(do-issue *core* ping)
يجب أن يقوم ذلك بطباعة رسالة الحالة إلى REPL كما هو متوقع. وهذا هو الأهم من كل شيء لاستخدام هذا النظام. لاحظ أنه من أجل القيام بأشياء مفيدة بالفعل، قد ترغب في الاستفادة من بعض الأنظمة الفرعية الموجودة مسبقًا والتي يقدمها المشروع maiden بالإضافة إلى النظام الأساسي. سيساعدك ذلك في التعامل مع المستخدمين والقنوات والحسابات والأوامر والشبكات والتخزين وما إلى ذلك. ضع في اعتبارك أيضًا أنه يمكنك الاستفادة من الميزات التي يقدمها Deeds بمفردها أيضًا، مثل تصفية التعبيرات للمعالجات.
الآن دعونا نلقي نظرة على نوع بدائي من العملاء. سيتمكن العميل ببساطة من الكتابة إلى ملف من خلال الأحداث.
(define-consumer file-client (client)
((file :initarg :file :accessor file))
(:default-initargs :file (error "FILE required.")))
(define-event write-event (client-event active-event)
((sequence :initarg :sequence))
(:default-initargs :sequence (error "SEQUENCE required.")))
لقد جعلنا write-event
client-event
لأنه يجب أن يكون خاصًا بالعميل الذي نريد الكتابة إليه، وجعلناه active-event
لأنه يطلب حدوث شيء ما. الآن دعونا نحدد معالجنا الذي سيهتم فعليًا بكتابة التسلسل إلى الملف.
(define-handler (file-client writer write-event) (c ev sequence)
:match-consumer 'client
(with-open-file (stream (file c) :direction :output :if-exists :append :if-does-not-exist :create)
(write-sequence sequence stream)))
يقوم خيار :match-consumer
بتعديل مرشح المعالج بطريقة بحيث يمرر المرشح فقط الأحداث التي تحتوي فتحة client
الخاصة بها على نفس مثيل file-client
الذي ينتمي إليه مثيل المعالج الحالي. وهذا أمر مهم، حيث أن كل مثيل file-client
سوف يتلقى مثيلاته الخاصة من معالجاته على المركز. بدون هذا الخيار، ستتم معالجة write-event
بواسطة كل مثيل file-client
بغض النظر عن المثيل الذي كان الحدث مخصصًا له. لاحظ أيضًا أننا أضفنا وسيطة sequence
إلى قائمة arglist الخاصة بالمعالج. سيتم ملء هذه الوسيطة بالفتحة المناسبة من الحدث. إذا لم يتم العثور على مثل هذه الفتحة، فسيتم الإشارة إلى حدوث خطأ.
حان الوقت لاختباره. سنقوم فقط بإعادة استخدام النواة من الأعلى.
(add-to-core *core* '(file-client :file "~/foo" :name :foo)
'(file-client :file "~/bar" :name :bar))
(do-issue *core* write-event :sequence "foo" :client (consumer :foo *core*))
(do-issue *core* write-event :sequence "bar" :client (consumer :bar *core*))
(alexandria:read-file-into-string "~/foo") ; => "foo"
(alexandria:read-file-into-string "~/bar") ; => "bar"
كما ترون، تم توجيه الأحداث إلى مثيلات المعالج المناسبة وفقًا للعميل الذي أردناه، وبالتالي تحتوي الملفات على ما نتوقعه منها.
أخيرًا، تجدر الإشارة إلى أنه من الممكن أيضًا إضافة المعالجات وإزالتها ديناميكيًا في وقت التشغيل، وحتى القيام بذلك للمعالجات غير المرتبطة بمستهلك معين. يكون هذا مفيدًا غالبًا عندما تحتاج إلى انتظار حدث استجابة من مكان ما. للتعامل مع منطق القيام بذلك بشكل غير متزامن والاحتفاظ بالانطباع بوجود تدفق أمر، تقدم maiden - تمامًا كما تفعل الأفعال - ماكرو with-awaiting
. ويمكن استخدامه على النحو التالي:
(with-awaiting (core event-type) (ev some-field)
(do-issue core initiating-event)
:timeout 20
some-field)
with-awaiting
مشابه جدًا لـ define-handler
، باستثناء أنه لا يأخذ اسمًا، وبدلاً من اسم المستهلك في البداية فإنه يحتاج إلى نسخة أساسية أو مستهلكة. كما يتطلب الأمر أيضًا خيارًا إضافيًا غير مستخدم، وهو :timeout
. الإضافة الأخرى المطلوبة هي "نموذج الإعداد" بعد قائمة arglist. من أجل إدارة كل شيء بشكل صحيح والتأكد من عدم حدوث أي حالات تعارض في النظام، يجب عليك بدء العملية التي ستطالب بحدث الاستجابة النهائية في نموذج الإعداد هذا. إذا بدأته قبل ذلك، فقد يتم إرسال حدث الاستجابة قبل إعداد المعالج المؤقت في النظام وسيظهر كما لو أنه لم يصل على الإطلاق.
وهذا إلى حد كبير كل الأساسيات. كما ذكرنا أعلاه، قم بإلقاء نظرة على الأنظمة الفرعية التي يتضمنها هذا المشروع، لأنها ستساعدك في جميع أنواع المهام والمشكلات الشائعة التي تدور حول أنظمة الدردشة وما إلى ذلك.
قبل فهم maiden ، من المفيد أن نفهم الأفعال، ولو على المستوى السطحي فقط. maiden يبني عليه بشكل كبير إلى حد ما.
core
هي الجزء المركزي من التكوين maiden . وهي مسؤولة عن إدارة وتنسيق المكونات الأخرى للنظام. يمكن أن يكون لديك عدة نوى تعمل في وقت واحد داخل نفس صورة اللثغة، ويمكنك أيضًا مشاركة المكونات بينها.
وبشكل أكثر تحديدًا، يتكون المركز من حلقة حدث ومجموعة من المستهلكين. حلقة الأحداث مسؤولة عن تسليم الأحداث إلى المعالجات. يتحمل المستهلكون مسؤولية ربط المعالجات بحلقة الحدث. العمليات التي من المرجح أن ترغب في تنفيذها على النواة هي: إصدار الأحداث إليها حسب issue
، أو إضافة المستهلكين إليها عن طريق add-consumer
، أو إزالة المستهلك منها عن طريق remove-consumer
.
لتسهيل إنشاء نواة مفيدة مع إضافة المستهلكين إليها، يمكنك الاستفادة من وظائف make-core
add-to-core
.
event
هو كائن يمثل تغييرا في النظام. يمكن استخدام الأحداث إما لتمثيل التغيير الذي حدث، أو لتمثيل طلب لحدوث التغيير. وتسمى هذه passive-event
active-event
على التوالي.
بشكل عام، ستستخدم الأحداث بالطرق التالية:
consumer
هو فئة تمثل مكونًا في النظام. يمكن أن يكون لكل مستهلك عدد كبير من المعالجات المرتبطة به، والتي سوف تتفاعل مع الأحداث في النظام. يأتي المستهلكون في نوعين أساسيين، agent
client
. الوكلاء هم مستهلكون يجب أن يتواجدوا على المركز مرة واحدة فقط، حيث يقومون بتنفيذ وظائف لن يكون من المنطقي تعدد إرسالها بطريقة ما. من ناحية أخرى، يمثل العملاء نوعًا ما من الجسر إلى نظام خارجي، ومن الطبيعي أن يُسمح لهم بوجود مثيلات متعددة على نفس النواة.
وبالتالي فإن تطوير مجموعة من الأوامر أو واجهة من نوع ما قد يؤدي على الأرجح إلى وكيل، في حين أن التفاعل مع خدمة مثل XMPP قد يؤدي إلى عميل.
يجب أن يتم تعريف المستهلك باستخدام define-consumer
، وهو مشابه لـ defclass
القياسي، ولكنه يضمن إعداد الفئات الفائقة والفئات الوصفية بشكل صحيح.
handler
عبارة عن كائنات تحتوي على وظيفة تنفذ إجراءات معينة عند إصدار حدث معين على النواة. يرتبط كل معالج بمستهلك معين ويتم إزالته أو إضافته إلى حلقة الأحداث الأساسية عند إزالة المستهلك أو إضافته إلى المركز.
يتم تعريف المعالج من خلال أحد define-handler
أو define-function-handler
أو define-instruction
أو define-query
. والتي يبني كل منها على التوالي على الأخير لتوفير اختصار أوسع للمتطلبات المشتركة. لاحظ أن الطريقة التي يتلقى بها المعالج الأحداث الخاصة به قد تختلف. قم بإلقاء نظرة على وثائق الأفعال لمعرفة فئات المعالج المتاحة.
يتضمن المشروع maiden نظامين فرعيين يعملان على توسيع الوظائف الأساسية.
يتضمن المشروع maiden أيضًا عددًا قليلاً من العملاء القياسيين الذين يمكن استخدامهم على الفور.
أخيرًا، يحتوي المشروع على مجموعة من وحدات الوكيل التي توفر وظائف مفيدة لإنشاء روبوتات الدردشة وما شابه. ويمكن أيضًا استخدامها على الفور.