Example #1
0
 /**
  * Append another chunk data to a previously-started chunked upload session.
  *
  * @param string $uploadId
  *     The unique identifier for the chunked upload session.  This is obtained via
  *     {@link chunkedUploadStart}.
  *
  * @param int $byteOffset
  *     The number of bytes you think you've already uploaded to the given chunked upload
  *     session.  The server will append the new chunk of data after that point.
  *
  * @param string $data
  *     The data to append to the existing chunked upload session.
  *
  * @return int|bool
  *     If <code>false</code>, it means the server didn't know about the given
  *     <code>$uploadId</code>.  This may be because the chunked upload session has expired
  *     (they last around 24 hours).
  *     If <code>true</code>, the chunk was successfully uploaded.  If an integer, it means
  *     you and the server don't agree on the current <code>$byteOffset</code>.  The returned
  *     integer is the server's internal byte offset for the chunked upload session.  You need
  *     to adjust your input to match.
  *
  * @throws Exception
  */
 function chunkedUploadContinue($uploadId, $byteOffset, $data)
 {
     Checker::argStringNonEmpty("uploadId", $uploadId);
     Checker::argNat("byteOffset", $byteOffset);
     Checker::argString("data", $data);
     $response = $this->_chunkedUpload(array("upload_id" => $uploadId, "offset" => $byteOffset), $data);
     if ($response->statusCode === 404) {
         // The server doesn't know our upload ID.  Maybe it expired?
         return false;
     }
     $correction = self::_chunkedUploadCheckForOffsetCorrection($response);
     if ($correction !== null) {
         list($correctedUploadId, $correctedByteOffset) = $correction;
         if ($correctedUploadId !== $uploadId) {
             throw new Exception_BadResponse("Corrective 400 upload_id mismatch: us=" . self::q($uploadId) . " server=" . self::q($correctedUploadId));
         }
         if ($correctedByteOffset === $byteOffset) {
             throw new Exception_BadResponse("Corrective 400 offset is the same as ours: {$byteOffset}");
         }
         return $correctedByteOffset;
     }
     if ($response->statusCode !== 200) {
         throw RequestUtil::unexpectedStatus($response);
     }
     list($retUploadId, $retByteOffset) = self::_chunkedUploadParse200Response($response->body);
     $nextByteOffset = $byteOffset + strlen($data);
     if ($uploadId !== $retUploadId) {
         throw new Exception_BadResponse("upload_id mismatch: us=" . self::q($uploadId) . ", server=" . self::q($uploadId));
     }
     if ($nextByteOffset !== $retByteOffset) {
         throw new Exception_BadResponse("next-offset mismatch: us={$nextByteOffset}, server={$retByteOffset}");
     }
     return true;
 }
 /**
  * @param int $maxRetries
  *    The number of times to retry it the action if it fails with one of the transient
  *    API errors.  A value of 1 means we'll try the action once and if it fails, we
  *    will retry once.
  *
  * @param callable $action
  *    The the action you want to retry.
  *
  * @return mixed
  *    Whatever is returned by the $action callable.
  */
 static function runWithRetry($maxRetries, $action)
 {
     Checker::argNat("maxRetries", $maxRetries);
     $retryDelay = 1;
     $numRetries = 0;
     while (true) {
         try {
             return $action();
         } catch (Exception_NetworkIO $ex) {
             $savedEx = $ex;
         } catch (Exception_ServerError $ex) {
             $savedEx = $ex;
         } catch (Exception_RetryLater $ex) {
             $savedEx = $ex;
         }
         // We maxed out our retries.  Propagate the last exception we got.
         if ($numRetries >= $maxRetries) {
             throw $savedEx;
         }
         $numRetries++;
         sleep($retryDelay);
         $retryDelay *= 2;
         // Exponential back-off.
     }
     throw new \RuntimeException("unreachable");
 }