Μετάβαση στο περιεχόμενο

Έξυπνο HTTP

Το Pitmaster επικοινωνεί με διακομιστές git μέσω HTTPS χρησιμοποιώντας το έξυπνο πρωτόκολλο HTTP. Αυτό είναι το κύριο μέσο μεταφοράς μέσω δικτύου. Χρησιμοποιεί τις εγγενείς λειτουργίες ροής του PHP (fopen με περιβάλλον ροής) για αιτήματα HTTP, επομένως πρέπει να είναι ενεργοποιημένο το allow_url_fopen.

SmartHttpClient

PHP
use Pitmaster\Protocol\SmartHttpClient;

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

Η προεπιλεγμένη τιμή του χρονικού ορίου είναι η σταθερά PITMASTER_HTTP_TIMEOUT (ακέραιος αριθμός) ή 30 δευτερόλεπτα αν δεν έχει οριστεί.

Εντοπισμός αναφορών

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() κάνει το ίδιο για το git-receive-pack. Το αίτημα εντοπισμού αναφορών αποστέλλεται στη διεύθυνση:

Κώδικας
GET <url>/info/refs?service=git-upload-pack

Η απόκριση είναι μια λίστα αναφορών κωδικοποιημένη σε pkt-line, με τις δυνατότητες στην πρώτη γραμμή.

Αποστολή pack (fetch)

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

Στέλνει ένα POST στο <url>/git-upload-pack με το σώμα διαπραγμάτευσης want/have. Επιστρέφει το ακατέργαστο σώμα απόκρισης (pkt-lines, NAK και δεδομένα side-band). Το UploadPackClient δημιουργεί το αίτημα και εξάγει το pack:

PHP
use Pitmaster\Protocol\UploadPackClient;

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

Λήψη pack (push)

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

Στέλνει ένα POST στο <url>/git-receive-pack με τις εντολές ενημέρωσης αναφορών και τα δεδομένα pack.

Κωδικοποίηση PktLine

Το πρωτόκολλο git χρησιμοποιεί πλαισίωση pkt-line για όλη την επικοινωνία. Κάθε γραμμή έχει ως πρόθεμα το συνολικό μήκος της (μαζί με το πρόθεμα μήκους των 4 byte), κωδικοποιημένο ως 4 δεκαεξαδικά ψηφία.

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)

Κανόνες μήκους

  • Ελάχιστη γραμμή δεδομένων: 0005 (ωφέλιμο φορτίο 1 byte)
  • Μέγιστη γραμμή δεδομένων: fff0 (ωφέλιμο φορτίο 65516 byte)
  • Πακέτο εκκαθάρισης: 0000
  • Πακέτο οριοθέτησης: 0001
  • Τέλος απόκρισης: 0002 (πρωτοκόλλου v2· το χειρίζεται το ProtocolV2::decode(), ενώ το PktLine::decode() το απορρίπτει)
PHP
PktLine::MAX_PAYLOAD;  // 65516 (65520 - 4)

Εντοπισμός αναφορών

Η κλάση RefDiscovery αναλύει τη διαφήμιση αναφορών του διακομιστή.

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

Μορφή διαφήμισης αναφορών

Η πρώτη γραμμή της διαφήμισης περιλαμβάνει δυνατότητες:

Κώδικας
<hash> HEAD\0<capability list>\n
<hash> refs/heads/main\n
<hash> refs/tags/v1.0\n
0000

Δυνατότητες

Η κλάση Capability αναλύει και διαχειρίζεται τις δυνατότητες του πρωτοκόλλου.

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

Συνήθεις δυνατότητες

Δυνατότητα Σημασία
multi_ack Ο διακομιστής υποστηρίζει διαπραγμάτευση multi-ack
thin-pack Ο διακομιστής στέλνει thin packs (ενδέχεται να παραλείπονται βασικά αντικείμενα). Το Pitmaster το ζητά, αλλά δεν μπορεί ακόμη να δημιουργήσει ευρετήριο για thin packs (#16)
side-band Ο διακομιστής χρησιμοποιεί side-band για δεδομένα pack (με όριο τα 1000 byte)
side-band-64k Ο διακομιστής χρησιμοποιεί side-band 64K για δεδομένα pack
ofs-delta Το pack μπορεί να χρησιμοποιεί αντικείμενα OFS_DELTA
shallow Ο διακομιστής υποστηρίζει shallow clone
no-done Ο διακομιστής δεν απαιτεί γραμμή "done"
symref=HEAD:refs/heads/main Συμβολικός στόχος του HEAD
agent=git/2.45.0 Έκδοση git του διακομιστή

Διαχωρισμός καναλιών side-band

Όταν ο διακομιστής χρησιμοποιεί side-band, τα δεδομένα pack πολυπλέκονται με μηνύματα προόδου και σφάλματος. Το πρώτο byte του ωφέλιμου φορτίου κάθε pkt-line υποδεικνύει το κανάλι:

Κανάλι Σημασία
1 Δεδομένα pack
2 Μηνύματα προόδου (stderr)
3 Μηνύματα μοιραίου σφάλματος

Το Pitmaster του UploadPackClient αφαιρεί τα byte καναλιού και ανασυνθέτει τα δεδομένα pack.

Εκδόσεις πρωτοκόλλου

v1 (προεπιλογή)

Το παραδοσιακό πρωτόκολλο. Ο εντοπισμός αναφορών στέλνει όλες τις αναφορές μαζί. Το Pitmaster διαπραγματεύεται σε έναν μόνο γύρο: στέλνει όσα ζητά, κάθε τοπική κορυφή αναφοράς ως have και το done.

v2

Ένα απλούστερο πρωτόκολλο με καλύτερη απόδοση.

Βασικές διαφορές από το v1:

  • Ο εντοπισμός αναφορών είναι ξεχωριστή εντολή ls-refs (μπορεί να φιλτράρει αναφορές)
  • Το fetch είναι μία εντολή fetch με δομημένες παραμέτρους
  • Χρησιμοποιεί πακέτα οριοθέτησης (0001) για να διαχωρίζει ενότητες

Τα clone() και fetch() χρησιμοποιούν πάντα το v1. Το v2 είναι διαθέσιμο όταν το καλείτε ρητά:

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

Ροή αιτημάτων HTTP

Κλωνοποίηση/Λήψη

Κώδικας
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)

Αποστολή

Κώδικας
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

Χειρισμός σφαλμάτων

Τα σφάλματα δικτύου προκαλούν ProtocolException. Αν αποτύχει η ανταλλαγή έξυπνου HTTP για clone() ή fetch(), το Pitmaster επιχειρεί ξανά μέσω απλού HTTP και, αν αποτύχει κι αυτό, επαναφέρει το αρχικό σφάλμα. Άλλες αποτυχίες (άγνωστος απομακρυσμένος διακομιστής, λαβή χωρίς διεργασία, pack που δεν μπορεί να καταχωριστεί σε ευρετήριο) προκαλούν άλλους τύπους εξαιρέσεων:

PHP
use Pitmaster\Exceptions\ProtocolException;

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

Συνήθη σφάλματα:

  • Ο διακομιστής δεν είναι προσβάσιμος (λήξη χρονικού ορίου)
  • Απαιτείται έλεγχος ταυτότητας ή δεν βρέθηκε το αποθετήριο (αναφέρεται ως Unexpected HTTP status 401, 403 ή 404)
  • Μη αναμενόμενο Content-Type στην απόκριση
  • Μη έγκυρα δεδομένα pkt-line
  • Μήνυμα σφάλματος από κανάλι side-band