Added CDN support.
This commit is contained in:
@@ -49,6 +49,7 @@ namespace HPCloud\Storage\ObjectStorage;
|
|||||||
* container.
|
* container.
|
||||||
*
|
*
|
||||||
* @todo Add support for container metadata.
|
* @todo Add support for container metadata.
|
||||||
|
* @todo Add CDN support fo container listings.
|
||||||
*/
|
*/
|
||||||
class Container implements \Countable, \IteratorAggregate {
|
class Container implements \Countable, \IteratorAggregate {
|
||||||
/**
|
/**
|
||||||
@@ -61,8 +62,10 @@ class Container implements \Countable, \IteratorAggregate {
|
|||||||
//protected $properties = array();
|
//protected $properties = array();
|
||||||
protected $name = NULL;
|
protected $name = NULL;
|
||||||
|
|
||||||
protected $count = 0;
|
// These were both changed from 0 to NULL to allow
|
||||||
protected $bytes = 0;
|
// lazy loading.
|
||||||
|
protected $count = NULL;
|
||||||
|
protected $bytes = NULL;
|
||||||
|
|
||||||
protected $token;
|
protected $token;
|
||||||
protected $url;
|
protected $url;
|
||||||
@@ -70,6 +73,9 @@ class Container implements \Countable, \IteratorAggregate {
|
|||||||
protected $acl;
|
protected $acl;
|
||||||
protected $metadata;
|
protected $metadata;
|
||||||
|
|
||||||
|
// This is only set if CDN service is activated.
|
||||||
|
protected $cdnUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform a metadata array into headers.
|
* Transform a metadata array into headers.
|
||||||
*
|
*
|
||||||
@@ -251,7 +257,8 @@ class Container implements \Countable, \IteratorAggregate {
|
|||||||
* @attention
|
* @attention
|
||||||
* Typically a container should be created by ObjectStorage::createContainer().
|
* Typically a container should be created by ObjectStorage::createContainer().
|
||||||
* Get existing containers with ObjectStorage::container() or
|
* 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.
|
* 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
|
* constructing a Container in no way guarantees that such a container exists
|
||||||
* on the origin object store.
|
* 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
|
* @param string $name
|
||||||
* The name.
|
* The name.
|
||||||
* @param string $url
|
* @param string $url
|
||||||
@@ -273,6 +302,24 @@ class Container implements \Countable, \IteratorAggregate {
|
|||||||
$this->token = $token;
|
$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.
|
* Get the name of this container.
|
||||||
*
|
*
|
||||||
@@ -290,13 +337,16 @@ class Container implements \Countable, \IteratorAggregate {
|
|||||||
* The number of bytes in this container.
|
* The number of bytes in this container.
|
||||||
*/
|
*/
|
||||||
public function bytes() {
|
public function bytes() {
|
||||||
|
if (is_null($this->bytes)) {
|
||||||
|
$this->loadExtraData();
|
||||||
|
}
|
||||||
return $this->bytes;
|
return $this->bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the container metadata.
|
* Get the container metadata.
|
||||||
*
|
*
|
||||||
* Metadata (also called tags) are name/value pairs that can be
|
* Metadata (also called tags) are name/value pairs that can be
|
||||||
* attached to a container.
|
* attached to a container.
|
||||||
*
|
*
|
||||||
* Names can be no longer than 128 characters, and values can be no
|
* Names can be no longer than 128 characters, and values can be no
|
||||||
@@ -359,6 +409,9 @@ class Container implements \Countable, \IteratorAggregate {
|
|||||||
* The number of items in this container.
|
* The number of items in this container.
|
||||||
*/
|
*/
|
||||||
public function count() {
|
public function count() {
|
||||||
|
if (is_null($this->count)) {
|
||||||
|
$this->loadExtraData();
|
||||||
|
}
|
||||||
return $this->count;
|
return $this->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -602,6 +655,10 @@ class Container implements \Countable, \IteratorAggregate {
|
|||||||
* - If-Modified-Since/If-Unmodified-Since
|
* - If-Modified-Since/If-Unmodified-Since
|
||||||
* - If-Match/If-None-Match
|
* - 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
|
* @param string $name
|
||||||
* The name of the object to load.
|
* The name of the object to load.
|
||||||
* @retval \HPCloud\Storage\ObjectStorage\RemoteObject
|
* @retval \HPCloud\Storage\ObjectStorage\RemoteObject
|
||||||
@@ -610,13 +667,20 @@ class Container implements \Countable, \IteratorAggregate {
|
|||||||
public function object($name) {
|
public function object($name) {
|
||||||
|
|
||||||
$url = self::objectUrl($this->url, $name);
|
$url = self::objectUrl($this->url, $name);
|
||||||
|
$cdn = self::objectUrl($this->cdnUrl, $name);
|
||||||
$headers = array();
|
$headers = array();
|
||||||
|
|
||||||
// Auth token.
|
// Auth token.
|
||||||
$headers['X-Auth-Token'] = $this->token;
|
$headers['X-Auth-Token'] = $this->token;
|
||||||
|
|
||||||
$client = \HPCloud\Transport::instance();
|
$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) {
|
if ($response->status() != 200) {
|
||||||
throw new \HPCloud\Exception('An unknown error occurred while saving: ' . $response->status());
|
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 = RemoteObject::newFromHeaders($name, $response->headers(), $this->token, $url);
|
||||||
$remoteObject->setContent($response->content());
|
$remoteObject->setContent($response->content());
|
||||||
|
|
||||||
|
if (!empty($this->cdnUrl)) {
|
||||||
|
$remoteObject->useCDN($cdn);
|
||||||
|
}
|
||||||
|
|
||||||
return $remoteObject;
|
return $remoteObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -659,13 +727,20 @@ class Container implements \Countable, \IteratorAggregate {
|
|||||||
*/
|
*/
|
||||||
public function remoteObject($name) {
|
public function remoteObject($name) {
|
||||||
$url = self::objectUrl($this->url, $name);
|
$url = self::objectUrl($this->url, $name);
|
||||||
|
$cdn = self::objectUrl($this->cdnUrl, $name);
|
||||||
$headers = array(
|
$headers = array(
|
||||||
'X-Auth-Token' => $this->token,
|
'X-Auth-Token' => $this->token,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
$client = \HPCloud\Transport::instance();
|
$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) {
|
if ($response->status() != 200) {
|
||||||
throw new \HPCloud\Exception('An unknown error occurred while saving: ' . $response->status());
|
throw new \HPCloud\Exception('An unknown error occurred while saving: ' . $response->status());
|
||||||
@@ -673,7 +748,13 @@ class Container implements \Countable, \IteratorAggregate {
|
|||||||
|
|
||||||
$headers = $response->headers();
|
$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;
|
return $this->url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function cdnUrl() {
|
||||||
|
return $this->cdnUrl;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the ACL.
|
* Get the ACL.
|
||||||
*
|
*
|
||||||
@@ -867,19 +952,31 @@ class Container implements \Countable, \IteratorAggregate {
|
|||||||
* called to "fill in" missing fields.
|
* called to "fill in" missing fields.
|
||||||
*/
|
*/
|
||||||
protected function loadExtraData() {
|
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.
|
// If URL and token are empty, we are dealing with
|
||||||
$this->acl = ACL::newFromHeaders($response->headers());
|
// 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.
|
// Get ACL.
|
||||||
$prefix = Container::CONTAINER_METADATA_HEADER_PREFIX;
|
$this->acl = ACL::newFromHeaders($response->headers());
|
||||||
$this->setMetadata(Container::extractHeaderAttributes($response->headers(), $prefix));
|
|
||||||
|
// 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