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
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í
$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)
$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:
use Pitmaster\Protocol\UploadPackClient;
$client = new UploadPackClient($http);
$packData = $client->fetch($url, $wants, $haves); // ObjectId[] wants and haves
Prijatie balíka (odoslanie zmien)
$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.
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 hoProtocolV2::decode(), zatiaľ čoPktLine::decode()ho odmieta)
PktLine::MAX_PAYLOAD; // 65516 (65520 - 4)
Zisťovanie referencií
Trieda RefDiscovery analyzuje oznámenie referencií zo servera.
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.
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) |
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 |
PitmasterUploadPackClient 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
fetchso š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:
$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:
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,403alebo404) - Neočakávaný
Content-Typev odpovedi - Neplatné údaje pkt-line
- Správa z chybového kanála side-band