blue-twilight/app/Console/Commands/ProcessQueueCommand.php

275 lines
8.1 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Album;
use App\Facade\UserConfig;
use App\Photo;
use App\QueueItem;
use App\Services\PhotoService;
use App\Services\RabbitMQService;
use App\User;
use App\UserActivity;
use Illuminate\Console\Command;
class ProcessQueueCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'bt-queue:process';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Processes items in the processing queue.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if (!UserConfig::isImageProcessingQueueEnabled())
{
$this->output->error('The image processing queue is not enabled');
}
$rabbitmq = new RabbitMQService();
$this->output->writeln('Monitoring queue');
$rabbitmq->waitOnQueue([$this, 'processQueueItem']);
}
/**
* Processes a single item from the queue.
*
* @param $msg
* @return void
*/
public function processQueueItem($msg)
{
$queueItemID = intval($msg->body);
$this->output->writeln(sprintf('Processing queue item %d', $queueItemID));
/** @var QueueItem $queueItem */
$queueItem = QueueItem::where('id', $queueItemID)->first();
if (is_null($queueItem))
{
$this->output->writeln('Queue item does not exist; skipping');
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
return;
}
try
{
switch (strtolower($queueItem->action_type))
{
case 'photo.analyse':
$this->processPhotoAnalyseMessage($queueItem);
break;
case 'photo.bulk_action.change_album':
case 'photo.bulk_action.delete':
case 'photo.bulk_action.flip_both':
case 'photo.bulk_action.flip_horizontal':
case 'photo.bulk_action.flip_vertical':
case 'photo.bulk_action.refresh_thumbnails':
case 'photo.bulk_action.rotate_left':
case 'photo.bulk_action.rotate_right':
$this->processPhotoBulkActionMessage($queueItem);
break;
default:
$this->output->writeln(sprintf('Action %s is not recognised, skipping', $queueItem->action_type));
return;
}
$queueItem->completed_at = new \DateTime();
$queueItem->save();
}
catch (\Exception $ex)
{
$this->output->error($ex->getMessage());
$queueItem->error_message = $ex->getMessage();
}
finally
{
$queueItem->completed_at = new \DateTime();
$queueItem->save();
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
}
}
private function createActivityRecord(Photo $photo, $type, $userID, $activityDateTime = null)
{
if (is_null($activityDateTime))
{
$activityDateTime = new \DateTime();
}
$userActivity = new UserActivity();
$userActivity->user_id = $userID;
$userActivity->activity_at = $activityDateTime;
$userActivity->type = $type;
$userActivity->photo_id = $photo->id;
$userActivity->save();
}
private function processPhotoAnalyseMessage(QueueItem $queueItem)
{
$this->output->writeln(sprintf('Analysing photo ID %l (batch: %s)', $queueItem->photo_id, $queueItem->batch_reference));
/** @var Photo $photo */
$photo = $queueItem->photo;
if (is_null($photo))
{
$this->output->writeln('Photo does not exist; skipping');
return;
}
/* IF CHANGING THIS LOGIC, ALSO CHECK PhotoController::analyse */
$photoService = new PhotoService($photo);
$photoService->analyse($queueItem->batch_reference);
// Log an activity record for the user's feed (remove an existing one as the date may have changed)
$this->removeExistingActivityRecords($photo, 'photo.taken');
if (!is_null($photo->taken_at))
{
// Log an activity record for the user's feed
$this->createActivityRecord($photo, 'photo.taken', $queueItem->user_id, $photo->taken_at);
}
$queueItem->is_successful = true;
}
private function processPhotoBulkActionMessage(QueueItem $queueItem)
{
$action = str_replace('photo.bulk_action.', '', $queueItem->action_type);
$this->output->writeln(sprintf('Apply action \'%s\' to photo ID %l (batch: %s)', $action, $queueItem->photo_id, $queueItem->batch_reference));
/** @var Photo $photo */
$photo = $queueItem->photo;
if (is_null($photo))
{
$this->output->writeln('Photo does not exist; skipping');
return;
}
/** @var User $user */
$user = $queueItem->user;
if (is_null($user))
{
$this->output->writeln('User does not exist; skipping');
return;
}
$photoService = new PhotoService($photo);
switch (strtolower($action))
{
/* This needs a bit more work - we need to also store the new album ID in the queue_items table */
case 'change_album':
if ($user->can('change-metadata', $photo))
{
$newAlbum = Album::where('id', intval($queueItem->new_album_id))->first();
if (is_null($newAlbum) || !$user->can('upload-photos', $newAlbum))
{
$this->output->writeln('Target album does not exist or user does not have permission.');
return;
}
$this->output->writeln(sprintf('Moving photo to album \'%s\'', $newAlbum->name));
$photoService->changeAlbum($newAlbum);
}
break;
case 'delete':
if ($user->can('delete', $photo))
{
$photoService->delete();
}
break;
case 'flip_both':
if ($user->can('manipulate', $photo))
{
$photoService->flip(true, true);
}
break;
case 'flip_horizontal':
if ($user->can('manipulate', $photo))
{
$photoService->flip(true, false);
}
break;
case 'flip_vertical':
if ($user->can('manipulate', $photo))
{
$photoService->flip(false, true);
}
break;
case 'refresh_thumbnails':
if ($user->can('change-metadata', $photo))
{
$photoService->regenerateThumbnails();
}
break;
case 'rotate_left':
if ($user->can('manipulate', $photo))
{
$photoService->rotate(90);
}
break;
case 'rotate_right':
if ($user->can('manipulate', $photo))
{
$photoService->rotate(270);
}
break;
default:
$this->output->writeln(sprintf('Action \'%s\' not recognised; skipping'));
return;
}
}
private function removeExistingActivityRecords(Photo $photo, $type)
{
$existingFeedRecords = UserActivity::where([
'user_id' => $photo->user_id,
'photo_id' => $photo->id,
'type' => $type
])->get();
foreach ($existingFeedRecords as $existingFeedRecord)
{
$existingFeedRecord->delete();
}
}
}