-
Notifications
You must be signed in to change notification settings - Fork 21
Adds support for Akamai purging #51
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
<?php | ||
|
||
namespace ostark\upper\drivers; | ||
|
||
use GuzzleHttp\Exception\BadResponseException; | ||
use ostark\upper\exceptions\AkamaiApiException; | ||
|
||
/** | ||
* Class Akamai Driver | ||
* | ||
* @package ostark\upper\drivers | ||
* | ||
*/ | ||
class Akamai extends AbstractPurger implements CachePurgeInterface | ||
{ | ||
/** | ||
* @var string | ||
*/ | ||
public $host; | ||
|
||
/** | ||
* @var string | ||
*/ | ||
public $clientToken; | ||
|
||
/** | ||
* @var string | ||
*/ | ||
public $clientSecret; | ||
|
||
/** | ||
* @var string | ||
*/ | ||
public $accessToken; | ||
|
||
/** | ||
* @var string | ||
*/ | ||
public $maxSize; | ||
|
||
/** | ||
* Purge cache by tag | ||
* | ||
* @param string $tag | ||
* | ||
* @return bool | ||
*/ | ||
public function purgeTag(string $tag) | ||
{ | ||
if ($this->useLocalTags) { | ||
return $this->purgeUrlsByTag($tag); | ||
} | ||
|
||
$this->sendRequest('production', 'POST', 'tag', $tag); | ||
$this->sendRequest('staging', 'POST', 'tag', $tag); | ||
ostark marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Purge cache by urls | ||
* | ||
* @param array $urls | ||
* | ||
* @return bool | ||
*/ | ||
public function purgeUrls(array $urls) | ||
{ | ||
foreach ($urls as $url) { | ||
if (!$this->sendRequest('production', 'POST', 'url', getenv('DEFAULT_SITE_URL') . $url)) { | ||
return false; | ||
} | ||
if (!$this->sendRequest('staging', 'POST', 'url', getenv('DEFAULT_SITE_URL') . $url)) { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
|
||
/** | ||
* Purge entire cache | ||
* | ||
* @return bool | ||
*/ | ||
public function purgeAll() | ||
{ | ||
// TODO: Purge all in Akamai | ||
return true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is there no endpoint? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately, no. Only by tag, cp code or url. CP Code could work as a purge all, but only if you set it up specifically. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had a quick look at the docs. cp code should work. |
||
// return $this->sendRequest('POST', 'purge_all'); | ||
} | ||
|
||
/** | ||
* Send API call | ||
* | ||
* @param string $method HTTP verb | ||
* @param string $type of purge | ||
* @param string $uri | ||
* @param array $headers | ||
* | ||
* @return bool | ||
* @throws \ostark\upper\exceptions\AkamaiApiException | ||
*/ | ||
protected function sendRequest(string $environment = 'production', string $method = 'POST', string $type = "url", string $uri = "", array $headers = []) | ||
{ | ||
// Akamai Open Edgegrid reads $_ENV which doesn't get populated by Craft, so filling in the blanks | ||
$_ENV['AKAMAI_HOST'] = getenv('AKAMAI_HOST'); | ||
$_ENV['AKAMAI_CLIENT_TOKEN'] = getenv('AKAMAI_CLIENT_TOKEN'); | ||
$_ENV['AKAMAI_CLIENT_SECRET'] = getenv('AKAMAI_CLIENT_SECRET'); | ||
$_ENV['AKAMAI_ACCESS_TOKEN'] = getenv('AKAMAI_ACCESS_TOKEN'); | ||
$_ENV['AKAMAI_MAX_SIZE'] = getenv('AKAMAI_MAX_SIZE'); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These values should be coming from config, not |
||
$auth = \Akamai\Open\EdgeGrid\Authentication::createFromEnv(); | ||
|
||
$auth->setHttpMethod('POST'); | ||
$auth->setPath('/ccu/v3/invalidate/' . $type . '/' . $environment); | ||
|
||
$body = json_encode(array( | ||
'objects' => array($uri) | ||
)); | ||
|
||
$auth->setBody($body); | ||
|
||
$context = array( | ||
'http' => array( | ||
'header' => array( | ||
'Authorization: ' . $auth->createAuthHeader(), | ||
'Content-Type: application/json', | ||
'Content-Length: ' . strlen($body), | ||
), | ||
'method' => 'POST', | ||
'content' => $body | ||
) | ||
); | ||
|
||
$context = stream_context_create($context); | ||
|
||
try { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there is nothing wrong with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair enough, I'll change it ! 👍🏻 |
||
json_decode(file_get_contents('https://' . $auth->getHost() . $auth->getPath(), false, $context)); | ||
} catch (BadResponseException $e) { | ||
throw AkamaiApiException::create( | ||
$e->getRequest(), | ||
$e->getResponse() | ||
); | ||
} | ||
|
||
return true; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
<?php | ||
|
||
namespace ostark\upper\exceptions; | ||
|
||
use Psr\Http\Message\RequestInterface; | ||
use Psr\Http\Message\ResponseInterface; | ||
|
||
class AkamaiApiException extends \Exception | ||
{ | ||
public function __construct(string $message = "", int $code = 0, \Throwable $previous = null) | ||
{ | ||
parent::__construct("Akamai API error: $message", $code, $previous); | ||
} | ||
|
||
/** | ||
* @param \Psr\Http\Message\RequestInterface $request | ||
* @param \Psr\Http\Message\ResponseInterface|null $response | ||
* | ||
* @return static | ||
*/ | ||
public static function create(RequestInterface $request, ResponseInterface $response = null) | ||
{ | ||
$uri = $request->getUri(); | ||
|
||
if (is_null($response)) { | ||
return new static("Akamai no response error, uri: '$uri'"); | ||
} | ||
|
||
// Extract error message from body | ||
$status = $response->getStatusCode(); | ||
$json = json_decode($response->getBody()); | ||
if (json_last_error() !== JSON_ERROR_NONE) { | ||
return new static("Akamai API error ($status) on: '$uri'", $status); | ||
} | ||
|
||
// Error message | ||
if (isset($json->msg)) { | ||
return new static($json->msg . ", uri: '$uri'", $response->getStatusCode()); | ||
} | ||
|
||
// Unknown | ||
return new static("Unknown error, uri: '$uri'"); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any good reason for
ttr(1200)
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In our experience, with sites that have a lot of URLs the purge by url loop takes too long and times out with the default TTR. We actually purge by tag now to avoid this problem, so I guess the ttr might indeed be overkill in most cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Hyra Let's not hardcode this. Either make it a config option, or just remove it and users can control it with
EVENT_BEFORE_PUSH
.