ImageS3UploadPipeline.php 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. <?php
  2. namespace App\Jobs\GroupsPipeline;
  3. use App\Models\GroupMedia;
  4. use App\Util\Media\Image;
  5. use Illuminate\Bus\Queueable;
  6. use Illuminate\Contracts\Queue\ShouldQueue;
  7. use Illuminate\Foundation\Bus\Dispatchable;
  8. use Illuminate\Queue\InteractsWithQueue;
  9. use Illuminate\Queue\SerializesModels;
  10. use Storage;
  11. use Illuminate\Http\File;
  12. use Exception;
  13. use GuzzleHttp\Exception\ClientException;
  14. use Aws\S3\Exception\S3Exception;
  15. use GuzzleHttp\Exception\ConnectException;
  16. use League\Flysystem\UnableToWriteFile;
  17. class ImageS3UploadPipeline implements ShouldQueue
  18. {
  19. use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
  20. protected $media;
  21. static $attempts = 1;
  22. /**
  23. * Delete the job if its models no longer exist.
  24. *
  25. * @var bool
  26. */
  27. public $deleteWhenMissingModels = true;
  28. /**
  29. * Create a new job instance.
  30. *
  31. * @return void
  32. */
  33. public function __construct(GroupMedia $media)
  34. {
  35. $this->media = $media;
  36. }
  37. /**
  38. * Execute the job.
  39. *
  40. * @return void
  41. */
  42. public function handle()
  43. {
  44. $media = $this->media;
  45. if(!$media || (bool) config_cache('pixelfed.cloud_storage') === false) {
  46. return;
  47. }
  48. $path = storage_path('app/' . $media->media_path);
  49. $p = explode('/', $media->media_path);
  50. $name = array_pop($p);
  51. $storagePath = implode('/', $p);
  52. $url = (bool) config_cache('pixelfed.cloud_storage') && (bool) config('media.storage.remote.resilient_mode') ?
  53. self::handleResilientStore($storagePath, $path, $name) :
  54. self::handleStore($storagePath, $path, $name);
  55. if($url && strlen($url) && str_starts_with($url, 'https://')) {
  56. $media->cdn_url = $url;
  57. $media->processed_at = now();
  58. $media->version = 11;
  59. $media->save();
  60. Storage::disk('local')->delete($media->media_path);
  61. }
  62. }
  63. protected function handleStore($storagePath, $path, $name)
  64. {
  65. return retry(3, function() use($storagePath, $path, $name) {
  66. $baseDisk = (bool) config_cache('pixelfed.cloud_storage') ? config('filesystems.cloud') : 'local';
  67. $disk = Storage::disk($baseDisk);
  68. $file = $disk->putFileAs($storagePath, new File($path), $name, 'public');
  69. return $disk->url($file);
  70. }, random_int(100, 500));
  71. }
  72. protected function handleResilientStore($storagePath, $path, $name)
  73. {
  74. $attempts = 0;
  75. return retry(4, function() use($storagePath, $path, $name, $attempts) {
  76. self::$attempts++;
  77. usleep(100000);
  78. $baseDisk = self::$attempts > 1 ? $this->getAltDriver() : config('filesystems.cloud');
  79. try {
  80. $disk = Storage::disk($baseDisk);
  81. $file = $disk->putFileAs($storagePath, new File($path), $name, 'public');
  82. } catch (S3Exception | ClientException | ConnectException | UnableToWriteFile | Exception $e) {}
  83. return $disk->url($file);
  84. }, function (int $attempt, Exception $exception) {
  85. return $attempt * 200;
  86. });
  87. }
  88. protected function getAltDriver()
  89. {
  90. return config('filesystems.cloud');
  91. }
  92. }