
# Nutikas HTTP

Pitmaster suhtleb git-serveritega HTTPS kaudu, kasutades nutikat HTTP-protokolli. See on peamine võrguedastusviis. See kasutab PHP natiivseid voo-funktsioone (`fopen` voo kontekstiga) HTTP päringute jaoks, seega peab `allow_url_fopen` olema lubatud.

## SmartHttpClient

```php
use Pitmaster\Protocol\SmartHttpClient;

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

Vaikimisi on ajalõpp konstant `PITMASTER_HTTP_TIMEOUT` (täisarv) või 30 sekundit, kui see pole määratud.

### Viidete tuvastamine

```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()` teeb sama `git-receive-pack` puhul. Viidete tuvastamise päring saadetakse aadressile:
```
GET <url>/info/refs?service=git-upload-pack
```

Vastus on pkt-line-kodeeringus viidete loend, mille esimesel real on võimalused.

### Paketi üleslaadimine (toomine)

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

Saadab aadressile `<url>/git-upload-pack` POST-päringu, mille sisuks on want/have läbirääkimisandmed. Tagastab toore vastusekeha (pkt-read, `NAK` ja side-band-andmed). `UploadPackClient` koostab päringu ja eraldab paketi:

```php
use Pitmaster\Protocol\UploadPackClient;

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

### Paketi vastuvõtmine (tõukamine)

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

Saadab aadressile `<url>/git-receive-pack` POST-päringu koos viidete uuenduskäskude ja paketiandmetega.

## PktLine'i kodeering

git-protokoll kasutab kogu side jaoks pkt-line-raamistust. Iga rea ees on selle kogupikkus (koos 4-baidise pikkuse eesliitega), mis on kodeeritud 4 kuueteistkümnendnumbrina.

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

### Pikkusreeglid

- Andmerea minimaalne pikkus: `0005` (1 baidi kasulik koormus)
- Andmerea maksimaalne pikkus: `fff0` (65516 baidi kasulik koormus)
- Tühjenduspakett: `0000`
- Eraldajapakett: `0001`
- Vastuse lõpp: `0002` (protokolli v2; seda käsitleb `ProtocolV2::decode()`, `PktLine::decode()` lükkab selle tagasi)

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

## Viidete tuvastamine

`RefDiscovery` klass parsib serveri viiteteate.

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

### Viiteteate vorming

Teate esimene rida sisaldab võimalusi:

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

## Võimalused

`Capability` klass parsib ja haldab protokolli võimalusi.

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

### Levinud võimalused

| Võimalus | Tähendus |
|-----------|---------|
| `multi_ack` | Server toetab mitme ACK-ga läbirääkimist |
| `thin-pack` | Server saadab õhukesi pakette (baasobjektid võivad puududa). Pitmaster küsib seda, kuid ei suuda veel õhukesi pakette indekseerida ([#16](https://github.com/inline0/pitmaster/issues/16)) |
| `side-band` | Server kasutab paketiandmete jaoks side-band'i (piirang 1000 baidile) |
| `side-band-64k` | Server kasutab paketiandmete jaoks 64K side-band'i |
| `ofs-delta` | Pakett võib kasutada OFS_DELTA-objekte |
| `shallow` | Server toetab madalat kloonimist |
| `no-done` | Server ei nõua rida "done" |
| `symref=HEAD:refs/heads/main` | HEAD-i sümboolne sihtmärk |
| `agent=git/2.45.0` | Serveri git-versioon |

## Side-band-kanalite eraldamine

Kui server kasutab side-band'i, multipleksitakse paketiandmed edenemis- ja veateadetega. Iga pkt-line'i kasuliku koormuse esimene bait näitab kanalit:

| Kanal | Tähendus |
|---------|---------|
| 1 | Paketiandmed |
| 2 | Edenemisteated (stderr) |
| 3 | Saatuslikud veateated |

Pitmaster `UploadPackClient` eemaldab kanali baidid ja paneb paketiandmed uuesti kokku.

## Protokolli versioonid

### v1 (vaikimisi)

Traditsiooniline protokoll. Viidete tuvastamisel saadetakse kõik viited korraga. Pitmaster peab läbirääkimisi ühes voorus: saadab oma soovid, iga kohaliku viite tipu kui `have` ning `done`.

### v2

Lihtsam ja parema jõudlusega protokoll.

Peamised erinevused võrreldes protokolliga v1:
- Viidete tuvastamine on eraldi käsk `ls-refs` (viiteid saab filtreerida)
- Toomine on üks käsk `fetch` struktureeritud parameetritega
- Sektsioonide eraldamiseks kasutatakse eraldajapakette (`0001`)

`clone()` ja `fetch()` kasutavad alati v1. v2 on saadaval, kui kutsute selle selgesõnaliselt:

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

## HTTP päringuvoog

### Kloonimine/toomine

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

### Tõukamine

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

## Vigade käsitlemine

Võrguvead põhjustavad `ProtocolException`. Kui nutikas HTTP-vahetus `clone()` või `fetch()` korral nurjub, proovib Pitmaster uuesti rumala HTTP kaudu ja viskab ebaõnnestumise korral algse vea uuesti. Muud tõrked (tundmatu kaugserver, protsessita käepide, indekseerimatu pakett) põhjustavad teist tüüpi erindeid:

```php
use Pitmaster\Exceptions\ProtocolException;

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

Levinud vead:
- Server pole kättesaadav (ajalõpp)
- Nõutakse autentimist või repositooriumi ei leitud (teatatuna kui `Unexpected HTTP status 401`, `403` või `404`)
- Ootamatu `Content-Type` vastuses
- Vigased pkt-line-andmed
- Side-band'i veakanali teade
