
# Protokolai

Pitmaster palaiko kelis tinklo transporto protokolus ryšiui su git serveriais. Pagrindinis transportas yra išmanusis HTTP. Didesniam suderinamumui užtikrinti siūlomi ir kiti protokolai.

## Išmanusis HTTP (pagrindinis)

Rekomenduojamas transportas. Veikia per HTTPS ir yra plačiausiai naudojamas protokolas. Nėra API pasirinktinių antraščių ar prisijungimo duomenų perdavimui; juos galima perduoti tik URL (`https://user:token@host/repo.git`), kurį PHP siunčia kaip Basic autentifikavimą. `clone()` saugo URL, įskaitant prisijungimo duomenis, `.git/config` faile kaip `remote.origin.url`. Užklausoms naudojami PHP srautų įvyniokliai, todėl turi būti įjungtas `allow_url_fopen`.

```php
use Pitmaster\Protocol\SmartHttpClient;

$http = new SmartHttpClient(timeout: 30);
$discovery = $http->discoverRefs('https://github.com/user/repo.git');
```

Išsamią informaciją rasite skiltyje [Išmanusis HTTP](https://pitmaster.inline0.dev/lt/docs/network/smart-http).

### Protokolas v1

Tradicinis išmanusis HTTP protokolas. Aptikimo metu siunčiamos visos nuorodos, o derantis naudojamos norimų, turimų ir užbaigimo eilutės.

```php
use Pitmaster\Protocol\ProtocolV1;
```

### Protokolas v2

Naujesnis protokolas su struktūruotomis komandomis (`ls-refs`, `fetch`). Veiksmingesnis saugyklose su daug nuorodų, nes klientas gali filtruoti nuorodų sąrašą.

`clone()` ir `fetch()` visada naudoja protokolą v1. Protokolas v2 aiškiai pasiekiamas per išmanųjį HTTP naudojant `SmartHttpClient::discoverRefsV2()` ir `UploadPackClient::fetchV2()`.

## Paprastasis HTTP

Atsarginis protokolas serveriams, nepalaikantiems išmaniojo HTTP protokolo. Paprastuoju protokolu objektai ir paketai gaunami atskirai, siunčiant įprastas HTTP GET užklausas.

```php
use Pitmaster\Protocol\DumbHttpClient;

$client = new DumbHttpClient();
```

Paprastojo HTTP apribojimai:
- Nėra derinimo (klientas turi atsisiųsti viską)
- Perduodant netaikomas deltų glaudinimas
- Gerokai lėtesnis už išmanųjį HTTP
- Kai kurie serveriai (GitHub, GitLab) jo nepalaiko

Paprastuoju protokolu gaunami:
1. `GET /info/refs` (paprastasis tekstas, be pkt-line)
2. `GET /HEAD` (numatytoji šaka)
3. `GET /objects/info/packs` (prieinamų paketų sąrašas)
4. `GET /objects/pack/pack-<hash>.pack` ir `.idx` (kiekvienas sąraše nurodytas paketas ir jo indeksas)
5. `GET /objects/<xx>/<rest>` (pavieniai palaidi objektai, pereinant nuo nuorodų viršūnių)

5 veiksmas atliekamas tik tada, kai serveris nenurodo jokių paketų. Jei paketai nurodyti, serveryje kaip palaidi failai esantys objektai neatsisiunčiami ([#18](https://github.com/inline0/pitmaster/issues/18)). Paprastasis klientas priima tik 40 simbolių objektų ID (SHA-1). Išmaniesiems HTTP mainams nepavykus, `clone()` ir `fetch()` pereina prie paprastojo HTTP.

## SSH

Jei įkeltas `ssh2` PHP plėtinys, SSH transportas jį naudoja. Kitu atveju per `proc_open()` paleidžiamas sistemos `ssh` klientas. Abiem atvejais nuotolinėje saugykloje vykdoma `git-upload-pack` arba `git-receive-pack`.

```php
use Pitmaster\Protocol\SshClient;

$client = new SshClient();
```

SSH URL:
```
git@github.com:user/repo.git
ssh://git@github.com/user/repo.git
```

Plėtinio nereikia. Šie du būdai veikia skirtingai:

**Sistemos `ssh` klientas** (naudojamas, kai `ssh2` neįkeltas). Pitmaster vykdo `ssh -o BatchMode=yes -o ConnectTimeout=30 -p <port> <user>@<host> <command>`, todėl autentifikavimui ir pagrindinio kompiuterio raktų tikrinimui taikoma jūsų SSH konfigūracija bei agentas. Komandą keičia šie aplinkos kintamieji:

| Kintamasis | Poveikis |
|----------|--------|
| `PITMASTER_SSH_COMMAND` | Vykdomasis failas, paleidžiamas vietoj `ssh` |
| `PITMASTER_SSH_IDENTITY_FILE` | Perduodamas kaip `-i <file>` |
| `PITMASTER_SSH_KNOWN_HOSTS` | Perduodamas kaip `-o UserKnownHostsFile=<file>` |
| `PITMASTER_SSH_STRICT_HOST_KEY_CHECKING` | Perduodamas kaip `-o StrictHostKeyChecking=<value>` |

Šis kelias paleidžia procesą, todėl jo negalima naudoti su deskriptoriais, atidarytais naudojant `['processes' => false]`.

**`ssh2` plėtinys** (visada naudojamas, kai įkeltas). Pitmaster autentifikuojasi naudodamas `~/.ssh/id_rsa`, o jei RSA raktas yra, bet atmetamas, – naudodamas `~/.ssh/id_ed25519`; kitais atvejais naudojamas SSH agentas. `PITMASTER_SSH_*` kintamųjų nepaisoma, o serverio pagrindinio kompiuterio raktas šiuo būdu netikrinamas ([#22](https://github.com/inline0/pitmaster/issues/22)).

SSH transportas vykdo `git-upload-pack` arba `git-receive-pack` kaip nuotolinę komandą ir palaiko ryšį SSH kanalu, naudodamas tą patį pkt-line protokolą kaip ir išmanusis HTTP.

## Git protokolas (TCP)

Savasis git protokolas palaiko ryšį per TCP prievadą 9418, naudodamas PHP lizdus. `GitProtocolClient` įgyvendina nuorodų aptikimą ir `upload-pack` (gavimą); siųsti duomenų juo negalima. `clone()` ir `fetch()` nenukreipia `git://` URL į jį, todėl naudokite tiesiogiai klientą.

```php
use Pitmaster\Protocol\GitProtocolClient;

$client = new GitProtocolClient();
```

Git URL:
```
git://github.com/user/repo.git
```

Savybės:
- Autentifikavimo nėra (praktiškai tik skaitoma prieiga)
- Šifravimo nėra
- Dauguma prieglobos paslaugų teikėjų šį protokolą laiko pasenusiu
- Naudojamas toks pats pkt-line formatavimas kaip išmaniajame HTTP

git protokolas pradinėje užklausoje siunčia paslaugos pavadinimą ir saugyklos kelią, tada vykdo įprastą pkt-line nuorodų aptikimą ir paketų derybą.

## Paketai

Git paketai yra neprisijungus naudojami paketų failai su nuorodų informacija. Jie leidžia perkelti saugyklos duomenis be tinklo ryšio.

```php
use Pitmaster\Protocol\Bundle;

// Read a bundle file
$bundle = Bundle::open('/path/to/repo.bundle');
$refs = $bundle->refs();
$packData = $bundle->packData();
$prerequisites = $bundle->prerequisites();

// Create one
$bundle = Bundle::create(['refs/heads/main' => $commitId], $packData);
$bundle->writeTo('/path/to/out.bundle');
```

Pitmaster nuskaito v2 ir v3 paketų antraštes. Paketui importuoti nėra `Repository` metodo: įrašykite `packData()` į `.git/objects/pack/`, sukurkite jo indeksą naudodami `PackIndexer::writeIndex()` ir patys atnaujinkite nuorodas.

Paketų formatas:
```
# v2 git bundle\n
-<prerequisite hash>\n    (zero or more)
<hash> <refname>\n        (one or more)
\n
<pack data>               (standard pack file format)
```

Paketai naudingi:
- Perkeliant duomenis fizinėmis laikmenomis (USB įrenginiais)
- Laipsniškoms atsarginėms kopijoms
- Klonams paruošti izoliuotose aplinkose

## Negiliosios klonuotos saugyklos

Pitmaster palaiko negilųjį klonavimą, kai gaunama tik riboto gylio pakeitimų istorija.

```php
use Pitmaster\Protocol\ShallowClone;
```

Perduokite gylį į `Pitmaster::clone($url, $path, $depth)` arba `$repo->fetch($remote, $depth)`. Prie užklausos pridedama galimybė `shallow` ir eilutė `deepen`:
```
want <hash>
deepen <depth>
```

Serveris atsako `shallow <hash>` eilutėmis, nurodančiomis, kur istorija buvo sutrumpinta. Pitmaster apskaičiuoja negiliąją ribą pagal patį gylį ir naudoja serverio `shallow` eilutes, jei apskaičiuojant nieko nerandama; rezultatas įrašomas į `.git/shallow`. `ShallowClone::readShallow()`, `writeShallow()` ir `isShallow()` tiesiogiai naudoja šį failą.

## Protokolų palyginimas

| Protokolas | Autentifikavimas | Šifravimas | Siuntimas | Įprastas naudojimas |
|----------|------|-----------|-------------|-------------|
| Išmanusis HTTP | Prisijungimo duomenys URL | HTTPS | Taip | Pagrindinis transportas |
| Paprastasis HTTP | Prisijungimo duomenys URL | HTTPS | Ne | Senas atsarginis variantas |
| SSH | SSH raktai arba agentas | SSH | Taip | Privačios saugyklos, CI |
| Git (TCP) | Nėra | Nėra | Ne | Tik skaitomos veidrodinės kopijos |
| Paketas | Netaikoma | Netaikoma | Netaikoma | Perkėlimas neprisijungus |

## Transporto pasirinkimas

`Pitmaster::clone()`, `$repo->fetch()` ir `$repo->push()` parenka transportą pagal URL:

| URL šablonas | Transportas |
|------------|-----------|
| `ssh://...` | SSH |
| `user@host:path` | SSH |
| Visa kita (`https://...`, `http://...`) | Išmanusis HTTP; klonavimas ir gavimas grįžta prie paprastojo HTTP |

`git://` URL ir vietiniai keliai šių metodų nepalaikomi: jie perduodami išmaniojo HTTP klientui ir sukelia klaidą. Jei naudojate `git://`, tiesiogiai naudokite `GitProtocolClient`. Šiuo metu HTTPS URL, kuriame yra ir naudotojas, ir prievadas (`https://user@host:8443/repo.git`), klaidingai palaikomas SSH URL ([#17](https://github.com/inline0/pitmaster/issues/17)).
