Skip to content

Commit

Permalink
Added CloudFront to list of available CDNs
Browse files Browse the repository at this point in the history
| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Doc PR        | none

* Sanitated starting and ending slashes in CloudFront::getPath()
* Replaced short array syntax [] in CloudFront::flushPaths() to keep BC with PHP 5.3
* Updated CloudFront CDN in order to throw custom exception while wrong paths given.
* Added unit tests for CloudFront.
* Added property "cdnFlushIdentifier" in BaseMedia.
* Updated CDNInterface and its implementations (added getFlushStatus() method).
* Added command to update CDN status for medias that are currently flushing.
* Updated translations.
* Normalized paths withouth leading slash.
* Throw exception while empty paths.
* Updated UpdateCdnStatusCommand (added verbose output).
* Normalized paths withouth leading slash.
* Added BaseProvider::flushCdn() method.
* Added check in BaseProvider to ensure CDN flush only in pre-existent medias.
* Bugfix in UpdateCdnStatusCommand.
  • Loading branch information
phansys committed Jan 9, 2015
1 parent 9d3ea49 commit f1bc740
Show file tree
Hide file tree
Showing 32 changed files with 671 additions and 52 deletions.
15 changes: 12 additions & 3 deletions CDN/CDNInterface.php
Expand Up @@ -34,7 +34,7 @@ public function getPath($relativePath, $isFlushable);
*
* @param string $string
*
* @return void
* @return void|string
*/
public function flush($string);

Expand All @@ -43,7 +43,7 @@ public function flush($string);
*
* @param string $string
*
* @return void
* @return void|string
*/
public function flushByString($string);

Expand All @@ -52,7 +52,16 @@ public function flushByString($string);
*
* @param array $paths
*
* @return void
* @return void|string
*/
public function flushPaths(array $paths);

/**
* Return the CDN status for given identifier
*
* @param string $identifier
*
* @return string
*/
public function getFlushStatus($identifier);
}
219 changes: 219 additions & 0 deletions CDN/CloudFront.php
@@ -0,0 +1,219 @@
<?php
/*
* This file is part of the Sonata project.
*
* (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sonata\MediaBundle\CDN;

use Aws\CloudFront\CloudFrontClient;
use Aws\CloudFront\Exception\CloudFrontException;

/**
*
* From http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Invalidation.html
*
* Invalidating Objects (Web Distributions Only)
* If you need to remove an object from CloudFront edge-server caches before it
* expires, you can do one of the following:
* Invalidate the object. The next time a viewer requests the object, CloudFront
* returns to the origin to fetch the latest version of the object.
* Use object versioning to serve a different version of the object that has a
* different name. For more information, see Updating Existing Objects Using
* Versioned Object Names.
* Important:
* You can invalidate most types of objects that are served by a web
* distribution, but you cannot invalidate media files in the Microsoft Smooth
* Streaming format when you have enabled Smooth Streaming for the corresponding
* cache behavior. In addition, you cannot invalidate objects that are served by
* an RTMP distribution. You can invalidate a specified number of objects each
* month for free. Above that limit, you pay a fee for each object that you
* invalidate. For example, to invalidate a directory and all of the files in
* the directory, you must invalidate the directory and each file individually.
* If you need to invalidate a lot of files, it might be easier and less
* expensive to create a new distribution and change your object paths to refer
* to the new distribution. For more information about the charges for
* invalidation, see Paying for Object Invalidation.
*
* @uses CloudFrontClient for stablish connection with CloudFront service
* @link http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Invalidation.htmlInvalidating Objects (Web Distributions Only)
* @author Javier Spagnoletti <phansys@gmail.com>
*/
class CloudFront implements CDNInterface
{
/**
* @var string
*/
protected $path;
/**
* @var string
*/
protected $key;
/**
* @var string
*/
protected $secret;
/**
* @var string
*/
protected $distributionId;
/**
* @var CloudFrontClient
*/
protected $client;

/**
* @param string $path
* @param string $key
* @param string $secret
* @param string $distributionId
*/
public function __construct($path, $key, $secret, $distributionId)
{
$this->path = $path;
$this->key = $key;
$this->secret = $secret;
$this->distributionId = $distributionId;
}

/**
* {@inheritdoc}
*/
public function getPath($relativePath, $isFlushable = false)
{
return sprintf('%s/%s', rtrim($this->path, '/'), ltrim($relativePath, '/'));
}

/**
* {@inheritdoc}
*/
public function flushByString($string)
{
return $this->flushPaths(array($string));
}

/**
* {@inheritdoc}
*/
public function flush($string)
{
return $this->flushPaths(array($string));
}

/**
* {@inheritdoc}
*
* @link http://docs.aws.amazon.com/aws-sdk-php/latest/class-Aws.CloudFront.CloudFrontClient.html#_createInvalidation
*/
public function flushPaths(array $paths)
{
if (empty($paths)) {
throw new \RuntimeException('Unable to flush : expected at least one path');
}
// Normalizes paths due possible typos since all the CloudFront's
// objects starts with a leading slash
$normalizedPaths = array_map(function($path) {
return '/' . ltrim($path, '/');
}, $paths);

try {
$result = $this->getClient()->createInvalidation(array(
'DistributionId' => $this->distributionId,
'Paths' => array(
'Quantity' => count($normalizedPaths),
'Items' => $normalizedPaths
),
'CallerReference' => $this->getCallerReference($normalizedPaths),
));

if (!in_array($status = $result->get('Status'), array('Completed', 'InProgress'))) {
throw new \RuntimeException('Unable to flush : ' . $status);
}

return $result->get('Id');
} catch (CloudFrontException $ex) {
throw new \RuntimeException('Unable to flush : ' . $ex->getMessage());
}
}

/**
* Return a CloudFrontClient
*
* @return CloudFrontClient
*/
private function getClient()
{
if (!$this->client) {
$this->client = CloudFrontClient::factory(array(
'key' => $this->key,
'secret' => $this->secret
));
}

return $this->client;
}

/**
* For testing only
*
* @param $client
*
* @return void
*/
public function setClient($client)
{
$this->client = $client;
}

/**
* Generates a valid caller reference from given paths regardless its order
*
* @param array $paths
* @return string a md5 representation
*/
protected function getCallerReference(array $paths)
{
sort($paths);

return md5(implode(',', $paths));
}

/**
* {@inheritdoc}
*
* @throws \RuntimeException
*/
public function getFlushStatus($identifier)
{
try {
$result = $this->getClient()->getInvalidation(array(
'DistributionId' => $this->distributionId,
'Id' => $identifier
));

return array_search($result->get('Status'), self::getStatusList());
} catch (CloudFrontException $ex) {
throw new \RuntimeException('Unable to retrieve flush status : ' . $ex->getMessage());
}
}

/**
* @static
* @return array
*/
public static function getStatusList()
{
// @todo: check for a complete list of available CloudFront statuses
return array(
self::STATUS_OK => 'Completed',
self::STATUS_TO_SEND => 'STATUS_TO_SEND',
self::STATUS_TO_FLUSH => 'STATUS_TO_FLUSH',
self::STATUS_ERROR => 'STATUS_ERROR',
self::STATUS_WAITING => 'InProgress',
);
}
}
14 changes: 11 additions & 3 deletions CDN/Fallback.php
Expand Up @@ -44,22 +44,30 @@ public function getPath($relativePath, $isFlushable)
*/
public function flushByString($string)
{
$this->cdn->flushByString($string);
return $this->cdn->flushByString($string);
}

/**
* {@inheritdoc}
*/
public function flush($string)
{
$this->cdn->flush($string);
return $this->cdn->flush($string);
}

/**
* {@inheritdoc}
*/
public function flushPaths(array $paths)
{
$this->cdn->flushPaths($paths);
return $this->cdn->flushPaths($paths);
}

/**
* {@inheritdoc}
*/
public function getFlushStatus($identifier)
{
return $this->cdn->getFlushStatus($identifier);
}
}
8 changes: 8 additions & 0 deletions CDN/PantherPortal.php
Expand Up @@ -119,4 +119,12 @@ public function setClient($client)
{
$this->client = $client;
}

/**
* {@inheritdoc}
*/
public function getFlushStatus($identifier)
{
// nothing to do
}
}
8 changes: 8 additions & 0 deletions CDN/Server.php
Expand Up @@ -54,4 +54,12 @@ public function flushPaths(array $paths)
{
// nothing to do
}

/**
* {@inheritdoc}
*/
public function getFlushStatus($identifier)
{
// nothing to do
}
}

0 comments on commit f1bc740

Please sign in to comment.