repository = $repo; $this->runner = new BackupRunner( $repo, $storage ?? new WpObjectStorage(), $webhooks ?? new WebhookSender(), $retention ?? new RetentionPolicy($repo), $database ?? new WpDatabaseDumper(), $crypto ?? new WpCrypto(), $files, $config, $logger, $manifest ?? new BackupManifest(new WpInventory(), new WpPlatformProbe(), $config), new ArchiveBuilder($files, new WpCache(), $logger), ); } /** * @param array $options */ public function createBackup(array $options, ?int $existingBackupId = null): int { return $this->runner->createBackup(self::withOwnStorageExcluded($options), $existingBackupId); } /** * Les dossiers de l'agent n'entrent dans aucune sauvegarde. * * Dans l'edition wordpress.org ils vivent sous uploads/sentinelo/, qui fait partie * des fichiers sauvegardes : sans cette exclusion, chaque sauvegarde emporterait * l'archive en cours d'ecriture de la precedente, et grossirait de toutes les * autres. L'edition privee les range sous wp-content/sentinelo-*, hors des roles * archives ; on les exclut quand meme, pour un site passe d'une edition a l'autre. * * Le motif est le chemin relatif a la racine du site — ce que compare * l'ArchiveBuilder —, ou le chemin complet quand le dossier vit hors de celle-ci. * * @param array $options * @return array */ public static function withOwnStorageExcluded(array $options): array { $root = untrailingslashit(wp_normalize_path(ABSPATH)); $own = array_map( static fn (string $dir): string => str_starts_with($dir, $root . '/') ? substr($dir, strlen($root) + 1) : $dir, sentinelo_storage_roots() ); $options['exclude_paths'] = array_values(array_unique(array_merge( array_map('strval', (array) ($options['exclude_paths'] ?? [])), $own ))); return $options; } /** * {@see SafetyBackupMaker}: the pre-restore snapshot. * * @param list $includes */ /** * Reprend l'envoi de la sauvegarde en cours, s'il en reste un. * * Appelée par le planificateur toutes les cinq minutes. Le cas ordinaire est * qu'il n'y ait rien en attente — on sort alors sans rien faire. * * On ne cherche que la sauvegarde en cours : deux envois simultanés se * disputeraient la bande passante d'un hébergement déjà lent, et l'agent * n'en autorise de toute façon qu'une à la fois. */ public function resumePendingUpload(): ?int { $inProgress = $this->repository->findInProgressId(); if (null === $inProgress) { return null; } return $this->runner->resumeUpload($inProgress); } /** * Reprend la construction d'archive en cours, s'il en reste une. * * Même cadence et même raisonnement que {@see self::resumePendingUpload()} : * le cas ordinaire est qu'il n'y ait rien à faire, et on ne s'occupe que de * la sauvegarde en cours — l'agent n'en autorise qu'une à la fois. */ /** * Libère une sauvegarde abandonnée par la plateforme. Voir BackupRunner::abandon(). * * @return array{backup_id: int, status: string, abandoned: bool, staging_removed: bool, upload_aborted: bool} */ public function abandon(int $backupId, string $reason): array { return $this->runner->abandon($backupId, $reason); } public function resumePendingArchive(): ?int { $inProgress = $this->repository->findInProgressId(); if (null === $inProgress) { return null; } return $this->runner->resumeArchive($inProgress); } public function createSafetyBackup(array $includes, string $comment): int { // Memes options que BackupRunner::createSafetyBackup(), mais par createBackup() // pour que l'exclusion des dossiers de l'agent s'applique aussi ici. return $this->createBackup([ 'type' => 'safety', 'includes' => $includes, 'cloud_upload' => true, 'comment' => $comment, ]); } }