Added CDN support.
This commit is contained in:
@@ -49,6 +49,7 @@ namespace HPCloud\Storage\ObjectStorage;
|
||||
* container.
|
||||
*
|
||||
* @todo Add support for container metadata.
|
||||
* @todo Add CDN support fo container listings.
|
||||
*/
|
||||
class Container implements \Countable, \IteratorAggregate {
|
||||
/**
|
||||
@@ -61,8 +62,10 @@ class Container implements \Countable, \IteratorAggregate {
|
||||
//protected $properties = array();
|
||||
protected $name = NULL;
|
||||
|
||||
protected $count = 0;
|
||||
protected $bytes = 0;
|
||||
// These were both changed from 0 to NULL to allow
|
||||
// lazy loading.
|
||||
protected $count = NULL;
|
||||
protected $bytes = NULL;
|
||||
|
||||
protected $token;
|
||||
protected $url;
|
||||
@@ -70,6 +73,9 @@ class Container implements \Countable, \IteratorAggregate {
|
||||
protected $acl;
|
||||
protected $metadata;
|
||||
|
||||
// This is only set if CDN service is activated.
|
||||
protected $cdnUrl;
|
||||
|
||||
/**
|
||||
* Transform a metadata array into headers.
|
||||
*
|
||||
@@ -251,7 +257,8 @@ class Container implements \Countable, \IteratorAggregate {
|
||||
* @attention
|
||||
* Typically a container should be created by ObjectStorage::createContainer().
|
||||
* Get existing containers with ObjectStorage::container() or
|
||||
* ObjectStorage::containers(). Do not use this unless you know what you are doing.
|
||||
* ObjectStorage::containers(). Using the constructor directly has some
|
||||
* side effects of which you should be aware.
|
||||
*
|
||||
* Simply creating a container does not save the container remotely.
|
||||
*
|
||||
@@ -259,6 +266,28 @@ class Container implements \Countable, \IteratorAggregate {
|
||||
* constructing a Container in no way guarantees that such a container exists
|
||||
* on the origin object store.
|
||||
*
|
||||
* The constructor involves a selective lazy loading. If a new container is created,
|
||||
* and one of its accessors is called before the accessed values are initialized, then
|
||||
* this will make a network round-trip to get the container from the remote server.
|
||||
*
|
||||
* Containers loaded from ObjectStorage::container() or Container::newFromRemote()
|
||||
* will have all of the necessary values set, and thus will not require an extra network
|
||||
* transaction to fetch properties.
|
||||
*
|
||||
* The practical result of this:
|
||||
*
|
||||
* - If you are creating a new container, it is best to do so with
|
||||
* ObjectStorage::createContainer().
|
||||
* - If you are manipulating an existing container, it is best to load the
|
||||
* container with ObjectStorage::container().
|
||||
* - If you are simply using the container to fetch resources from the
|
||||
* container, you may wish to use `new Container($name, $url, $token)`
|
||||
* and then load objects from that container. Note, however, that
|
||||
* manipulating the container directly will likely involve an extra HTTP
|
||||
* transaction to load the container data.
|
||||
* - When in doubt, use the ObjectStorage methods. That is always the safer
|
||||
* option.
|
||||
*
|
||||
* @param string $name
|
||||
* The name.
|
||||
* @param string $url
|
||||
@@ -273,6 +302,24 @@ class Container implements \Countable, \IteratorAggregate {
|
||||
$this->token = $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL of the CDN to use.
|
||||
*
|
||||
* If this is set, the Container will attempt to fetch objects
|
||||
* from the CDN instead of the Swift storage whenever possible.
|
||||
*
|
||||
* If ObjectStorage::useCDN() is already called, this is not necessary.
|
||||
*
|
||||
* Setting this to NULL will have the effect of turning off CDN for this
|
||||
* container.
|
||||
*
|
||||
* @param string $url
|
||||
* The URL to the CDN for this container.
|
||||
*/
|
||||
public function useCDN($url) {
|
||||
$this->cdnUrl = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this container.
|
||||
*
|
||||
@@ -290,6 +337,9 @@ class Container implements \Countable, \IteratorAggregate {
|
||||
* The number of bytes in this container.
|
||||
*/
|
||||
public function bytes() {
|
||||
if (is_null($this->bytes)) {
|
||||
$this->loadExtraData();
|
||||
}
|
||||
return $this->bytes;
|
||||
}
|
||||
|
||||
@@ -359,6 +409,9 @@ class Container implements \Countable, \IteratorAggregate {
|
||||
* The number of items in this container.
|
||||
*/
|
||||
public function count() {
|
||||
if (is_null($this->count)) {
|
||||
$this->loadExtraData();
|
||||
}
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
@@ -602,6 +655,10 @@ class Container implements \Countable, \IteratorAggregate {
|
||||
* - If-Modified-Since/If-Unmodified-Since
|
||||
* - If-Match/If-None-Match
|
||||
*
|
||||
* If a CDN has been specified either using useCDN() or
|
||||
* ObjectStorage::useCDN(), this will attempt to fetch the object
|
||||
* from the CDN.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the object to load.
|
||||
* @retval \HPCloud\Storage\ObjectStorage\RemoteObject
|
||||
@@ -610,13 +667,20 @@ class Container implements \Countable, \IteratorAggregate {
|
||||
public function object($name) {
|
||||
|
||||
$url = self::objectUrl($this->url, $name);
|
||||
$cdn = self::objectUrl($this->cdnUrl, $name);
|
||||
$headers = array();
|
||||
|
||||
// Auth token.
|
||||
$headers['X-Auth-Token'] = $this->token;
|
||||
|
||||
$client = \HPCloud\Transport::instance();
|
||||
$response = $client->doRequest($url, 'GET', $headers);
|
||||
|
||||
if (empty($this->cdnUrl)) {
|
||||
$response = $client->doRequest($url, 'GET', $headers);
|
||||
}
|
||||
else {
|
||||
$response = $client->doRequest($cdn, 'GET', $headers);
|
||||
}
|
||||
|
||||
if ($response->status() != 200) {
|
||||
throw new \HPCloud\Exception('An unknown error occurred while saving: ' . $response->status());
|
||||
@@ -625,6 +689,10 @@ class Container implements \Countable, \IteratorAggregate {
|
||||
$remoteObject = RemoteObject::newFromHeaders($name, $response->headers(), $this->token, $url);
|
||||
$remoteObject->setContent($response->content());
|
||||
|
||||
if (!empty($this->cdnUrl)) {
|
||||
$remoteObject->useCDN($cdn);
|
||||
}
|
||||
|
||||
return $remoteObject;
|
||||
}
|
||||
|
||||
@@ -659,13 +727,20 @@ class Container implements \Countable, \IteratorAggregate {
|
||||
*/
|
||||
public function remoteObject($name) {
|
||||
$url = self::objectUrl($this->url, $name);
|
||||
$cdn = self::objectUrl($this->cdnUrl, $name);
|
||||
$headers = array(
|
||||
'X-Auth-Token' => $this->token,
|
||||
);
|
||||
|
||||
|
||||
$client = \HPCloud\Transport::instance();
|
||||
$response = $client->doRequest($url, 'HEAD', $headers);
|
||||
|
||||
if (empty($this->cdnUrl)) {
|
||||
$response = $client->doRequest($url, 'HEAD', $headers);
|
||||
}
|
||||
else {
|
||||
$response = $client->doRequest($cdn, 'HEAD', $headers);
|
||||
}
|
||||
|
||||
if ($response->status() != 200) {
|
||||
throw new \HPCloud\Exception('An unknown error occurred while saving: ' . $response->status());
|
||||
@@ -673,7 +748,13 @@ class Container implements \Countable, \IteratorAggregate {
|
||||
|
||||
$headers = $response->headers();
|
||||
|
||||
return RemoteObject::newFromHeaders($name, $headers, $this->token, $url);
|
||||
$obj = RemoteObject::newFromHeaders($name, $headers, $this->token, $url);
|
||||
|
||||
if (!empty($this->cdnUrl)) {
|
||||
$obj->useCDN($cdn);
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -836,6 +917,10 @@ class Container implements \Countable, \IteratorAggregate {
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
public function cdnUrl() {
|
||||
return $this->cdnUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ACL.
|
||||
*
|
||||
@@ -867,19 +952,31 @@ class Container implements \Countable, \IteratorAggregate {
|
||||
* called to "fill in" missing fields.
|
||||
*/
|
||||
protected function loadExtraData() {
|
||||
// Do a GET on $url to fetch headers.
|
||||
$client = \HPCloud\Transport::instance();
|
||||
$headers = array(
|
||||
'X-Auth-Token' => $this->token,
|
||||
);
|
||||
$response = $client->doRequest($this->url, 'GET', $headers);
|
||||
|
||||
// Get ACL.
|
||||
$this->acl = ACL::newFromHeaders($response->headers());
|
||||
// If URL and token are empty, we are dealing with
|
||||
// a local item that has not been saved, and was not
|
||||
// created with Container::createContainer(). We treat
|
||||
// this as an error condition.
|
||||
if (empty($this->url) || empty($this->token)) {
|
||||
throw new \HPCloud\Exception('Remote data cannot be fetched. Tokena and endpoint URL are required.');
|
||||
}
|
||||
// Do a GET on $url to fetch headers.
|
||||
$client = \HPCloud\Transport::instance();
|
||||
$headers = array(
|
||||
'X-Auth-Token' => $this->token,
|
||||
);
|
||||
$response = $client->doRequest($this->url, 'GET', $headers);
|
||||
|
||||
// Get metadata.
|
||||
$prefix = Container::CONTAINER_METADATA_HEADER_PREFIX;
|
||||
$this->setMetadata(Container::extractHeaderAttributes($response->headers(), $prefix));
|
||||
// Get ACL.
|
||||
$this->acl = ACL::newFromHeaders($response->headers());
|
||||
|
||||
// Update size and count.
|
||||
$this->bytes = $response->header('X-Container-Bytes-Used', 0);
|
||||
$this->count = $response->header('X-Container-Object-Count', 0);
|
||||
|
||||
// Get metadata.
|
||||
$prefix = Container::CONTAINER_METADATA_HEADER_PREFIX;
|
||||
$this->setMetadata(Container::extractHeaderAttributes($response->headers(), $prefix));
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user