File: /home/infowars/askalexjones.com/wp-content/plugins/backup/src/JetBackup/Queue/QueueItem.php
<?php
namespace JetBackup\Queue;
use JetBackup\BackupJob\BackupJob;
use JetBackup\CLI\CLI;
use JetBackup\Data\Engine;
use JetBackup\Data\SleekStore;
use JetBackup\Entities\Util;
use JetBackup\Exception\FieldsValidationException;
use JetBackup\Exception\TaskException;
use JetBackup\Factory;
use JetBackup\JetBackup;
use JetBackup\Log\LogController;
use JetBackup\ResumableTask\ResumableTask;
use SleekDB\Exceptions\InvalidArgumentException;
use SleekDB\Exceptions\IOException;
use SleekDB\QueryBuilder;
if (!defined( '__JETBACKUP__')) die('Direct access is not allowed');
class QueueItem extends Engine {
const COLLECTION = 'queue';
const UNIQUE_ID = 'unique_id';
const ITEM_ID = 'item_id';
const CREATED = 'created';
const STARTED = 'started';
const ENDED = 'ended';
const TYPE = 'type';
const TYPE_NAME = 'type_name';
const STATUS = 'status';
const STATUS_NAME = 'status_name';
const STATUS_TIME = 'status_time';
const PROGRESS = 'progress';
const ERRORS = 'errors';
const ITEM_DATA = 'item_data';
const LOG_FILE = 'log_file';
const EXEC_TIME = 'exec_time';
const PROGRESS_LAST_STEP = -1;
private ?Progress $_progress=null;
private ?aQueueItem $_item_data=null;
private ?ResumableTask $_resumable_task=null;
public function __construct($_id=null) {
parent::__construct(self::COLLECTION);
if($_id) $this->_loadById((int) $_id);
}
/**
* @param $unique_id
*
* @return void
* @throws IOException
* @throws InvalidArgumentException
*/
public function loadByUniqueId($unique_id) {
$this->_load([[self::UNIQUE_ID, '=', $unique_id]]);
}
/**
* @return void
* @throws IOException
* @throws InvalidArgumentException
*/
public function addError(): void {
$this->set(self::ERRORS, $this->getErrors() + 1);
$this->save();
}
public function getErrors(): int {
return $this->get(self::ERRORS, 0);
}
public function setUniqueId($id) { $this->set(self::UNIQUE_ID, $id); }
public function getUniqueId():string { return $this->get(self::UNIQUE_ID); }
public function setCreated($value):void { $this->set(self::CREATED, $value); }
public function getCreated() { return $this->get(self::CREATED); }
public function setStarted(int $value):void { $this->set(self::STARTED, $value); }
public function getStarted():int { return (int) $this->get(self::STARTED, 0); }
public function setEnded(int $value):void { $this->set(self::ENDED, $value); }
public function getEnded():int { return (int) $this->get(self::ENDED, 0); }
public function setType($value):void {
$this->set(self::TYPE, $value);
$this->_item_data = null;
}
public function getType() { return $this->get(self::TYPE); }
public function setStatus($value):void {
$this->set(self::STATUS, $value);
$this->setStatusTime(time());
}
public function getStatus() {
return $this->get(self::STATUS); // this will return from memory
}
public function setProgress(Progress $value):void {
$this->_progress = $value;
$this->set(self::PROGRESS, $value->getData());
}
public function getProgress():Progress {
if(!$this->_progress) $this->_progress = new Progress($this->get(self::PROGRESS, []));
return $this->_progress;
}
public function updateProgress(string $message, ?int $current_item=null) {
$progress = $this->getProgress();
$currentProgress = $progress->getCurrentItem();
if($current_item !== null) $currentProgress = $current_item <= $progress->getTotalItems() ? $current_item : $progress->getTotalItems();
if($current_item === self::PROGRESS_LAST_STEP) $currentProgress = $progress->getTotalItems();
else $currentProgress++;
$progress->setMessage($message);
$progress->setCurrentItem($currentProgress);
$this->save();
}
public function updateStatus($status) {
if($this->getStatus() == Queue::STATUS_PENDING) $this->setStarted(time());
$this->setStatus($status);
$this->setStatusTime(time());
if($status >= Queue::STATUS_DONE) {
$this->getResumableTask()->delete();
$this->setEnded(time());
}
$this->save();
if (in_array($this->getStatus(), Queue::REQUIRES_CLEANUP)) Util::rm($this->getWorkspace());
}
public function setItemData(aQueueItem $value):void {
$this->_item_data = $value;
$this->set(self::ITEM_DATA, $value->getData());
}
/**
* @return QueueItemBackup|QueueItemRestore|QueueItemDownload|QueueItemReindex|QueueItemRetentionCleanup|QueueItemSystem|QueueItemExport|QueueItemExtract|null
*/
public function getItemData():?aQueueItem {
if(!$this->_item_data) {
$data = (array) $this->get(self::ITEM_DATA, []);
switch ($this->getType()) {
case Queue::QUEUE_TYPE_BACKUP: $this->_item_data = new QueueItemBackup($data); break;
case Queue::QUEUE_TYPE_RESTORE: $this->_item_data = new QueueItemRestore($data); break;
case Queue::QUEUE_TYPE_DOWNLOAD: $this->_item_data = new QueueItemDownload($data); break;
case Queue::QUEUE_TYPE_DOWNLOAD_BACKUP_LOG: $this->_item_data = new QueueItemDownload($data); break;
case Queue::QUEUE_TYPE_REINDEX: $this->_item_data = new QueueItemReindex($data); break;
case Queue::QUEUE_TYPE_RETENTION_CLEANUP: $this->_item_data = new QueueItemRetentionCleanup($data); break;
case Queue::QUEUE_TYPE_SYSTEM: $this->_item_data = new QueueItemSystem($data); break;
case Queue::QUEUE_TYPE_EXPORT: $this->_item_data = new QueueItemExport($data); break;
case Queue::QUEUE_TYPE_EXTRACT: $this->_item_data = new QueueItemExtract($data); break;
}
}
return $this->_item_data;
}
public function setLogFile($value):void { $this->set(self::LOG_FILE, $value); }
public function getLogFile() { return $this->get(self::LOG_FILE); }
public function setItemId($value):void { $this->set(self::ITEM_ID, $value); }
public function getItemId() { return $this->get(self::ITEM_ID); }
public function setStatusTime($value):void { $this->set(self::STATUS_TIME, $value); }
public function getStatusTime() { return $this->get(self::STATUS_TIME); }
public static function db():SleekStore {
return new SleekStore(self::COLLECTION);
}
public static function query():QueryBuilder {
return self::db()->createQueryBuilder();
}
/**
* @throws InvalidArgumentException
*/
public function delete():void {
if(!$this->getId()) return;
$this->getDB()->clearCache();
$this->getDB()->deleteById($this->getId());
}
public function save():void {
if(!$this->getUniqueId()) $this->setUniqueId(Util::generateUniqueId());
$this->setProgress($this->getProgress());
$this->setItemData($this->getItemData());
parent::save();
}
public function getResumableTask():ResumableTask {
if(!$this->_resumable_task) $this->_resumable_task = new ResumableTask($this->getUniqueId(), $this->getWorkspace());
return $this->_resumable_task;
}
public function getWorkspace(): string {
return Factory::getLocations()->getTempDir() . JetBackup::SEP . $this->getUniqueId();
}
public function getAbortFileLocation(): string {
return $this->getWorkspace() . JetBackup::SEP . $this->getUniqueId() . '.abort';
}
/**
* @return void
* @throws TaskException
*/
public function abort() {
if ($this->getStatus() == Queue::STATUS_PENDING) {
$this->updateStatus(Queue::STATUS_ABORTED);
return;
}
if(!file_exists($this->getWorkspace())) throw new TaskException('Queue item working folder not set yet');
$this->updateStatus(Queue::STATUS_ABORTED);
touch($this->getAbortFileLocation());
}
/**
* @return void
* @throws InvalidArgumentException
* @throws IOException
*/
public function startOver() {
$this->setUniqueId('');
$this->setStatus(Queue::STATUS_PENDING);
$progress = $this->getProgress();
$progress->setMessage('Starting over queue item');
$progress->resetSub();
$this->setProgress($progress);
if(file_exists($this->getAbortFileLocation())) unlink($this->getAbortFileLocation());
$this->save();
}
public function getExecutionTime():string {
if ($this->getStarted() == 0) return '00:00:00';
if ($this->getEnded() > 0) return gmdate('H:i:s', $this->getEnded() - $this->getStarted());
return gmdate('H:i:s', time() - $this->getStarted());
}
public static function prepare():QueueItem {
$item = new QueueItem();
$item->setStatus(Queue::STATUS_PENDING);
$item->setCreated(time());
$item->setEngine(Engine::ENGINE_WP);
$progress = $item->getProgress();
$progress->setCurrentItem(0);
$progress->setMessage('Waiting for cron...');
return $item;
}
public function getDisplay():array {
return [
JetBackup::ID_FIELD => $this->getId(),
self::UNIQUE_ID => $this->getUniqueId(),
self::ITEM_ID => $this->getItemId(),
self::TYPE => $this->getType(),
self::TYPE_NAME => Queue::QUEUE_TYPES_NAMES[$this->getType()] ?? 'Unknown',
Engine::ENGINE => $this->getEngine(),
self::CREATED => $this->getCreated(),
self::STARTED => $this->getStarted(),
self::ENDED => $this->getEnded(),
self::ITEM_DATA => $this->getItemData()->getDisplay() ?: [],
self::STATUS => $this->getStatus(),
self::STATUS_NAME => Queue::QUEUE_STATUS_NAMES[$this->getType()][$this->getStatus()] ?? '',
self::STATUS_TIME => $this->getStatusTime(),
self::PROGRESS => $this->getProgress()->getDisplay(),
self::LOG_FILE => $this->getLogFile(),
self::EXEC_TIME => $this->getExecutionTime(),
];
}
public function getDisplayCLI():array {
$statuses = Queue::STATUS_NAMES;
switch($this->getType()) {
case Queue::QUEUE_TYPE_BACKUP:
/** @var QueueItemBackup $item */
$item = $this->getItemData();
$statuses += $item->getType() == BackupJob::TYPE_ACCOUNT ? Queue::STATUS_BACKUP_ACCOUNT_NAMES : Queue::STATUS_BACKUP_CONFIG_NAMES;
break;
case Queue::QUEUE_TYPE_RESTORE: $statuses += Queue::STATUS_PRE_RESTORE_NAMES; break;
case Queue::QUEUE_TYPE_DOWNLOAD: $statuses += Queue::STATUS_DOWNLOAD_NAMES; break;
case Queue::QUEUE_TYPE_REINDEX: $statuses += Queue::STATUS_REINDEX_NAMES; break;
case Queue::QUEUE_TYPE_RETENTION_CLEANUP: $statuses += Queue::STATUS_CLEANUP_NAMES; break;
case Queue::QUEUE_TYPE_SYSTEM: $statuses += Queue::STATUS_SYSTEM_NAMES; break;
case Queue::QUEUE_TYPE_EXPORT: $statuses += Queue::STATUS_EXPORT_NAMES; break;
case Queue::QUEUE_TYPE_EXTRACT: $statuses += Queue::STATUS_EXTRACT_NAMES; break;
}
return [
'ID' => $this->getId(),
'Item ID' => $this->getItemId(),
'Type' => Queue::QUEUE_TYPES_NAMES[$this->getType()] . ' (' . $this->getType() . ')',
'Engine' => $this->getEngineName(),
'Created' => CLI::date($this->getCreated()),
'Started' => $this->getStarted() ? CLI::date($this->getStarted()) : 'Never',
'Ended' => $this->getEnded() ? CLI::date($this->getEnded()) : 'Never',
'Status' => $statuses[$this->getStatus()],
'Status Time' => $this->getStatusTime() ? CLI::date($this->getStatusTime()) : 'Never',
'Log File' => $this->getLogFile(),
];
}
/**
* @throws FieldsValidationException
*/
public function validateFields():void {
if(!$this->getType()) throw new FieldsValidationException("Queue type must be set");
}
}