2023-04-17 01:07:57 +00:00
|
|
|
<?php
|
|
|
|
|
2023-10-15 02:20:21 +00:00
|
|
|
declare(strict_types=1);
|
|
|
|
|
2023-04-17 01:07:57 +00:00
|
|
|
namespace OCA\Memories\Cron;
|
|
|
|
|
2023-04-17 01:47:26 +00:00
|
|
|
use OCA\Memories\AppInfo\Application;
|
2023-04-17 01:07:57 +00:00
|
|
|
use OCA\Memories\Service;
|
2023-10-22 19:58:33 +00:00
|
|
|
use OCA\Memories\Settings\SystemConfig;
|
2023-04-17 01:07:57 +00:00
|
|
|
use OCP\AppFramework\Utility\ITimeFactory;
|
|
|
|
use OCP\BackgroundJob\TimedJob;
|
2023-04-17 01:47:26 +00:00
|
|
|
use OCP\IConfig;
|
2023-04-17 01:07:57 +00:00
|
|
|
use OCP\IUserManager;
|
|
|
|
use Psr\Log\LoggerInterface;
|
|
|
|
|
2023-04-17 01:47:26 +00:00
|
|
|
const MAX_RUN_TIME = 300; // seconds
|
|
|
|
const INTERVAL = 900; // seconds (don't set this too low)
|
2023-04-17 01:07:57 +00:00
|
|
|
|
|
|
|
class IndexJob extends TimedJob
|
|
|
|
{
|
2023-04-17 01:47:26 +00:00
|
|
|
private bool $_hasError = false;
|
2023-04-17 01:07:57 +00:00
|
|
|
|
|
|
|
public function __construct(
|
|
|
|
ITimeFactory $time,
|
2023-10-15 01:51:17 +00:00
|
|
|
private Service\Index $service,
|
|
|
|
private IUserManager $userManager,
|
|
|
|
private LoggerInterface $logger,
|
2023-10-15 01:59:00 +00:00
|
|
|
private IConfig $config,
|
2023-04-17 01:07:57 +00:00
|
|
|
) {
|
|
|
|
parent::__construct($time);
|
|
|
|
|
|
|
|
$this->setInterval(INTERVAL);
|
|
|
|
}
|
|
|
|
|
2023-10-15 01:51:17 +00:00
|
|
|
/**
|
|
|
|
* Run the background indexing job.
|
|
|
|
*/
|
2023-10-15 20:16:57 +00:00
|
|
|
protected function run(mixed $argument): void
|
2023-04-17 01:07:57 +00:00
|
|
|
{
|
|
|
|
// Check if indexing is enabled
|
2023-10-22 19:58:33 +00:00
|
|
|
if ('0' === SystemConfig::get('memories.index.mode')) {
|
2023-04-17 01:07:57 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-04-17 01:47:26 +00:00
|
|
|
// Store the last run time
|
2023-10-14 08:25:50 +00:00
|
|
|
$this->config->setAppValue(Application::APPNAME, 'last_index_job_start', (string) time());
|
|
|
|
$this->config->setAppValue(Application::APPNAME, 'last_index_job_duration', (string) 0);
|
2023-04-17 01:47:26 +00:00
|
|
|
|
2023-04-17 01:07:57 +00:00
|
|
|
// Run for a maximum of 5 minutes
|
|
|
|
$startTime = microtime(true);
|
2023-10-14 08:25:50 +00:00
|
|
|
$this->service->continueCheck = static function () use ($startTime): bool {
|
2023-04-17 01:07:57 +00:00
|
|
|
return (microtime(true) - $startTime) < MAX_RUN_TIME;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Index with static exiftool process
|
|
|
|
// This is sub-optimal: the process may not be required at all.
|
|
|
|
try {
|
2023-09-29 18:25:49 +00:00
|
|
|
// Start and make sure exiftool is working
|
2023-04-17 01:07:57 +00:00
|
|
|
\OCA\Memories\Exif::ensureStaticExiftoolProc();
|
2023-09-29 18:25:49 +00:00
|
|
|
Service\BinExt::testExiftool(); // throws
|
|
|
|
|
|
|
|
// Run the indexer
|
2023-04-17 01:07:57 +00:00
|
|
|
$this->indexAllUsers();
|
2023-09-29 18:25:49 +00:00
|
|
|
|
|
|
|
// Remove stale index entries
|
2023-04-25 00:59:26 +00:00
|
|
|
$this->service->cleanupStale();
|
2023-09-29 18:25:49 +00:00
|
|
|
|
2023-04-17 01:47:26 +00:00
|
|
|
$this->log('Indexing completed successfully', 'success');
|
2023-04-17 01:07:57 +00:00
|
|
|
} catch (Service\ProcessClosedException $e) {
|
2023-04-23 09:53:38 +00:00
|
|
|
$this->log('Indexing process stopped before completion. Will continue on next run', 'info');
|
2023-09-29 18:25:49 +00:00
|
|
|
} catch (\Exception $e) {
|
|
|
|
$this->log('Indexing exception: '.$e->getMessage());
|
2023-04-17 01:07:57 +00:00
|
|
|
} finally {
|
2023-09-29 18:25:49 +00:00
|
|
|
// Close the static exiftool process
|
2023-04-17 01:07:57 +00:00
|
|
|
\OCA\Memories\Exif::closeStaticExiftoolProc();
|
|
|
|
}
|
2023-04-17 01:47:26 +00:00
|
|
|
|
|
|
|
// Store the last run duration
|
|
|
|
$duration = round(microtime(true) - $startTime, 2);
|
2023-10-14 08:25:50 +00:00
|
|
|
$this->config->setAppValue(Application::APPNAME, 'last_index_job_duration', (string) $duration);
|
2023-04-17 01:07:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Index all users.
|
|
|
|
*
|
|
|
|
* @throws Service\ProcessClosedException if the process was closed before completion
|
|
|
|
*/
|
|
|
|
private function indexAllUsers(): void
|
|
|
|
{
|
|
|
|
$this->userManager->callForSeenUsers(function ($user) {
|
|
|
|
try {
|
|
|
|
$this->service->indexUser($user->getUID());
|
|
|
|
} catch (Service\ProcessClosedException $e) {
|
|
|
|
throw $e;
|
|
|
|
} catch (\Exception $e) {
|
2023-04-17 01:47:26 +00:00
|
|
|
$this->log('Indexing failed for user '.$user->getUID().': '.$e->getMessage());
|
2023-04-17 01:07:57 +00:00
|
|
|
} catch (\Throwable $e) {
|
2023-04-17 01:47:26 +00:00
|
|
|
$this->log('[BUG] uncaught exception: '.$e->getMessage());
|
2023-04-17 01:07:57 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2023-04-17 01:47:26 +00:00
|
|
|
|
|
|
|
private function log(string $msg, string $type = 'error'): void
|
|
|
|
{
|
2023-04-23 09:53:38 +00:00
|
|
|
if ('success' === $type || 'info' === $type) {
|
|
|
|
// If this is just an informational message, we log it with level info
|
2023-10-22 19:07:22 +00:00
|
|
|
$this->logger->info($msg, ['app' => Application::APPNAME]);
|
2023-04-23 09:53:38 +00:00
|
|
|
}
|
|
|
|
|
2023-04-17 01:47:26 +00:00
|
|
|
if ($this->_hasError && 'success' === $type) {
|
|
|
|
// Don't overwrite an error with a success
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->config->setAppValue(Application::APPNAME, 'last_index_job_status', $msg);
|
|
|
|
$this->config->setAppValue(Application::APPNAME, 'last_index_job_status_type', $type);
|
|
|
|
|
2023-04-23 09:53:38 +00:00
|
|
|
if ('warning' === $type) {
|
2023-10-22 19:07:22 +00:00
|
|
|
$this->logger->warning($msg, ['app' => Application::APPNAME]);
|
2023-04-17 01:47:26 +00:00
|
|
|
} elseif ('error' === $type) {
|
|
|
|
$this->_hasError = true;
|
2023-10-22 19:07:22 +00:00
|
|
|
$this->logger->error($msg, ['app' => Application::APPNAME]);
|
2023-04-17 01:47:26 +00:00
|
|
|
}
|
|
|
|
}
|
2023-04-17 01:07:57 +00:00
|
|
|
}
|