Skip to content

Commit

Permalink
Merge pull request fbrnc#16 from AOEpeople/feature/purge_via_sns
Browse files Browse the repository at this point in the history
Feature/purge via sns
  • Loading branch information
fbrnc authored Jul 19, 2016
2 parents 891111e + f17dabe commit a323f42
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 84 deletions.
61 changes: 61 additions & 0 deletions app/code/community/Aoe/Static/Model/Cache/Adapter/Sns.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

/**
* Class Aoe_Static_Model_Cache_Adapter_Sns
*/
class Aoe_Static_Model_Cache_Adapter_Sns extends Aoe_Static_Model_Cache_Adapter_Varnish
{

/**
* @var string
*/
protected $snsTopic;

/**
* @var \Aws\Sns\SnsClient
*/
protected $snsClient;


public function getSnsTopic()
{
if (is_null($this->snsTopic)) {
$this->snsTopic = Mage::getStoreConfig('dev/aoestatic/snsTopic');
if (empty($this->snsTopic)) {
throw new Exception('Invalid SNS topic');
}
}
return $this->snsTopic;
}

public function getSnsClient()
{
if (is_null($this->snsClient)) {

$file = Mage::getBaseDir('lib') . DS . 'AwsSdk' . DS . 'autoload.php';
if (!is_file($file)) {
throw new Exception('Please install Mage_AwsSdk');
}
require_once $file;

// use EC2 instance profile of ENV vars to configure the client
$this->snsClient = new \Aws\Sns\SnsClient([
'version' => '2010-03-31',
'region' => Mage::getStoreConfig('dev/aoestatic/snsRegion')
]);
}
return $this->snsClient;
}

protected function sendRequests(array $actions)
{
Mage::log('[Aoe_Static SNS] Public SNS message');
$this->getSnsClient()->publish([
'Message' => json_encode($actions),
'Subject' => 'Aoe_Static',
'TopicArn' => $this->getSnsTopic(),
]);
return array();
}

}
142 changes: 62 additions & 80 deletions app/code/community/Aoe/Static/Model/Cache/Adapter/Varnish.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,27 @@
*/
class Aoe_Static_Model_Cache_Adapter_Varnish implements Aoe_Static_Model_Cache_Adapter_Interface
{
/** @var array */
protected $_varnishServers = array();
/**
* @var array
*/
protected $varnishServers;

/**
* Constructor
*/
public function __construct()
protected function getVarnishServers()
{
$serverConfig = Mage::getStoreConfig('dev/aoestatic/servers');
if (strpos($serverConfig, ',') !== false) {
// old format - comma-separated list of servers
$this->_varnishServers = Mage::helper('aoestatic')->trimExplode(",", $serverConfig, true);
} else {
// new format - newline-separated list of servers
$this->_varnishServers = Mage::helper('aoestatic')->trimExplode("\n", $serverConfig, true);
if (is_null($this->varnishServers)) {
$serverConfig = Mage::getStoreConfig('dev/aoestatic/servers');
if (strpos($serverConfig, ',') !== false) {
// old format - comma-separated list of servers
$this->varnishServers = Mage::helper('aoestatic')->trimExplode(",", $serverConfig, true);
} else {
// new format - newline-separated list of servers
$this->varnishServers = Mage::helper('aoestatic')->trimExplode("\n", $serverConfig, true);
}
}
return $this->varnishServers;
}

/**
Expand All @@ -41,79 +46,37 @@ public function purgeAll()
*/
public function purge(array $urls)
{
$errors = array();
$actions = [];

// Separate regex ('R:...') from plain urls
$regexPatterns = array();
foreach($urls as $k => $url) {
foreach ($urls as $k => $url) {
if(strpos($url, 'R:') === 0) {
unset($urls[$k]);
$regexPatterns[] = substr($url, 2);
} else {
$actions[] = [
'method' => 'PURGE',
'path' => $url,
'headers' => []
];
}
}
$regexPatterns = (empty($regexPatterns) ? '' : '((' . implode(')|(', $regexPatterns) . '))');

// Init curl handler
$curlHandlers = array(); // keep references for clean up
$multiHandler = curl_multi_init();

foreach ($this->_varnishServers as $varnishServer) {
foreach ($urls as $url) {
$varnishUrl = "http://" . $varnishServer . '/' . $url;

$curlHandler = curl_init();
curl_setopt($curlHandler, CURLOPT_URL, $varnishUrl);
curl_setopt($curlHandler, CURLOPT_CUSTOMREQUEST, 'PURGE');
curl_setopt($curlHandler, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curlHandler, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curlHandler, CURLOPT_SSL_VERIFYHOST, 0);

curl_multi_add_handle($multiHandler, $curlHandler);
$curlHandlers[] = $curlHandler;
}

if(!empty($regexPatterns)) {
$curlHandler = curl_init();
curl_setopt($curlHandler, CURLOPT_URL, "http://" . $varnishServer);
curl_setopt($curlHandler, CURLOPT_CUSTOMREQUEST, 'BAN');
curl_setopt($curlHandler, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curlHandler, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curlHandler, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($curlHandler, CURLOPT_HTTPHEADER, array('X-Url: ' . $regexPatterns));

curl_multi_add_handle($multiHandler, $curlHandler);
$curlHandlers[] = $curlHandler;
}
}

do {
curl_multi_exec($multiHandler, $active);
} while ($active);

// Error handling and clean up
foreach ($curlHandlers as $curlHandler) {
$info = curl_getinfo($curlHandler);

if (curl_errno($curlHandler)) {
$errors[] = "Cannot purge url {$info['url']} due to error" . curl_error($curlHandler);
} else if ($info['http_code'] != 200 && $info['http_code'] != 404) {
$errors[] = "Cannot purge url {$info['url']}, http code: {$info['http_code']}. curl error: " . curl_error($curlHandler);
}

curl_multi_remove_handle($multiHandler, $curlHandler);
curl_close($curlHandler);
if (!empty($regexPatterns)) {
$regexPatterns = '((' . implode(')|(', $regexPatterns) . '))';
$actions[] = [
'method' => 'BAN',
'path' => '/',
'headers' => ['X-Url' => $regexPatterns]
];
}
curl_multi_close($multiHandler);

return $errors;
return $this->sendRequests($actions);
}

public function purgeTags(array $tags)
{
$errors = array();
// Init curl handler
$curlHandlers = array(); // keep references for clean up
$multiHandler = curl_multi_init();

// Tag delimiter
$td = str_replace(' ', '\x20', preg_quote(Aoe_Static_Model_Cache_Control::TAG_DELIMITER));

Expand All @@ -131,25 +94,44 @@ public function purgeTags(array $tags)

$regex = "(?U)(^|{$td})((" . implode(')|(', $tags) . "))($|{$td})";

foreach ($this->_varnishServers as $varnishServer) {
$varnishUrl = "http://" . $varnishServer;
return $this->sendRequests([[
'method' => 'BAN',
'path' => '/',
'headers' => ['X-Tags' => $regex]
]]);
}

$curlHandler = curl_init();
curl_setopt($curlHandler, CURLOPT_URL, $varnishUrl);
curl_setopt($curlHandler, CURLOPT_CUSTOMREQUEST, 'BAN');
curl_setopt($curlHandler, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curlHandler, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curlHandler, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($curlHandler, CURLOPT_HTTPHEADER, array('X-Tags: ' . $regex));
protected function sendRequests(array $actions)
{
// Init curl handler
$curlHandlers = array(); // keep references for clean up
$multiHandler = curl_multi_init();

curl_multi_add_handle($multiHandler, $curlHandler);
$curlHandlers[] = $curlHandler;
foreach ($actions as $action) {
foreach ($this->getVarnishServers() as $varnishServer) {
$curlHandler = curl_init();
curl_setopt($curlHandler, CURLOPT_URL, $varnishServer . '/' . $action['path']);
curl_setopt($curlHandler, CURLOPT_CUSTOMREQUEST, $action['method']);
curl_setopt($curlHandler, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curlHandler, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curlHandler, CURLOPT_SSL_VERIFYHOST, 0);
if (count($action['headers'])) {
$headers = [];
foreach ($action['headers'] as $key => $value) {
$headers[] = "$key: $value";
}
curl_setopt($curlHandler, CURLOPT_HTTPHEADER, $headers);
}
curl_multi_add_handle($multiHandler, $curlHandler);
$curlHandlers[] = $curlHandler;
}
}

do {
curl_multi_exec($multiHandler, $active);
} while ($active);

$errors = array();
// Error handling and clean up
foreach ($curlHandlers as $curlHandler) {
$info = curl_getinfo($curlHandler);
Expand Down
10 changes: 6 additions & 4 deletions app/code/community/Aoe/Static/etc/aoe_static.xml
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,16 @@
<adapters><!-- Register additional adapters here -->
<varnish>
<model>aoestatic/cache_adapter_varnish</model>
<config>
</config>
<config></config>
</varnish>
<blackhole>
<model>aoestatic/cache_adapter_blackhole</model>
<config>
</config>
<config></config>
</blackhole>
<sns>
<model>aoestatic/cache_adapter_sns</model>
<config></config>
</sns>
</adapters>
</aoe_static_purging>

Expand Down
16 changes: 16 additions & 0 deletions app/code/community/Aoe/Static/etc/system.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@
<show_in_website>0</show_in_website>
<show_in_store>0</show_in_store>
</use_aoe_asynccache>
<snsTopic>
<label>SNS Topic (for SNS purge adapter only)</label>
<frontend_type>text</frontend_type>
<sort_order>130</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>0</show_in_website>
<show_in_store>0</show_in_store>
</snsTopic>
<snsRegion>
<label>SNS Region</label>
<frontend_type>text</frontend_type>
<sort_order>140</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>0</show_in_website>
<show_in_store>0</show_in_store>
</snsRegion>
<debug translate="label">
<label>Debug</label>
<comment><![CDATA[Add debug data to responses]]></comment>
Expand Down
1 change: 1 addition & 0 deletions modman
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ app/design/frontend/base/default/layout/aoestatic/ app/design/frontend/base/defa
app/design/frontend/base/default/template/aoestatic/ app/design/frontend/base/default/template/aoestatic/
app/etc/modules/Aoe_Static.xml app/etc/modules/Aoe_Static.xml
js/aoestatic/ js/aoestatic/
shell/aoe_static.php shell/aoe_static.php
59 changes: 59 additions & 0 deletions shell/aoe_static.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

require_once 'abstract.php';

class Aoe_Static_Shell extends Mage_Shell_Abstract
{

public function purgeAllAction()
{
$errors = Mage::helper('aoestatic')->purgeAll();
var_dump($errors);
}

/**
* Run script
*/
public function run()
{
$action = $this->getArg('action');
if (empty($action)) {
echo $this->usageHelp();
} else {
$actionMethodName = $action . 'Action';
if (method_exists($this, $actionMethodName)) {
$this->$actionMethodName();
} else {
echo "Action $action not found!\n";
echo $this->usageHelp();
exit(1);
}
}
}

/**
* Retrieve Usage Help Message
*
* @return string
*/
public function usageHelp()
{
$help = 'Available actions: ' . "\n";
$methods = get_class_methods($this);
foreach ($methods as $method) {
if (substr($method, -6) == 'Action') {
$help .= ' -action ' . substr($method, 0, -6);
$helpMethod = $method . 'Help';
if (method_exists($this, $helpMethod)) {
$help .= $this->$helpMethod();
}
$help .= "\n";
}
}
return $help;
}

}

$shell = new Aoe_Static_Shell();
$shell->run();

0 comments on commit a323f42

Please sign in to comment.