
# Viedais HTTP

Pitmaster sazinās ar git serveriem, izmantojot HTTPS un viedo HTTP protokolu. Tas ir galvenais tīkla transports. Tiek izmantotas PHP iebūvētās plūsmas funkcijas (`fopen` ar plūsmas kontekstu) HTTP pieprasījumiem, tāpēc jābūt iespējotam `allow_url_fopen`.

## SmartHttpClient

```php
use Pitmaster\Protocol\SmartHttpClient;

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

Noildzes noklusējuma vērtība ir konstante `PITMASTER_HTTP_TIMEOUT` (vesels skaitlis) vai 30 sekundes, ja tā nav definēta.

### Refu atklāšana

```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()` dara to pašu attiecībā uz `git-receive-pack`. Refa atklāšanas pieprasījums tiek nosūtīts uz:
```
GET <url>/info/refs?service=git-upload-pack
```

Atbilde ir pkt-line kodēts refu saraksts, kura pirmajā rindā ir iespējas.

### Upload pack (izgūšana)

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

Nosūta POST pieprasījumu uz `<url>/git-upload-pack` ar vajadzīgo un esošo objektu saskaņošanas pamatdaļu. Atgriež neapstrādāto atbildes pamatdaļu (pkt-line, `NAK` un side-band datus). `UploadPackClient` izveido pieprasījumu un iegūst pack:

```php
use Pitmaster\Protocol\UploadPackClient;

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

### Receive pack (nosūtīšana)

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

Nosūta POST pieprasījumu uz `<url>/git-receive-pack` ar refu atjaunināšanas komandām un pack datiem.

## PktLine kodējums

git protokolā visai saziņai izmanto pkt-line ietvaru. Katras rindas sākumā ir tās kopējais garums, ieskaitot 4 baitu garuma prefiksu, kas kodēts kā 4 heksadecimālcipari.

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

### Garuma noteikumi

- Minimālā datu rinda: `0005` (1 baita saturs)
- Maksimālā datu rinda: `fff0` (65516 baitu saturs)
- Iztukšošanas pakete: `0000`
- Atdalītāja pakete: `0001`
- Atbildes beigu pakete: `0002` (protokolā v2; to apstrādā `ProtocolV2::decode()`, bet `PktLine::decode()` to noraida)

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

## Refa atklāšana

Klase `RefDiscovery` parsē servera refu paziņojumu.

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

### Refa paziņojuma formāts

Paziņojuma pirmajā rindā ir iekļautas iespējas:

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

## Iespējas

Klase `Capability` parsē un pārvalda protokola iespējas.

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

### Biežākās iespējas

| Iespēja | Nozīme |
|-----------|---------|
| `multi_ack` | Serveris atbalsta vairāku apstiprinājumu saskaņošanu |
| `thin-pack` | Serveris nosūta plānus pack failus (bāzes objekti var nebūt iekļauti). Pitmaster to pieprasa, bet pagaidām nevar indeksēt plānus pack failus ([#16](https://github.com/inline0/pitmaster/issues/16)) |
| `side-band` | Serveris pack datiem izmanto side-band (ierobežots līdz 1000 baitu) |
| `side-band-64k` | Serveris pack datiem izmanto 64K side-band |
| `ofs-delta` | Pack failā var būt OFS_DELTA objekti |
| `shallow` | Serveris atbalsta seklus klonus |
| `no-done` | Serverim nav nepieciešama rinda "done" |
| `symref=HEAD:refs/heads/main` | HEAD simboliskais mērķis |
| `agent=git/2.45.0` | Servera git versija |

## Side-band kanālu atdalīšana

Kad serveris izmanto side-band, pack dati tiek multipleksēti ar progresa un kļūdu ziņojumiem. Katras pkt-line lietderīgās slodzes pirmais baits norāda kanālu:

| Kanāls | Nozīme |
|---------|---------|
| 1 | Pack dati |
| 2 | Progresa ziņojumi (stderr) |
| 3 | Kritiski kļūdu ziņojumi |

Pitmaster `UploadPackClient` noņem kanālu baitus un atkal apvieno pack datus.

## Protokola versijas

### v1 (noklusējuma)

Tradicionālais protokols. Refa atklāšanā visi refi tiek nosūtīti uzreiz. Pitmaster veic saskaņošanu vienā kārtā: nosūta nepieciešamos refus, katra lokālā refa galapunkta komitu kā `have`, kā arī `done`.

### v2

Vienkāršāks protokols ar labāku veiktspēju.

Galvenās atšķirības no v1:
- Refa atklāšana ir atsevišķa `ls-refs` komanda (var filtrēt refus)
- Izgūšanai izmanto vienu `fetch` komandu ar strukturētiem parametriem
- Sadaļu atdalīšanai izmanto atdalītāja paketes (`0001`)

`clone()` un `fetch()` vienmēr izmanto v1. v2 ir pieejams, ja to izsaucat tieši:

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

## HTTP pieprasījuma darbplūsma

### Klonēšana/Iegūšana

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

### Nosūtīšana

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

## Kļūdu apstrāde

Tīkla kļūdas izmet `ProtocolException`. Ja viedā HTTP apmaiņa ar `clone()` vai `fetch()` neizdodas, Pitmaster atkārto mēģinājumu, izmantojot vienkāršo HTTP, un, ja arī tas neizdodas, izmet sākotnējo kļūdu. Citas kļūmes (nezināms attālais repozitorijs, rokturis bez procesa, indeksēt neiespējama pakotne) izmet cita veida izņēmumus:

```php
use Pitmaster\Exceptions\ProtocolException;

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

Biežākās kļūdas:
- Serveris nav sasniedzams (iestājies taimauts)
- Nepieciešama autentifikācija vai repozitorijs nav atrasts (ziņots kā `Unexpected HTTP status 401`, `403` vai `404`)
- Negaidīts `Content-Type` atbildē
- Nederīgi pkt-line dati
- Sānu joslas kļūdu kanāla ziņojums
