PluginProbe
JetBackup – Backup, Restore & Migrate / 3.1.21.3
JetBackup – Backup, Restore & Migrate v3.1.21.3
3.1.23.6 3.1.23.5 3.1.23.3 3.1.22.4 3.1.22.3 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.8.1 1.4.9 1.5.0 1.5.1 1.5.1.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 1.6.10 All 82 releases
backup / src / JetBackup / Queue / QueueItem.php
QueueItem.php
323 lines 11.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace JetBackup\Queue;
4
5 use JetBackup\BackupJob\BackupJob;
6 use JetBackup\CLI\CLI;
7 use JetBackup\Data\Engine;
8 use JetBackup\Data\SleekStore;
9 use JetBackup\Entities\Util;
10 use JetBackup\Exception\FieldsValidationException;
11 use JetBackup\Exception\TaskException;
12 use JetBackup\Factory;
13 use JetBackup\JetBackup;
14 use JetBackup\Log\LogController;
15 use JetBackup\ResumableTask\ResumableTask;
16 use SleekDB\Exceptions\InvalidArgumentException;
17 use SleekDB\Exceptions\IOException;
18 use SleekDB\QueryBuilder;
19
20 if (!defined( '__JETBACKUP__')) die('Direct access is not allowed');
21
22 class QueueItem extends Engine {
23
24 const COLLECTION = 'queue';
25
26 const UNIQUE_ID = 'unique_id';
27 const ITEM_ID = 'item_id';
28 const CREATED = 'created';
29 const STARTED = 'started';
30 const ENDED = 'ended';
31 const TYPE = 'type';
32 const TYPE_NAME = 'type_name';
33 const STATUS = 'status';
34 const STATUS_NAME = 'status_name';
35 const STATUS_TIME = 'status_time';
36 const PROGRESS = 'progress';
37 const ERRORS = 'errors';
38 const ITEM_DATA = 'item_data';
39 const LOG_FILE = 'log_file';
40 const EXEC_TIME = 'exec_time';
41
42 const PROGRESS_LAST_STEP = -1;
43
44 private ?Progress $_progress=null;
45 private ?aQueueItem $_item_data=null;
46 private ?ResumableTask $_resumable_task=null;
47
48 public function __construct($_id=null) {
49 parent::__construct(self::COLLECTION);
50 if($_id) $this->_loadById((int) $_id);
51 }
52
53 /**
54 * @param $unique_id
55 *
56 * @return void
57 * @throws IOException
58 * @throws InvalidArgumentException
59 */
60 public function loadByUniqueId($unique_id) {
61 $this->_load([[self::UNIQUE_ID, '=', $unique_id]]);
62 }
63
64 /**
65 * @return void
66 * @throws IOException
67 * @throws InvalidArgumentException
68 */
69 public function addError(): void {
70 $this->set(self::ERRORS, $this->getErrors() + 1);
71 $this->save();
72 }
73
74 public function getErrors(): int {
75 return $this->get(self::ERRORS, 0);
76 }
77
78
79 public function setUniqueId($id) { $this->set(self::UNIQUE_ID, $id); }
80 public function getUniqueId():string { return $this->get(self::UNIQUE_ID); }
81
82 public function setCreated($value):void { $this->set(self::CREATED, $value); }
83 public function getCreated() { return $this->get(self::CREATED); }
84
85 public function setStarted(int $value):void { $this->set(self::STARTED, $value); }
86 public function getStarted():int { return (int) $this->get(self::STARTED, 0); }
87
88 public function setEnded(int $value):void { $this->set(self::ENDED, $value); }
89 public function getEnded():int { return (int) $this->get(self::ENDED, 0); }
90
91 public function setType($value):void {
92 $this->set(self::TYPE, $value);
93 $this->_item_data = null;
94 }
95
96 public function getType() { return $this->get(self::TYPE); }
97
98 public function setStatus($value):void {
99 $this->set(self::STATUS, $value);
100 $this->setStatusTime(time());
101 }
102 public function getStatus() {
103 return $this->get(self::STATUS); // this will return from memory
104 }
105
106 public function setProgress(Progress $value):void {
107 $this->_progress = $value;
108 $this->set(self::PROGRESS, $value->getData());
109 }
110
111 public function getProgress():Progress {
112 if(!$this->_progress) $this->_progress = new Progress($this->get(self::PROGRESS, []));
113 return $this->_progress;
114 }
115
116 public function updateProgress(string $message, ?int $current_item=null) {
117 $progress = $this->getProgress();
118 $currentProgress = $progress->getCurrentItem();
119
120 if($current_item !== null) $currentProgress = $current_item <= $progress->getTotalItems() ? $current_item : $progress->getTotalItems();
121 if($current_item === self::PROGRESS_LAST_STEP) $currentProgress = $progress->getTotalItems();
122 else $currentProgress++;
123 $progress->setMessage($message);
124 $progress->setCurrentItem($currentProgress);
125 $this->save();
126 }
127
128 public function updateStatus($status) {
129 if($this->getStatus() == Queue::STATUS_PENDING) $this->setStarted(time());
130 $this->setStatus($status);
131 $this->setStatusTime(time());
132 if($status >= Queue::STATUS_DONE) {
133 $this->getResumableTask()->delete();
134 $this->setEnded(time());
135 }
136 $this->save();
137 if (in_array($this->getStatus(), Queue::REQUIRES_CLEANUP)) Util::rm($this->getWorkspace());
138 }
139
140 public function setItemData(aQueueItem $value):void {
141 $this->_item_data = $value;
142 $this->set(self::ITEM_DATA, $value->getData());
143 }
144
145 /**
146 * @return QueueItemBackup|QueueItemRestore|QueueItemDownload|QueueItemReindex|QueueItemRetentionCleanup|QueueItemSystem|QueueItemExport|QueueItemExtract|null
147 */
148 public function getItemData():?aQueueItem {
149
150 if(!$this->_item_data) {
151 $data = (array) $this->get(self::ITEM_DATA, []);
152 switch ($this->getType()) {
153 case Queue::QUEUE_TYPE_BACKUP: $this->_item_data = new QueueItemBackup($data); break;
154 case Queue::QUEUE_TYPE_RESTORE: $this->_item_data = new QueueItemRestore($data); break;
155 case Queue::QUEUE_TYPE_DOWNLOAD: $this->_item_data = new QueueItemDownload($data); break;
156 case Queue::QUEUE_TYPE_DOWNLOAD_BACKUP_LOG: $this->_item_data = new QueueItemDownload($data); break;
157 case Queue::QUEUE_TYPE_REINDEX: $this->_item_data = new QueueItemReindex($data); break;
158 case Queue::QUEUE_TYPE_RETENTION_CLEANUP: $this->_item_data = new QueueItemRetentionCleanup($data); break;
159 case Queue::QUEUE_TYPE_SYSTEM: $this->_item_data = new QueueItemSystem($data); break;
160 case Queue::QUEUE_TYPE_EXPORT: $this->_item_data = new QueueItemExport($data); break;
161 case Queue::QUEUE_TYPE_EXTRACT: $this->_item_data = new QueueItemExtract($data); break;
162
163 }
164 }
165
166 return $this->_item_data;
167 }
168
169 public function setLogFile($value):void { $this->set(self::LOG_FILE, $value); }
170 public function getLogFile() { return $this->get(self::LOG_FILE); }
171
172 public function setItemId($value):void { $this->set(self::ITEM_ID, $value); }
173 public function getItemId() { return $this->get(self::ITEM_ID); }
174
175 public function setStatusTime($value):void { $this->set(self::STATUS_TIME, $value); }
176 public function getStatusTime() { return $this->get(self::STATUS_TIME); }
177
178 public static function db():SleekStore {
179 return new SleekStore(self::COLLECTION);
180 }
181
182 public static function query():QueryBuilder {
183 return self::db()->createQueryBuilder();
184 }
185
186 /**
187 * @throws InvalidArgumentException
188 */
189 public function delete():void {
190 if(!$this->getId()) return;
191 $this->getDB()->clearCache();
192 $this->getDB()->deleteById($this->getId());
193 }
194
195 public function save():void {
196 if(!$this->getUniqueId()) $this->setUniqueId(Util::generateUniqueId());
197 $this->setProgress($this->getProgress());
198 $this->setItemData($this->getItemData());
199 parent::save();
200 }
201
202 public function getResumableTask():ResumableTask {
203 if(!$this->_resumable_task) $this->_resumable_task = new ResumableTask($this->getUniqueId(), $this->getWorkspace());
204 return $this->_resumable_task;
205 }
206
207 public function getWorkspace(): string {
208 return Factory::getLocations()->getTempDir() . JetBackup::SEP . $this->getUniqueId();
209 }
210
211 public function getAbortFileLocation(): string {
212 return $this->getWorkspace() . JetBackup::SEP . $this->getUniqueId() . '.abort';
213 }
214 /**
215 * @return void
216 * @throws TaskException
217 */
218 public function abort() {
219 if ($this->getStatus() == Queue::STATUS_PENDING) {
220 $this->updateStatus(Queue::STATUS_ABORTED);
221 return;
222 }
223 if(!file_exists($this->getWorkspace())) throw new TaskException('Queue item working folder not set yet');
224 $this->updateStatus(Queue::STATUS_ABORTED);
225 touch($this->getAbortFileLocation());
226 }
227
228 /**
229 * @return void
230 * @throws InvalidArgumentException
231 * @throws IOException
232 */
233 public function startOver() {
234 $this->setUniqueId('');
235 $this->setStatus(Queue::STATUS_PENDING);
236 $progress = $this->getProgress();
237 $progress->setMessage('Starting over queue item');
238 $progress->resetSub();
239 $this->setProgress($progress);
240 if(file_exists($this->getAbortFileLocation())) unlink($this->getAbortFileLocation());
241 $this->save();
242 }
243
244 public function getExecutionTime():string {
245 if ($this->getStarted() == 0) return '00:00:00';
246 if ($this->getEnded() > 0) return gmdate('H:i:s', $this->getEnded() - $this->getStarted());
247 return gmdate('H:i:s', time() - $this->getStarted());
248 }
249
250 public static function prepare():QueueItem {
251 $item = new QueueItem();
252 $item->setStatus(Queue::STATUS_PENDING);
253 $item->setCreated(time());
254 $item->setEngine(Engine::ENGINE_WP);
255
256 $progress = $item->getProgress();
257 $progress->setCurrentItem(0);
258 $progress->setMessage('Waiting for cron...');
259
260 return $item;
261 }
262
263 public function getDisplay():array {
264 return [
265 JetBackup::ID_FIELD => $this->getId(),
266 self::UNIQUE_ID => $this->getUniqueId(),
267 self::ITEM_ID => $this->getItemId(),
268 self::TYPE => $this->getType(),
269 self::TYPE_NAME => Queue::QUEUE_TYPES_NAMES[$this->getType()] ?? 'Unknown',
270 Engine::ENGINE => $this->getEngine(),
271 self::CREATED => $this->getCreated(),
272 self::STARTED => $this->getStarted(),
273 self::ENDED => $this->getEnded(),
274 self::ITEM_DATA => $this->getItemData()->getDisplay() ?: [],
275 self::STATUS => $this->getStatus(),
276 self::STATUS_NAME => Queue::QUEUE_STATUS_NAMES[$this->getType()][$this->getStatus()] ?? '',
277 self::STATUS_TIME => $this->getStatusTime(),
278 self::PROGRESS => $this->getProgress()->getDisplay(),
279 self::LOG_FILE => $this->getLogFile(),
280 self::EXEC_TIME => $this->getExecutionTime(),
281 ];
282 }
283
284 public function getDisplayCLI():array {
285 $statuses = Queue::STATUS_NAMES;
286 switch($this->getType()) {
287 case Queue::QUEUE_TYPE_BACKUP:
288 /** @var QueueItemBackup $item */
289 $item = $this->getItemData();
290 $statuses += $item->getType() == BackupJob::TYPE_ACCOUNT ? Queue::STATUS_BACKUP_ACCOUNT_NAMES : Queue::STATUS_BACKUP_CONFIG_NAMES;
291 break;
292 case Queue::QUEUE_TYPE_RESTORE: $statuses += Queue::STATUS_PRE_RESTORE_NAMES; break;
293 case Queue::QUEUE_TYPE_DOWNLOAD: $statuses += Queue::STATUS_DOWNLOAD_NAMES; break;
294 case Queue::QUEUE_TYPE_REINDEX: $statuses += Queue::STATUS_REINDEX_NAMES; break;
295 case Queue::QUEUE_TYPE_RETENTION_CLEANUP: $statuses += Queue::STATUS_CLEANUP_NAMES; break;
296 case Queue::QUEUE_TYPE_SYSTEM: $statuses += Queue::STATUS_SYSTEM_NAMES; break;
297 case Queue::QUEUE_TYPE_EXPORT: $statuses += Queue::STATUS_EXPORT_NAMES; break;
298 case Queue::QUEUE_TYPE_EXTRACT: $statuses += Queue::STATUS_EXTRACT_NAMES; break;
299 }
300
301 return [
302 'ID' => $this->getId(),
303 'Item ID' => $this->getItemId(),
304 'Type' => Queue::QUEUE_TYPES_NAMES[$this->getType()] . ' (' . $this->getType() . ')',
305 'Engine' => $this->getEngineName(),
306 'Created' => CLI::date($this->getCreated()),
307 'Started' => $this->getStarted() ? CLI::date($this->getStarted()) : 'Never',
308 'Ended' => $this->getEnded() ? CLI::date($this->getEnded()) : 'Never',
309 'Status' => $statuses[$this->getStatus()],
310 'Status Time' => $this->getStatusTime() ? CLI::date($this->getStatusTime()) : 'Never',
311 'Log File' => $this->getLogFile(),
312 ];
313 }
314
315 /**
316 * @throws FieldsValidationException
317 */
318 public function validateFields():void {
319 if(!$this->getType()) throw new FieldsValidationException("Queue type must be set");
320 }
321
322
323 }