$lines Checkpoint JSONL lines, oldest first. * @param string $requestId Normalized ledger id of the table attempt. * @return array{bytes: int|null, source: string, resource_timing_state: string} */ public static function forRequest(array $lines, string $requestId): array { $result = array( 'bytes' => null, 'source' => ABJ_404_Solution_MeasuredBodyBytes::SOURCE_UNAVAILABLE, 'resource_timing_state' => ABJ_404_Solution_MeasuredBodyBytes::SOURCE_UNAVAILABLE, ); if ($requestId === '') { return $result; } foreach ($lines as $line) { // Lines that cannot possibly match are rejected before the JSON // decoder sees them: this pass runs over whole journals. if (strpos($line, ABJ_404_Solution_DiagnosticClientVerdict::PRIOR_ATTEMPT_EVENT) === false) { continue; } $record = json_decode($line, true); if (!is_array($record) || ABJ_404_Solution_DiagnosticClientVerdict::reportedOutcome($record)['id'] !== $requestId) { continue; } // Latest report wins: a retried attempt is reported more than once // and the later report describes the later delivery. $report = is_array($record['report'] ?? null) ? $record['report'] : array(); $timing = is_array($report['rt'] ?? null) ? $report['rt'] : array(); $bytes = ABJ_404_Solution_MeasuredBodyBytes::disclosed($timing['decodedBodySize'] ?? null); $state = $report['rtState'] ?? null; $result = array( 'bytes' => $bytes, 'source' => $bytes === null ? ABJ_404_Solution_MeasuredBodyBytes::SOURCE_UNAVAILABLE : ABJ_404_Solution_MeasuredBodyBytes::SOURCE_RESOURCE_TIMING, 'resource_timing_state' => is_scalar($state) ? (string)$state : ABJ_404_Solution_MeasuredBodyBytes::SOURCE_UNAVAILABLE, ); } return $result; } }