-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #48 from quantcdn/feature/quant-tome
Add the quant tome module.
- Loading branch information
Showing
7 changed files
with
428 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
services: | ||
quant_tome.commands: | ||
class: \Drupal\quant_tome\Commands\QuantTomeCommands | ||
arguments: ['@quant_tome.deploy_batch'] | ||
tags: | ||
- { name: drush.command } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
name: 'Quant Tome' | ||
type: module | ||
description: 'Deploy Tome static output to Quant.' | ||
core: 8.x | ||
core_version_requirement: ^8 || ^9 | ||
package: Quant | ||
dependencies: | ||
- tome:tome_static | ||
- quant:quant_api |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
services: | ||
quant_tome.redirect_subscriber: | ||
class: Drupal\quant_tome\EventSubscriber\RedirectSubscriber | ||
arguments: ['@tome_static.generator', '@file_system'] | ||
tags: | ||
- { name: event_subscriber } | ||
quant_tome.deploy_batch: | ||
class: Drupal\quant_tome\QuantTomeBatch | ||
arguments: | ||
- '@tome_static.generator' | ||
- '@file_system' | ||
- '@quant_api.client' | ||
- '@queue' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
<?php | ||
|
||
namespace Drupal\quant_tome\Commands; | ||
|
||
use Drush\Commands\DrushCommands; | ||
use Drupal\quant\Commands\QuantDrushCommands; | ||
use Drupal\quant_tome\QuantTomeBatch; | ||
|
||
/** | ||
* Contains the quant:tome:deploy command. | ||
*/ | ||
class QuantTomeCommands extends DrushCommands { | ||
|
||
/** | ||
* The batch builder. | ||
* | ||
* @var \Drupal\quant_tome\QuantTomeBatch | ||
*/ | ||
protected $batch; | ||
|
||
/** | ||
* QuantTomeCommands constructor. | ||
* | ||
* @param \Drupal\quant_tome\QuantTomeBatch $batch | ||
* The batch service. | ||
*/ | ||
public function __construct(QuantTomeBatch $batch) { | ||
$this->batch = $batch; | ||
} | ||
|
||
/** | ||
* Deploy a Tome static build to Quant. | ||
* | ||
* @command quant:tome:deploy | ||
*/ | ||
public function deploy(array $options = ['threads' => 5]) { | ||
$this->io()->writeln('Preparing Tome output for Quant...'); | ||
|
||
if (!$this->batch->checkConfig()) { | ||
$this->io()->error('Cannot connect to the Quant API. Please check the Quant configuration.'); | ||
return 1; | ||
} | ||
if (!$this->batch->checkBuild()) { | ||
$this->io()->error('No Tome static build is available. Please run "drush tome:static".'); | ||
return 1; | ||
} | ||
|
||
$batch_builder = $this->batch->getBatch(); | ||
batch_set($batch_builder->toArray()); | ||
|
||
$result = drush_backend_batch_process(); | ||
|
||
if (!empty($result['object'][0]['errors'])) { | ||
$this->io()->error('Deploy failed. Please consult the error log for more information.'); | ||
return 1; | ||
} | ||
|
||
// Process the queue after the batch has collected it. | ||
$quant_drush = new QuantDrushCommands(); | ||
$quant_drush->message(['threads' => $options['threads']]); | ||
} | ||
|
||
} |
68 changes: 68 additions & 0 deletions
68
modules/quant_tome/src/EventSubscriber/RedirectSubscriber.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?php | ||
|
||
namespace Drupal\quant_tome\EventSubscriber; | ||
|
||
use Drupal\Core\File\FileSystemInterface; | ||
use Drupal\tome_static\StaticGeneratorInterface; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
use Symfony\Component\HttpFoundation\RedirectResponse; | ||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent; | ||
use Symfony\Component\HttpKernel\KernelEvents; | ||
|
||
/** | ||
* Writes to the _redirects file when redirects are generated. | ||
*/ | ||
class RedirectSubscriber implements EventSubscriberInterface { | ||
|
||
/** | ||
* The static generator. | ||
* | ||
* @var \Drupal\tome_static\StaticGeneratorInterface | ||
*/ | ||
protected $staticGenerator; | ||
|
||
/** | ||
* The file system. | ||
* | ||
* @var \Drupal\Core\File\FileSystemInterface | ||
*/ | ||
protected $fileSystem; | ||
|
||
/** | ||
* Constructs a RedirectSubscriber object. | ||
* | ||
* @param \Drupal\tome_static\StaticGeneratorInterface $static_generator | ||
* The static generator. | ||
* @param \Drupal\Core\File\FileSystemInterface $file_system | ||
* The file system. | ||
*/ | ||
public function __construct(StaticGeneratorInterface $static_generator, FileSystemInterface $file_system) { | ||
$this->staticGenerator = $static_generator; | ||
$this->fileSystem = $file_system; | ||
} | ||
|
||
/** | ||
* Reacts to a response event. | ||
* | ||
* @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event | ||
* The event. | ||
*/ | ||
public function onResponse(FilterResponseEvent $event) { | ||
$response = $event->getResponse(); | ||
$request = $event->getRequest(); | ||
if ($request->attributes->has(StaticGeneratorInterface::REQUEST_KEY) && $response instanceof RedirectResponse) { | ||
$base_dir = $this->staticGenerator->getStaticDirectory(); | ||
$this->fileSystem->prepareDirectory($base_dir, FileSystemInterface::CREATE_DIRECTORY); | ||
file_put_contents("$base_dir/_redirects", $request->getPathInfo() . ' ' . $response->getTargetUrl() . "\n", FILE_APPEND); | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public static function getSubscribedEvents() { | ||
$events[KernelEvents::RESPONSE][] = ['onResponse']; | ||
return $events; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
<?php | ||
|
||
namespace Drupal\quant_tome; | ||
|
||
use Drupal\Core\Batch\BatchBuilder; | ||
use Drupal\Core\DependencyInjection\DependencySerializationTrait; | ||
use Drupal\Core\File\FileSystemInterface; | ||
use Drupal\Core\Queue\QueueFactory; | ||
use Drupal\quant\Plugin\QueueItem\RedirectItem; | ||
use Drupal\quant\Plugin\QueueItem\RouteItem; | ||
use Drupal\quant_api\Client\QuantClient; | ||
use Drupal\tome_base\PathTrait; | ||
use Drupal\tome_static\StaticGeneratorInterface; | ||
|
||
/** | ||
* Batch process for Tome static content. | ||
*/ | ||
class QuantTomeBatch { | ||
|
||
use PathTrait; | ||
use DependencySerializationTrait; | ||
|
||
/** | ||
* The static generator. | ||
* | ||
* @var \Drupal\tome_static\StaticGeneratorInterface | ||
*/ | ||
protected $static; | ||
|
||
/** | ||
* The file system. | ||
* | ||
* @var \Drupal\Core\File\FileSystemInterface | ||
*/ | ||
protected $fileSystem; | ||
|
||
/** | ||
* The Quant API client. | ||
* | ||
* @var \Drupal\quant_api\Client\QuantClient | ||
*/ | ||
protected $client; | ||
|
||
/** | ||
* The queue factory. | ||
* | ||
* @var \Drupal\Core\Queue\QueueFactory | ||
*/ | ||
protected $queueFactory; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param \Drupal\tome_static\StaticGeneratorInterface $static | ||
* The Tome static generator. | ||
* @param \Drupal\Core\File\FileSystemInterface $file_system | ||
* The file system interface. | ||
* @param \Drupal\quant_api\Client\QuantClient $client | ||
* The Quant API client. | ||
* @param \Drupal\Core\Queue\QueueFactory $queue_factory | ||
* The queue factory. | ||
*/ | ||
public function __construct(StaticGeneratorInterface $static, FileSystemInterface $file_system, QuantClient $client, QueueFactory $queue_factory) { | ||
$this->static = $static; | ||
$this->fileSystem = $file_system; | ||
$this->client = $client; | ||
$this->queueFactory = $queue_factory; | ||
} | ||
|
||
/** | ||
* Check to see if Quant is configured correctly. | ||
* | ||
* @return bool | ||
* If we can connect to the Quant API. | ||
*/ | ||
public function checkConfig() { | ||
return $this->client->ping(); | ||
} | ||
|
||
/** | ||
* Determine if Tome export exists. | ||
* | ||
* @return bool | ||
* State of the export location. | ||
*/ | ||
public function checkBuild() { | ||
return file_exists($this->static->getStaticDirectory()); | ||
} | ||
|
||
/** | ||
* Generate the batch to seed Tome exports. | ||
* | ||
* @return \Drupal\Core\Batch\BatchBuilder | ||
* A batch builder object. | ||
*/ | ||
public function getBatch() { | ||
$batch_builder = new BatchBuilder(); | ||
$files = []; | ||
|
||
foreach ($this->fileSystem->scanDirectory($this->static->getStaticDirectory(), '/.*/') as $file) { | ||
$files[] = $file->uri; | ||
} | ||
|
||
foreach (array_chunk($files, 10) as $chunk) { | ||
$batch_builder->addOperation([$this, 'getHashes'], [$chunk]); | ||
} | ||
|
||
$batch_builder->addOperation([$this, 'checkRequiredFiles']); | ||
return $batch_builder; | ||
} | ||
|
||
/** | ||
* Generate hashes of the files. | ||
* | ||
* Generate hashes as Quant's API would for the file content. This will reduce | ||
* the number of files that we need to seed in the final batch operation. | ||
* | ||
* @todo Quant meta look up or local? | ||
* | ||
* @param array $files | ||
* List of file URIs. | ||
* @param array|\ArrayAccess &$context | ||
* The batch context. | ||
*/ | ||
public function getHashes(array $files, &$context) { | ||
$file_hashes = []; | ||
foreach ($files as $file) { | ||
$file_hashes[$file] = md5(file_get_contents($file)); | ||
} | ||
|
||
$context['results']['files'] = isset($context['results']['files']) ? $context['results']['files'] : []; | ||
$context['results']['files'] = array_merge($context['results']['files'], $file_hashes); | ||
} | ||
|
||
/** | ||
* Processes the hashed records and generates the deploy batch. | ||
* | ||
* Takes the computed file hashes and evaluates which files need to be sent | ||
* to Quant. Then, it creates another batch operation to seed the data. | ||
* | ||
* @param array|\ArrayAccess $context | ||
* The batch context. | ||
*/ | ||
public function checkRequiredFiles(&$context) { | ||
$file_hashes = $context['results']['files']; | ||
|
||
$queue = $this->queueFactory->get('quant_seed_worker'); | ||
$queue->deleteQueue(); | ||
|
||
foreach ($file_hashes as $file_path => $hash) { | ||
if (strpos($file_path, 'redirect') > -1) { | ||
if ($handle = fopen($file_path, 'r')) { | ||
while (!feof($handle)) { | ||
$line = fgets($handle); | ||
$redirect = explode(' ', $line); | ||
$source = trim($redirect[0]); | ||
if (empty($source)) { | ||
break; | ||
} | ||
// Only use the destination URI. | ||
$destination = parse_url(trim($redirect[1]), PHP_URL_PATH); | ||
$queue->createItem(new RedirectItem([ | ||
'source' => $source, | ||
'destination' => $destination, | ||
'status_code' => 301, | ||
])); | ||
} | ||
} | ||
fclose($handle); | ||
continue; | ||
} | ||
|
||
$uri = $this->pathToUri($file_path); | ||
$item = new RouteItem([ | ||
'route' => $uri, | ||
'uri' => $uri, | ||
'file_path' => $file_path, | ||
]); | ||
|
||
$queue->createItem($item); | ||
} | ||
} | ||
|
||
/** | ||
* Convert the path to a URI. | ||
* | ||
* @param string $file_path | ||
* The file path. | ||
* | ||
* @return string | ||
* URI based on the file path. | ||
*/ | ||
public function pathToUri($file_path) { | ||
// Strip directory and index.html to match regular Quant processing. | ||
$uri = str_replace($this->static->getStaticDirectory(), '', $file_path); | ||
$uri = str_replace('/index.html', '', $uri); | ||
return $uri; | ||
} | ||
|
||
/** | ||
* Deploy a file to Quant. | ||
* | ||
* @var \Drupal\quant\Plugin\QueueItem $item | ||
* The file item to send to Quant API. | ||
*/ | ||
public function deploy($item, array &$context) { | ||
\Drupal::logger('quant_tome')->notice('Sending %s', [ | ||
'%s' => $item->log(), | ||
]); | ||
$item->send(); | ||
} | ||
|
||
/** | ||
* Finish deploy process. | ||
* | ||
* @param bool $success | ||
* TRUE if batch successfully completed. | ||
* @param array $context | ||
* Batch context. | ||
*/ | ||
public function finish($success, array &$context) { | ||
if ($success) { | ||
\Drupal::logger('quant_tome')->info('Complete!'); | ||
} | ||
else { | ||
\Drupal::logger('quant_tome')->error('Failed to deploy all files, check the logs!'); | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.