argument('filename'); $filename = basename($exportFile); if ($filename === $exportFile) { $exportFullFileName = $defaultExportPath . '/' . $filename; $exportPath = $defaultExportPath; } else { $exportFullFileName = $exportFile; $exportPath = dirname($exportFile); } $format = $this->argument('format') ?? 'gz'; if (!file_exists($exportFullFileName)) { Log::error('export offline: file not exists', [ 'file' => $exportFullFileName ]); $this->error('file not exists: ' . $exportFullFileName); return 1; } $zipFile = $this->getZipFileName($filename, $format); $zipFullFileName = $exportPath . '/' . $zipFile; if (file_exists($zipFullFileName)) { unlink($zipFullFileName); } $this->info("start compress: {$exportFullFileName}"); Log::debug('export offline zip start', [ 'file' => $exportFullFileName, 'format' => $format ]); $this->compress($exportFullFileName, $zipFullFileName, $format); $this->info('压缩完成'); Log::debug('zip done', [ 'zip' => $zipFullFileName ]); /* |-------------------------------------------------------------------------- | 上传 S3 |-------------------------------------------------------------------------- */ $bucket = config('mint.attachments.bucket_name.temporary'); $tmpFile = $bucket . '/' . $zipFile; $this->info('upload file=' . $tmpFile); Log::debug('export offline upload', [ 'file' => $tmpFile ]); Storage::put($tmpFile, fopen($zipFullFileName, 'r')); $this->info('upload done'); Log::debug('upload done'); /* |-------------------------------------------------------------------------- | 生成下载链接 |-------------------------------------------------------------------------- */ if (App::environment('local')) { $link = Storage::url($tmpFile); } else { try { $link = Storage::temporaryUrl( $tmpFile, now()->addDays(2) ); } catch (\Exception $e) { Log::error('temporaryUrl fail', [ 'exception' => $e ]); $this->error('generate temporaryUrl fail'); return 1; } } $this->info('link=' . $link); /* |-------------------------------------------------------------------------- | CDN 列表 |-------------------------------------------------------------------------- */ $url = []; foreach (config('mint.server.cdn_urls') as $key => $cdn) { $url[] = [ 'link' => $cdn . '/' . $zipFile, 'hostname' => 'china cdn-' . $key ]; } $url[] = [ 'link' => $link, 'hostname' => 'Amazon cloud storage(Hongkong)' ]; /* |-------------------------------------------------------------------------- | Cache 写入 |-------------------------------------------------------------------------- */ $info = Cache::get('/offline/index', []); if (!is_array($info)) { $info = []; } $id = $this->argument('id'); // 先移除已有相同 id 的记录 $info = array_values(array_filter($info, function ($item) use ($id) { return !isset($item['id']) || $item['id'] != $id; })); // 再追加新数据 $info[] = [ 'id' => $id, 'title' => $this->argument('title'), 'filename' => $zipFile, 'url' => $url, 'create_at' => now()->toDateTimeString(), 'chapter' => Cache::get("/export/chapter/count"), 'filesize' => filesize($zipFullFileName), 'min_app_ver' => '1.3', ]; Cache::put('/offline/index', $info); /* |-------------------------------------------------------------------------- | 删除原始文件 |-------------------------------------------------------------------------- */ sleep(5); try { if (is_file($exportFullFileName)) { unlink($exportFullFileName); } if (file_exists($zipFullFileName)) { unlink($zipFullFileName); } } catch (\Throwable $e) { Log::error('delete source fail', [ 'exception' => $e ]); } return 0; } /* |-------------------------------------------------------------------------- | 生成压缩文件名 |-------------------------------------------------------------------------- */ protected function getZipFileName(string $filename, string $format): string { return match ($format) { '7z' => $filename . '.7z', 'lzma' => $filename . '.lzma', default => $filename . '.tar.gz' }; } /* |-------------------------------------------------------------------------- | 压缩函数 |-------------------------------------------------------------------------- */ protected function compress($source, $target, $format) { $isDir = is_dir($source); switch ($format) { case '7z': $command = [ '7z', 'a', '-t7z', '-mx=9', $target, $source ]; break; case 'lzma': if ($isDir) { $tmpTar = $source . '.tar'; $tar = new Process([ 'tar', '-cf', $tmpTar, '-C', dirname($source), basename($source) ]); $tar->run(); $source = $tmpTar; } $command = [ 'xz', '-k', '-9', '--format=lzma', $source ]; break; default: $command = [ 'tar', '-czf', $target, '-C', dirname($source), basename($source) ]; } $this->info(implode(' ', $command)); $process = new Process($command); $process->setTimeout(60 * 60 * 6); $process->run(); $this->info($process->getOutput()); if (!$process->isSuccessful()) { Log::error('compress fail', [ 'error' => $process->getErrorOutput() ]); throw new \RuntimeException($process->getErrorOutput()); } } }