fix: make BusProNet response failures diagnosable and non-fatal
This commit is contained in:
@@ -58,15 +58,58 @@ trait ApiClientTrait
|
||||
fwrite($socket, $send);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a single response message. The protocol prepends the payload length as a
|
||||
* 10 byte header, so read exactly that many bytes rather than guessing at EOF:
|
||||
* a peer that closes mid-stream would otherwise yield a silently truncated body.
|
||||
*
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
private function receive($socket): string
|
||||
{
|
||||
$response = '';
|
||||
$header = $this->readBytes($socket, 10);
|
||||
|
||||
while (false === feof($socket)) {
|
||||
$response .= fread($socket, 4096);
|
||||
if (10 !== strlen($header)) {
|
||||
throw new ApiClientException(sprintf('Incomplete response header, got %d of 10 bytes', strlen($header)));
|
||||
}
|
||||
|
||||
return $response;
|
||||
$expectedLength = (int) trim($header);
|
||||
|
||||
if (1 > $expectedLength) {
|
||||
throw new ApiClientException(sprintf('Response announced an empty body (header "%s")', trim($header)));
|
||||
}
|
||||
|
||||
$body = $this->readBytes($socket, $expectedLength);
|
||||
|
||||
if (strlen($body) !== $expectedLength) {
|
||||
throw new ApiClientException(sprintf('Truncated response, got %d of %d announced bytes', strlen($body), $expectedLength));
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiClientException
|
||||
*/
|
||||
private function readBytes($socket, int $length): string
|
||||
{
|
||||
$buffer = '';
|
||||
|
||||
while (strlen($buffer) < $length && false === feof($socket)) {
|
||||
$chunk = fread($socket, min(4096, $length - strlen($buffer)));
|
||||
|
||||
if (false === $chunk || '' === $chunk) {
|
||||
if (true === (stream_get_meta_data($socket)['timed_out'] ?? false)) {
|
||||
throw new ApiClientException(sprintf('Timed out reading response after %d of %d bytes', strlen($buffer), $length));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$buffer .= $chunk;
|
||||
}
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
private function disconnect($socket): void
|
||||
|
||||
Reference in New Issue
Block a user