
# Inteligentný HTTP

Pitmaster komunikuje so servermi git cez HTTPS pomocou inteligentného protokolu HTTP. Ide o hlavný sieťový prenos. Používa natívne funkcie prúdu v PHP (`fopen` s kontextom prúdu) na požiadavky HTTP, preto musí byť povolené `allow_url_fopen`.

## SmartHttpClient

```php
use Pitmaster\Protocol\SmartHttpClient;

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

Predvolená hodnota časového limitu je konštanta `PITMASTER_HTTP_TIMEOUT` (celé číslo), prípadne 30 sekúnd, ak nie je definovaná.

### Zistenie referencií

```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()` robí to isté pre `git-receive-pack`. Požiadavka na zistenie referencií smeruje na:
```
GET <url>/info/refs?service=git-upload-pack
```

Odpoveďou je zoznam referencií zakódovaný vo formáte pkt-line, pričom schopnosti sú uvedené na prvom riadku.

### Nahratie balíka (načítanie)

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

Odošle požiadavku POST na `<url>/git-upload-pack` s telom obsahujúcim dohodu want/have. Vráti surové telo odpovede (riadky pkt-line, `NAK` a údaje side-band). `UploadPackClient` zostaví požiadavku a vyberie z nej balík:

```php
use Pitmaster\Protocol\UploadPackClient;

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

### Prijatie balíka (odoslanie zmien)

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

Odošle požiadavku POST na `<url>/git-receive-pack` s príkazmi na aktualizáciu referencií a údajmi balíka.

## Kódovanie PktLine

Protokol git používa na všetku komunikáciu rámcovanie pkt-line. Každému riadku predchádza jeho celková dĺžka (vrátane 4-bajtového prefixu dĺžky), zakódovaná ako 4 hexadecimálne číslice.

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

### Pravidlá dĺžky

- Minimálny dátový riadok: `0005` (1 bajt dát)
- Maximálny dátový riadok: `fff0` (65516 bajtov dát)
- Paket na vyprázdnenie: `0000`
- Oddeľovací paket: `0001`
- Koniec odpovede: `0002` (protokol v2; spracúva ho `ProtocolV2::decode()`, zatiaľ čo `PktLine::decode()` ho odmieta)

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

## Zisťovanie referencií

Trieda `RefDiscovery` analyzuje oznámenie referencií zo servera.

```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
```

### Formát oznámenia referencií

Prvý riadok oznámenia obsahuje schopnosti:

```
<hash> HEAD\0<capability list>\n
<hash> refs/heads/main\n
<hash> refs/tags/v1.0\n
0000
```

## Schopnosti

Trieda `Capability` analyzuje a spravuje schopnosti protokolu.

```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']
```

### Bežné schopnosti

| Schopnosť | Význam |
|-----------|---------|
| `multi_ack` | Server podporuje dohodu multi-ack |
| `thin-pack` | Server odosiela tenké balíky (základné objekty môžu chýbať). Pitmaster o ne žiada, ale zatiaľ nedokáže indexovať tenké balíky ([#16](https://github.com/inline0/pitmaster/issues/16)) |
| `side-band` | Server používa side-band pre údaje balíka (obmedzené na 1000 bajtov) |
| `side-band-64k` | Server používa side-band 64K pre údaje balíka |
| `ofs-delta` | Balík môže obsahovať objekty OFS_DELTA |
| `shallow` | Server podporuje plytké klonovanie |
| `no-done` | Server nevyžaduje riadok „done“ |
| `symref=HEAD:refs/heads/main` | Symbolický cieľ HEAD |
| `agent=git/2.45.0` | Verzia git servera |

## Demultiplexovanie side-band

Keď server používa side-band, údaje balíka sa multiplexujú so správami o priebehu a chybách. Prvý bajt dát každej položky pkt-line označuje kanál:

| Kanál | Význam |
|---------|---------|
| 1 | Údaje balíka |
| 2 | Správy o priebehu (stderr) |
| 3 | Závažné chybové správy |

Pitmaster`UploadPackClient` odstráni bajty kanálov a znovu zostaví údaje balíka.

## Verzie protokolu

### v1 (predvolená)

Tradičný protokol. Pri zisťovaní referencií sa naraz odošlú všetky referencie. Pitmaster rokuje v jednom kole: odošle svoje požiadavky want, všetky lokálne vrcholy referencií ako `have` a `done`.

### v2

Jednoduchší protokol s lepším výkonom.

Hlavné rozdiely oproti v1:
- Zisťovanie referencií je samostatný príkaz `ls-refs` (možno filtrovať referencie)
- Načítanie je jediný príkaz `fetch` so štruktúrovanými parametrami
- Na oddelenie sekcií používa oddeľovacie pakety (`0001`)

`clone()` a `fetch()` vždy používajú v1. v2 je k dispozícii, keď ho zavoláte explicitne:

```php
$discovery = $http->discoverRefsV2($url);       // ls-refs
$packData = (new UploadPackClient($http))->fetchV2($url, $wants, $haves);
```

## Tok požiadaviek HTTP

### Klonovanie/načítanie

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

### Odoslanie zmien

```
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
```

## Spracovanie chýb

Chyby siete vyvolávajú `ProtocolException`. Ak zlyhá výmena inteligentného HTTP v rámci `clone()` alebo `fetch()`, Pitmaster zopakuje operáciu cez jednoduchý HTTP a ak zlyhá aj tá, znovu vyvolá pôvodnú chybu. Ostatné zlyhania (neznámy vzdialený zdroj, rukoväť bez procesu, balík, ktorý nemožno indexovať) vyvolajú iné typy výnimiek:

```php
use Pitmaster\Exceptions\ProtocolException;

try {
    $repo->fetch();
} catch (ProtocolException $e) {
    echo "Network error: {$e->getMessage()}\n";
}
```

Bežné chyby:
- Server je nedostupný (časový limit)
- Vyžaduje sa overenie alebo úložisko sa nenašlo (oznámi sa ako `Unexpected HTTP status 401`, `403` alebo `404`)
- Neočakávaný `Content-Type` v odpovedi
- Neplatné údaje pkt-line
- Správa z chybového kanála side-band
