- الرئيسية
- Documentation
- الأصلية
- الغلاف الأصلي وPTY والعملية ومفاتيح الداخلية
الغلاف الأصلي وPTY والعملية ومفاتيح الداخلية
تتناول هذه الوثيقة العمليات الأولية للتنفيذ/العملية/الطرفية في @f5-sales-demo/pi-natives: shell وpty وps وkeys، باستخدام المصطلحات المعمارية من docs/natives-architecture.md.
ملفات التنفيذ
Section titled “ملفات التنفيذ”crates/pi-natives/src/shell.rscrates/pi-natives/src/shell/windows.rs(Windows فقط)crates/pi-natives/src/pty.rscrates/pi-natives/src/ps.rscrates/pi-natives/src/keys.rscrates/pi-natives/src/task.rs(سلوك الإلغاء المشترك المستخدم بواسطة shell/pty)packages/natives/src/shell/index.tspackages/natives/src/shell/types.tspackages/natives/src/pty/index.tspackages/natives/src/pty/types.tspackages/natives/src/ps/index.tspackages/natives/src/ps/types.tspackages/natives/src/keys/index.tspackages/natives/src/keys/types.tspackages/natives/src/bindings.ts
ملكية الطبقات
Section titled “ملكية الطبقات”- طبقة غلاف/API في TypeScript (
packages/natives/src/*): نقاط دخول مكتوبة بالأنواع، وسطح الإلغاء (timeoutMs،AbortSignal)، وبيئة JavaScript. - طبقة وحدة Rust N-API (
crates/pi-natives/src/*): تنفيذ عملية الغلاف/PTY، واجتياز شجرة العمليات/إنهاؤها، وتحليل تسلسلات المفاتيح. - بوابة التحقق (
native.ts، على مستوى المعمارية): تضمن وجود الصادرات المطلوبة (Shell،executeShell،PtySession،killTree،listDescendants، ومساعدات المفاتيح) قبل استخدام الأغلفة.
النظام الفرعي للغلاف (shell)
Section titled “النظام الفرعي للغلاف (shell)”نموذج API
Section titled “نموذج API”يتم عرض وضعَي تنفيذ:
- لقطة واحدة عبر
executeShell(options, onChunk?). - جلسة دائمة عبر
new Shell(options?)ثمshell.run(...)بصورة متكررة.
يقوم كلاهما ببث الإخراج من خلال استدعاء خلفي آمن للخيوط ويعيد { exitCode?, cancelled, timedOut }.
إنشاء الجلسة ونموذج البيئة
Section titled “إنشاء الجلسة ونموذج البيئة”ينشئ Rust brush_core::Shell بالإعدادات التالية:
- وضع غير تفاعلي،
do_not_inherit_env: true،- إعادة بناء صريحة للبيئة من بيئة المضيف،
- قائمة تجاهل للمتغيرات الحساسة للغلاف (
PS1،PWD،SHLVL، صادرات دوال bash، إلخ).
سلوك بيئة الجلسة:
- يُطبَّق
ShellOptions.sessionEnvمرة واحدة عند إنشاء الجلسة. - يقتصر
ShellRunOptions.envعلى نطاق الأمر (EnvironmentScope::Command) ويُزال بعد كل تشغيل. - يُدمج
PATHبشكل خاص على Windows مع إزالة التكرار غير الحساس لحالة الأحرف.
إثراء المسار الخاص بـ Windows فقط (shell/windows.rs): تُلحق مسارات Git-for-Windows المكتشفة (cmd، bin، usr/bin) إذا كانت موجودة ولم تُضمَّن مسبقاً.
دورة حياة وقت التشغيل وانتقالات الحالة
Section titled “دورة حياة وقت التشغيل وانتقالات الحالة”يستخدم الغلاف الدائم (Shell.run) آلة الحالة التالية:
- خامل/غير مُهيأ:
session: None. - قيد التشغيل: أول استدعاء لـ
run()ينشئ الجلسة بشكل كسول، ويخزن رمزcurrent_abort، وينفذ الأمر. - مكتمل + استمرارية: إذا كان تدفق التحكم في التنفيذ
Normal، يُمسحcurrent_abortوتُعاد استخدام الجلسة. - مكتمل + إنهاء: إذا كان تدفق التحكم متعلقاً بالحلقة/النص البرمجي/خروج الغلاف (
BreakLoop،ContinueLoop،ReturnFromFunctionOrScript،ExitShell)، تُسقط الجلسة (session: None). - مُلغى/انتهت مهلته: تُلغى مهمة التشغيل، وانتظار سماح (2 ثانية)، ثم إلغاء قسري؛ وتُسقط الجلسة.
- خطأ: تُسقط الجلسة.
يقوم الغلاف أحادي الاستخدام (executeShell) دائماً بإنشاء جلسة جديدة وإسقاطها لكل استدعاء.
سلوك البث/الإخراج
Section titled “سلوك البث/الإخراج”- يُوجَّه كلٌّ من stdout وstderr إلى أنبوب مشترك ويُقرأان بصورة متزامنة.
- يفك القارئ ترميز UTF-8 بشكل تدريجي؛ وتُصدر تسلسلات البايت غير الصالحة قطعاً بديلة
U+FFFD. - بعد اكتمال العملية، يخضع استنزاف الإخراج لحراسي خمول وأقصى مدة (
250msخمول،2sأقصى) لتفادي التوقف بسبب المهام الخلفية التي تبقي واصفات البيانات مفتوحة.
الإلغاء والمهلة والمهام الخلفية
Section titled “الإلغاء والمهلة والمهام الخلفية”- يُنشأ
CancelTokenمنtimeoutMsوالإشارة الاختياريةAbortSignal. - عند الإلغاء/انتهاء المهلة، يُشغَّل رمز إلغاء الغلاف، ثم تحصل المهمة على نافذة سماح لمدة ثانيتين قبل الإلغاء القسري.
- إذا حدث الإلغاء، تُنهى المهام الخلفية (
TERM، ثمKILLبعد تأخير) باستخدام بيانات وظائف brush.
سلوك Shell.abort():
- يُلغي فقط الأمر الجاري تشغيله لتلك النسخة من
Shell، - لا يُنفِّذ شيئاً عند عدم وجود تشغيل نشط.
سلوك الفشل
Section titled “سلوك الفشل”تشمل الأخطاء الشائعة التي تظهر:
- فشل تهيئة الجلسة (
Failed to initialize shell)، - أخطاء مجلد العمل الحالي (
Failed to set cwd)، - فشل تعيين/إزالة البيئة،
- فشل مصدر اللقطة،
- فشل إنشاء/استنساخ الأنبوب،
- فشل التنفيذ (
Shell execution failed: ...)، - فشل غلاف المهمة (
Shell execution task failed: ...).
علامات الإلغاء على مستوى النتيجة:
- انتهاء المهلة ->
exitCode: undefined،timedOut: true. - إشارة الإلغاء ->
exitCode: undefined،cancelled: true.
النظام الفرعي لـ PTY (pty)
Section titled “النظام الفرعي لـ PTY (pty)”نموذج API
Section titled “نموذج API”يعرض new PtySession():
start(options, onChunk?) -> Promise<{ exitCode?, cancelled, timedOut }>write(data)resize(cols, rows)kill()
دورة حياة وقت التشغيل وانتقالات الحالة
Section titled “دورة حياة وقت التشغيل وانتقالات الحالة”آلة حالة PtySession:
- خامل:
core: None. - محجوز: تُثبِّت
start()قناة التحكم بصورة متزامنة (core: Some) قبل بدء العمل غير المتزامن، مما يجعلwrite/resize/killصالحة فوراً. - قيد التشغيل: تعالج حلقة PTY المحجوبة حالة العملية الفرعية وأحداث القارئ ونبضات الإلغاء ورسائل التحكم.
- مغلق الطرفية: خروج العملية الفرعية + اكتمال القارئ.
- منتهٍ: يُعاد تعيين
coreإلىNoneدائماً بعد اكتمال مهمة البدء (نجاحاً أو خطأً).
حارس التزامن:
- يُعيد البدء أثناء التشغيل الفعلي
PTY session already running.
أنماط الإنشاء/الإرفاق/الكتابة/القراءة/الإنهاء
Section titled “أنماط الإنشاء/الإرفاق/الكتابة/القراءة/الإنهاء”- يُفتح PTY عبر
portable_pty::native_pty_system().openpty(...). - يعمل الأمر حالياً كـ
sh -lc <command>مع تجاوزات اختيارية لـcwdوالبيئة. - يُرسل
write()بايتات خام إلى stdin لـ PTY. - يُثبِّت
resize()الأبعاد (cols 20..400،rows 5..200) ويستدعي تغيير حجم الرئيسي. - يُعلِّم
kill()التشغيل ملغىً ويقتل العملية الفرعية.
مسار الإخراج:
- يقرأ خيط قارئ مخصص دفق الرئيسي،
- فك ترميز UTF-8 التدريجي مع استبدال
U+FFFDعند البايتات غير الصالحة، - تُعاد توجيه القطع عبر استدعاء N-API الخلفي الآمن للخيوط.
دلالات الإلغاء والمهلة
Section titled “دلالات الإلغاء والمهلة”- يُغذِّي
timeoutMsوAbortSignalCancelToken. - تستدعي الحلقة
ct.heartbeat()دورياً؛ ويُشغِّل الإلغاءُ قتلَ العملية الفرعية. - يعتمد تصنيف المهلة على النص (
"Timeout"كجزء من نص خطأ نبضة القلب).
سلوك الفشل
Section titled “سلوك الفشل”تشمل أسطح الأخطاء:
- فشل تخصيص/فتح PTY،
- فشل إنشاء PTY،
- فشل الحصول على الكاتب/القارئ،
- فشل حالة/انتظار العملية الفرعية،
- تسمم القفل،
- قطع قناة التحكم (
PTY session is no longer available).
فشل استدعاءات التحكم عند عدم التشغيل:
- تُعيد
write/resize/killPTY session is not running.
النظام الفرعي لشجرة العمليات (ps)
Section titled “النظام الفرعي لشجرة العمليات (ps)”نموذج API
Section titled “نموذج API”killTree(pid, signal) -> numberlistDescendants(pid) -> number[]
كما يُسجِّل غلاف TypeScript تكامل kill-tree الأصلي في الأدوات المشتركة عبر setNativeKillTree(native.killTree).
التنفيذ الخاص بالمنصة
Section titled “التنفيذ الخاص بالمنصة”- Linux: يقرأ بشكل تعاودي
/proc/<pid>/task/<pid>/children. - macOS: يستخدم
libprocproc_listchildpids. - Windows: يأخذ لقطة لجدول العمليات بـ
CreateToolhelp32Snapshot، ويبني خريطة الوالد->الأبناء، وينهي بـOpenProcess(PROCESS_TERMINATE)+TerminateProcess.
سلوك kill-tree
Section titled “سلوك kill-tree”- تُجمع العمليات الفرعية بشكل تعاودي.
- يكون ترتيب القتل من الأسفل إلى الأعلى (العمليات الفرعية الأعمق أولاً) للحد من إعادة تبني الأيتام.
- يُقتل pid الجذر أخيراً.
- تكون قيمة الإرجاع هي عدد الإنهاءات الناجحة.
سلوك الإشارة:
- POSIX: يُمرَّر
signalالمُقدَّم إلىkill. - Windows: يُتجاهل
signal؛ والإنهاء هو إنهاء غير مشروط للعملية.
سلوك الفشل
Section titled “سلوك الفشل”هذه الوحدة مصممة عمداً لعدم إطلاق أخطاء على مستوى الواجهة:
- تُتخطى فروع شجرة العمليات المفقودة/غير القابلة للوصول،
- تُحسب إخفاقات قتل pid كل منها كغير ناجحة (وليست أخطاء)،
- عادةً ما تُنتج فجوة البحث
[]منlistDescendantsو0منkillTree.
النظام الفرعي لتحليل المفاتيح (keys)
Section titled “النظام الفرعي لتحليل المفاتيح (keys)”نموذج API
Section titled “نموذج API”المساعدات المعروضة:
parseKey(data, kittyProtocolActive)matchesKey(data, keyId, kittyProtocolActive)parseKittySequence(data)matchesKittySequence(data, expectedCodepoint, expectedModifier)matchesLegacySequence(data, keyName)
نموذج التحليل
Section titled “نموذج التحليل”يجمع المحلل:
- تعيينات مباشرة أحادية البايت (
enter،tab،ctrl+<letter>، ASCII قابل للطباعة)، - بحث O(1) في تسلسل الهروب القديم (خريطة PHF)،
- تحليل
modifyOtherKeysلـ xterm، - تحليل بروتوكول Kitty (
CSI u،CSI ~،CSI 1;...<letter>)، - تطبيع إلى معرِّفات المفاتيح (
ctrl+c،shift+tab،pageUp،f5، إلخ).
معالجة المُعدِّل:
- تُقارَن فقط بتات shift/alt/ctrl لمطابقة المفاتيح،
- تُقنَّع بتات القفل قبل المقارنات.
سلوك التخطيط:
- يُقيَّد الرجوع إلى التخطيط الأساسي عمداً حتى لا تُنشئ التخطيطات المعاد تعيينها تطابقات زائفة للأحرف/الرموز ASCII.
سلوك الفشل
Section titled “سلوك الفشل”- تُنتج التسلسلات غير المعروفة أو غير الصالحة
nullمن دوال التحليل. - تُعيد دوال المطابقة
falseعند فشل التحليل أو عدم التطابق. - لا يوجد سطح خطأ مُطلَق لإدخال المفاتيح المشوه.
تعيين واجهة JS للغلاف ↔ صادرات Rust
Section titled “تعيين واجهة JS للغلاف ↔ صادرات Rust”الغلاف + PTY + العملية
Section titled “الغلاف + PTY + العملية”| واجهة غلاف TypeScript | صادر Rust N-API | ملاحظات |
|---|---|---|
executeShell(options, onChunk?) | executeShell (execute_shell) | تنفيذ غلاف أحادي الاستخدام |
new Shell(options?) | فئة Shell | جلسة غلاف دائمة |
shell.run(options, onChunk?) | Shell::run | يُعيد استخدام الجلسة عند تدفق التحكم باستمرارية |
shell.abort() | Shell::abort | يُلغي التشغيل النشط لتلك النسخة من الغلاف |
new PtySession() | فئة PtySession | جلسة PTY ذات حالة |
pty.start(options, onChunk?) | PtySession::start | تشغيل PTY تفاعلي |
pty.write(data) | PtySession::write | تمرير مباشر لـ stdin الخام |
pty.resize(cols, rows) | PtySession::resize | أبعاد طرفية محدودة |
pty.kill() | PtySession::kill | قتل قسري للعملية الفرعية النشطة في PTY |
killTree(pid, signal) | killTree (kill_tree) | إنهاء شجرة العمليات بدءاً من الأبناء |
listDescendants(pid) | listDescendants (list_descendants) | قائمة تعاودية بالعمليات الفرعية |
المفاتيح
Section titled “المفاتيح”| واجهة غلاف TypeScript | صادر Rust N-API | ملاحظات |
|---|---|---|
matchesKittySequence(data, cp, mod) | matchesKittySequence (matches_kitty_sequence) | مطابقة codepoint+modifier لـ Kitty |
parseKey(data, kittyProtocolActive) | parseKey (parse_key) | محلل معرِّف المفتاح المُطبَّع |
matchesLegacySequence(data, keyName) | matchesLegacySequence (matches_legacy_sequence) | فحص خريطة التسلسل القديم الدقيق |
parseKittySequence(data) | parseKittySequence (parse_kitty_sequence) | نتيجة تحليل Kitty المهيكلة |
matchesKey(data, keyId, kittyProtocolActive) | matchesKey (matches_key) | مطابقة مفاتيح عالية المستوى |
ملاحظات تنظيف الجلسات المهجورة والإنهاء
Section titled “ملاحظات تنظيف الجلسات المهجورة والإنهاء”- جلسة الغلاف الدائمة: إذا أُلغي تشغيل ما أو انتهت مهلته أو أخفق أو كان تدفق التحكم من غير النوع الاستمراري، يُسقط Rust صراحةً حالة الجلسة الداخلية. تحتفظ عمليات التشغيل العادية الناجحة بالجلسة لإعادة الاستخدام.
- جلسة PTY: يُمسح
coreدائماً بعد انتهاءstart()، بما في ذلك مسارات الفشل. - لا يُعرض عقد قتل صريح مدفوع بمُنهي JS من قِبل الأغلفة؛ يرتبط التنظيف أساساً بمسارات اكتمال التشغيل/الإلغاء. يجب على المستدعين استخدام
timeoutMsأوAbortSignalأوshell.abort()أوpty.kill()للإنهاء الحتمي.