
# HTTP الذكي

يتواصل Pitmaster مع خوادم git عبر HTTPS باستخدام بروتوكول HTTP الذكي. وهذه وسيلة النقل الأساسية عبر الشبكة. ويستخدم وظائف التدفق الأصلية في PHP (`fopen` مع سياق تدفق) لطلبات HTTP، لذا يجب تفعيل `allow_url_fopen`.

## SmartHttpClient

```php
use Pitmaster\Protocol\SmartHttpClient;

$http = new SmartHttpClient();
// Or with custom timeout:
$http = new SmartHttpClient(timeout: 60);
```

تكون المهلة افتراضيًا قيمة الثابت `PITMASTER_HTTP_TIMEOUT` (عددًا صحيحًا)، أو 30 ثانية إذا لم يكن معرّفًا.

### اكتشاف المراجع

```php
$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، مع الإمكانات في السطر الأول.

### حزمة الرفع (الجلب)

```php
$response = $http->uploadPack($url, $requestBody);
```

يرسل طلب POST إلى `<url>/git-upload-pack` يتضمن متن التفاوض على المطلوب والمتاح. ويعيد متن الاستجابة الخام (أسطر pkt، و`NAK`، وبيانات النطاق الجانبي). ينشئ `UploadPackClient` الطلب ويستخرج الحزمة:

```php
use Pitmaster\Protocol\UploadPackClient;

$client = new UploadPackClient($http);
$packData = $client->fetch($url, $wants, $haves);   // ObjectId[] wants and haves
```

### حزمة الاستلام (الدفع)

```php
$response = $http->receivePack($url, $requestBody);
```

يرسل طلب POST إلى `<url>/git-receive-pack` يتضمن أوامر تحديث المراجع وبيانات الحزمة.

## ترميز PktLine

يستخدم بروتوكول git تأطير pkt-line لجميع الاتصالات. يسبق كل سطر طوله الإجمالي، بما في ذلك بادئة الطول ذات 4 بايتات، المرمّز بأربعة أرقام ست عشرية.

```php
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()`)

```php
PktLine::MAX_PAYLOAD;  // 65516 (65520 - 4)
```

## اكتشاف المراجع

تحلّل الفئة `RefDiscovery` إعلان المراجع الصادر عن الخادم.

```php
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` إمكانات البروتوكول وتديرها.

```php
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](https://github.com/inline0/pitmaster/issues/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 عند استدعائه صراحةً:

```php
$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 البسيط، ثم يعيد رمي الخطأ الأصلي إذا فشلت المحاولة أيضًا. أما الإخفاقات الأخرى (مثل جهة بعيدة غير معروفة أو مقبض بلا عملية أو حزمة يتعذر فهرستها) فترمي أنواعًا أخرى من الاستثناءات:

```php
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 غير صالحة
- رسالة خطأ في قناة النطاق الجانبي
