$id, 'tipo' => $tipo, 'status' => 'queued', 'fase' => $fase, 'total' => $total, 'processed' => 0, 'logs' => [], 'result' => [], 'error' => null, 'started_at' => null, 'finished_at' => null, ]; $this->put($id, $state); return $state; } public function get(string $id): ?array { return Cache::get($this->key($id)); } public function put(string $id, array $state): void { Cache::put($this->key($id), $state, $this->ttlSeconds); } public function forget(string $id): void { Cache::forget($this->key($id)); } public function update(string $id, callable $callback): ?array { $state = $this->get($id); if (! $state) { return null; } $state = $callback($state) ?? $state; $this->put($id, $state); return $state; } public function log(string $id, string $message): void { $this->update($id, function (array $state) use ($message) { $state['logs'][] = '[' . now()->format('H:i:s') . '] ' . $message; $state['logs'] = array_slice($state['logs'], -self::MAX_LOG); return $state; }); } /** * Cambia fase e, insieme, il totale di riferimento: ogni fase ha una sua * unita' di misura (file da comprimere, file da estrarre, passi di * cancellazione) e la barra riparte da zero su quel totale. */ public function fase(string $id, string $fase, int $total = 0): void { $this->update($id, function (array $state) use ($fase, $total) { $state['fase'] = $fase; $state['total'] = $total; $state['processed'] = 0; return $state; }); $this->log($id, $fase . ($total > 0 ? ' (' . $total . ')' : '')); } public function avanza(string $id, int $processed, ?int $total = null): void { $this->update($id, function (array $state) use ($processed, $total) { $state['processed'] = $processed; if ($total !== null) { $state['total'] = $total; } return $state; }); } public function markRunning(string $id): void { $this->update($id, function (array $state) { $state['status'] = 'running'; $state['started_at'] ??= now()->toDateTimeString(); return $state; }); } public function markCompleted(string $id, array $result = []): void { $this->update($id, function (array $state) use ($result) { $state['status'] = 'completed'; $state['processed'] = max($state['processed'], $state['total']); $state['result'] = $result + $state['result']; $state['finished_at'] = now()->toDateTimeString(); return $state; }); } public function markFailed(string $id, string $error): void { $this->update($id, function (array $state) use ($error) { $state['status'] = 'failed'; $state['error'] = $error; $state['finished_at'] = now()->toDateTimeString(); return $state; }); $this->log($id, 'ERRORE: ' . $error); } /** * L'archivio e' pronto ma non si prosegue: l'azzeramento parte solo quando * il download risulta consegnato per intero. */ public function markAttesaDownload(string $id, array $result): void { $this->update($id, function (array $state) use ($result) { $state['status'] = 'running'; $state['fase'] = self::FASE_ATTESA_DOWNLOAD; $state['processed'] = $state['total']; $state['result'] = $result + $state['result']; return $state; }); } protected function key(string $id): string { return 'backup-op:' . $id; } }