*/ private $body; /** * Transport or application error message, empty on success. * * @var string */ private $error; /** * @param int $status HTTP status. * @param array $body Decoded body. * @param string $error Error message. */ public function __construct( int $status, array $body = array(), string $error = '' ) { $this->status = $status; $this->body = $body; $this->error = $error; } /** * A response for a request that never reached the collector. * * @param string $message Reason. * @return self */ public static function failed( string $message ): self { return new self( 0, array(), $message ); } /** * Whether the collector accepted the call. * * @return bool */ public function is_ok(): bool { return $this->status >= 200 && $this->status < 300; } /** * Whether sending the identical payload again could plausibly succeed. * * @return bool */ public function is_retryable(): bool { if ( $this->is_ok() ) { return false; } // No status at all means a timeout, a DNS failure or a dropped connection — the request may // never have been seen, so it is exactly the case retrying exists for. if ( 0 === $this->status ) { return true; } // 429 and 5xx are the collector saying "not now" rather than "not this". Everything else in the // 4xx range is a decision about the payload or the key, and will be repeated verbatim. return 408 === $this->status || 429 === $this->status || $this->status >= 500; } /** * HTTP status, or zero. * * @return int */ public function status(): int { return $this->status; } /** * The decoded body. * * @return array */ public function body(): array { return $this->body; } /** * One top-level body value. * * @param string $key Body key. * @param mixed $default Value when absent. * @return mixed */ public function get( string $key, $default = null ) { return array_key_exists( $key, $this->body ) ? $this->body[ $key ] : $default; } /** * A message describing the failure, suitable for an admin notice. * * @return string */ public function error(): string { if ( '' !== $this->error ) { return $this->error; } if ( $this->is_ok() ) { return ''; } foreach ( array( 'message', 'error' ) as $key ) { if ( isset( $this->body[ $key ] ) && is_scalar( $this->body[ $key ] ) ) { return (string) $this->body[ $key ]; } } /* translators: %d: HTTP status code returned by the AdPix collector. */ return sprintf( __( 'The AdPix collector returned HTTP %d.', 'adpix-analytics' ), $this->status ); } /** * The collector's request id, which is what support needs to find the call in its own logs. * * @return string */ public function request_id(): string { $id = $this->get( 'request_id', '' ); return is_scalar( $id ) ? (string) $id : ''; } }