HTTP الذكي
يتواصل Pitmaster مع خوادم git عبر HTTPS باستخدام بروتوكول HTTP الذكي. وهذه وسيلة النقل الأساسية عبر الشبكة. ويستخدم وظائف التدفق الأصلية في PHP (fopen مع سياق تدفق) لطلبات HTTP، لذا يجب تفعيل allow_url_fopen.
SmartHttpClient
use Pitmaster\Protocol\SmartHttpClient;
$http = new SmartHttpClient();
// Or with custom timeout:
$http = new SmartHttpClient(timeout: 60);
تكون المهلة افتراضيًا قيمة الثابت PITMASTER_HTTP_TIMEOUT (عددًا صحيحًا)، أو 30 ثانية إذا لم يكن معرّفًا.
اكتشاف المراجع
$discovery = $http->discoverRefs('https://github.com/user/repo.git');
foreach ($discovery->refs() as $name => $id) {
echo "{$id->hex} {$name}\n";
}
// HEAD symref (e.g., 'refs/heads/main')
$defaultBranch = $discovery->headSymref();
// Specific ref
$mainId = $discovery->ref('refs/heads/main');
// Server capabilities (a Capability object, or null)
$caps = $discovery->capabilities();
ينفذ discoverReceivePackRefs() الأمر نفسه من أجل git-receive-pack. يُرسل طلب اكتشاف المراجع إلى:
GET <url>/info/refs?service=git-upload-pack
الاستجابة قائمة مراجع مرمّزة بصيغة pkt-line، مع الإمكانات في السطر الأول.
حزمة الرفع (الجلب)
$response = $http->uploadPack($url, $requestBody);
يرسل طلب POST إلى <url>/git-upload-pack يتضمن متن التفاوض على المطلوب والمتاح. ويعيد متن الاستجابة الخام (أسطر pkt، وNAK، وبيانات النطاق الجانبي). ينشئ UploadPackClient الطلب ويستخرج الحزمة:
use Pitmaster\Protocol\UploadPackClient;
$client = new UploadPackClient($http);
$packData = $client->fetch($url, $wants, $haves); // ObjectId[] wants and haves
حزمة الاستلام (الدفع)
$response = $http->receivePack($url, $requestBody);
يرسل طلب POST إلى <url>/git-receive-pack يتضمن أوامر تحديث المراجع وبيانات الحزمة.
ترميز PktLine
يستخدم بروتوكول git تأطير pkt-line لجميع الاتصالات. يسبق كل سطر طوله الإجمالي، بما في ذلك بادئة الطول ذات 4 بايتات، المرمّز بأربعة أرقام ست عشرية.
use Pitmaster\Protocol\PktLine;
// Encode a single line
$encoded = PktLine::encode("want abc123def456\n");
// "0016want abc123def456\n"
// Flush packet (end of section)
$flush = PktLine::flush();
// "0000"
// Delimiter packet (protocol v2)
$delim = PktLine::delimiter();
// "0001"
// Decode a stream
$lines = PktLine::decode($rawData);
// Each element is: string (data), null (flush), or false (delimiter)
قواعد الطول
- الحد الأدنى لسطر البيانات:
0005(حمولة بحجم 1 بايت) - الحد الأقصى لسطر البيانات:
fff0(حمولة بحجم 65516 بايت) - حزمة التفريغ:
0000 - حزمة الفاصل:
0001 - نهاية الاستجابة:
0002(في البروتوكول v2؛ يتعامل معهاProtocolV2::decode()، بينما يرفضهاPktLine::decode())
PktLine::MAX_PAYLOAD; // 65516 (65520 - 4)
اكتشاف المراجع
تحلّل الفئة RefDiscovery إعلان المراجع الصادر عن الخادم.
use Pitmaster\Protocol\RefDiscovery;
$discovery = RefDiscovery::parse($pktLines);
// All refs
$refs = $discovery->refs();
// ['refs/heads/main' => ObjectId, 'refs/tags/v1.0' => ObjectId, ...]
// Single ref
$id = $discovery->ref('refs/heads/main');
// HEAD symbolic ref (from capabilities)
$symref = $discovery->headSymref();
// 'refs/heads/main' or null
// Server capabilities
$caps = $discovery->capabilities();
// Capability object (see below), or null
تنسيق إعلان المراجع
يتضمن السطر الأول من الإعلان الإمكانات:
<hash> HEAD\0<capability list>\n
<hash> refs/heads/main\n
<hash> refs/tags/v1.0\n
0000
الإمكانات
تحلّل الفئة Capability إمكانات البروتوكول وتديرها.
use Pitmaster\Protocol\Capability;
$caps = Capability::parse('thin-pack side-band-64k ofs-delta symref=HEAD:refs/heads/main');
$caps->has('thin-pack'); // true
$caps->get('symref'); // 'HEAD:refs/heads/main'
$caps->all(); // ['thin-pack' => null, ..., 'symref' => 'HEAD:refs/heads/main']
الإمكانات الشائعة
| الإمكانية | المعنى |
|---|---|
multi_ack |
يدعم الخادم التفاوض متعدد الإقرارات |
thin-pack |
يرسل الخادم حزمًا رقيقة (قد تُحذف الكائنات الأساسية). يطلبها Pitmaster، لكنه لا يستطيع فهرسة الحزم الرقيقة بعد (#16) |
side-band |
يستخدم الخادم النطاق الجانبي لبيانات الحزمة (بحد أقصى 1000 بايت) |
side-band-64k |
يستخدم الخادم نطاقًا جانبيًا بحجم 64K لبيانات الحزمة |
ofs-delta |
قد تستخدم الحزمة كائنات OFS_DELTA |
shallow |
يدعم الخادم الاستنساخ السطحي |
no-done |
لا يتطلب الخادم سطر «انتهاء» |
symref=HEAD:refs/heads/main |
الهدف الرمزي لـ HEAD |
agent=git/2.45.0 |
إصدار git لدى الخادم |
فصل بيانات النطاق الجانبي
عندما يستخدم الخادم النطاق الجانبي، تتعدد قنوات بيانات الحزمة لتشمل رسائل التقدم والأخطاء. يشير البايت الأول من حمولة كل سطر pkt-line إلى القناة:
| القناة | المعنى |
|---|---|
| 1 | بيانات الحزمة |
| 2 | رسائل التقدم (stderr) |
| 3 | رسائل الخطأ الفادح |
تزيل Pitmaster الخاصة بـ UploadPackClient بايتات القنوات وتعيد تجميع بيانات الحزمة.
إصدارات البروتوكول
v1 (افتراضي)
البروتوكول التقليدي. يرسل اكتشاف المراجع كل المراجع دفعة واحدة. يتفاوض Pitmaster في جولة واحدة: يرسل المطلوب، ورؤوس كل المراجع المحلية على هيئة have، وdone.
v2
بروتوكول أبسط وأفضل أداءً.
الاختلافات الرئيسية عن v1:
- اكتشاف المراجع أمر منفصل
ls-refs(يمكنه تصفية المراجع) - الجلب أمر واحد
fetchبمعلمات منظّمة - يستخدم حزمًا ذات فواصل (
0001) للفصل بين الأقسام
يستخدم كل من clone() وfetch() الإصدار v1 دائمًا. يتوفر v2 عند استدعائه صراحةً:
$discovery = $http->discoverRefsV2($url); // ls-refs
$packData = (new UploadPackClient($http))->fetchV2($url, $wants, $haves);
تدفق طلب HTTP
الاستنساخ/الجلب
1. GET /info/refs?service=git-upload-pack
Response: pkt-line encoded ref list
2. POST /git-upload-pack
Request: want <hash>\n ... have <hash>\n ... done\n
Response: NAK\n + pack data (possibly side-band wrapped)
الدفع
1. GET /info/refs?service=git-receive-pack
Response: pkt-line encoded ref list
2. POST /git-receive-pack
Request: <old-hash> <new-hash> refs/heads/main\0<capabilities>\n
0000
PACK<pack data>
Response: unpack ok\n + ref status lines
معالجة الأخطاء
تؤدي أخطاء الشبكة إلى رمي ProtocolException. عندما يفشل تبادل clone() أو fetch() الذكي عبر HTTP، يعيد Pitmaster المحاولة عبر HTTP البسيط، ثم يعيد رمي الخطأ الأصلي إذا فشلت المحاولة أيضًا. أما الإخفاقات الأخرى (مثل جهة بعيدة غير معروفة أو مقبض بلا عملية أو حزمة يتعذر فهرستها) فترمي أنواعًا أخرى من الاستثناءات:
use Pitmaster\Exceptions\ProtocolException;
try {
$repo->fetch();
} catch (ProtocolException $e) {
echo "Network error: {$e->getMessage()}\n";
}
أخطاء شائعة:
- تعذّر الوصول إلى الخادم (انتهاء المهلة)
- المصادقة مطلوبة أو المستودع غير موجود (يُبلّغ عن ذلك باعتباره
Unexpected HTTP status 401أو403أو404) Content-Typeغير متوقع في الاستجابة- بيانات pkt-line غير صالحة
- رسالة خطأ في قناة النطاق الجانبي