File "AssociateProductMedia.php"

Full Path: /home/clickysoft/public_html/jmapi5.clickysoft.net/app/Jobs/AssociateProductMedia.php
File size: 6.85 KB
MIME-type: text/x-php
Charset: utf-8

<?php

namespace App\Jobs;

use App\Http\Controllers\Traits\MediaUploadingTrait;
use App\Models\Product;
use App\Models\ProductPrice;
use App\Models\TempProductUrl;
use GuzzleHttp\Client;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Http\UploadedFile;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\ThrottlesExceptions;
use Illuminate\Queue\SerializesModels;

class AssociateProductMedia implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MediaUploadingTrait;

    public int $timeout = 120;
    public int $ipIndex = 0;

    //These are being used in order to avoid throttling by google
    public const USA_IPS = [
        '23.129.64.202', // New York
        '45.33.109.244', // Dallas
        '45.79.202.233', // Fremont
        '23.239.23.148', // Atlanta
        '192.155.85.170', // Los Angeles
        '23.129.64.197', // New York
        '96.8.120.196', // Chicago
        '96.8.120.227', // Chicago
        '96.8.120.201', // Chicago
        '45.79.202.94', // Fremont
        '192.99.68.31', // Canada, but commonly used as US proxy
        '192.99.68.167', // Canada, but commonly used as US proxy
        '192.99.68.145', // Canada, but commonly used as US proxy
        '192.99.68.162', // Canada, but commonly used as US proxy
        '192.99.68.164', // Canada, but commonly used as US proxy
        '192.99.68.166', // Canada, but commonly used as US proxy
        '192.99.68.170', // Canada, but commonly used as US proxy
        '192.99.68.175', // Canada, but commonly used as US proxy
        '192.99.68.180', // Canada, but commonly used as US proxy
        '192.99.68.182', // Canada, but commonly used as US proxy
        '192.99.68.186', // Canada, but commonly used as US proxy
        '192.99.68.188', // Canada, but commonly used as US proxy
        '192.99.68.191', // Canada, but commonly used as US proxy
        '192.99.68.194', // Canada, but commonly used as US proxy
        '192.99.68.197', // Canada, but commonly used as US proxy
        '192.99.68.199', // Canada, but commonly used as US proxy
        '192.99.68.201', // Canada, but commonly used as US proxy
        '192.99.68.203', // Canada, but commonly used as US proxy
        '192.99.68.206', // Canada, but commonly used as US proxy
    ];

    /*public function middleware(): array
    {
        return [new ThrottlesExceptions(10, 5)];
    }*/

    public function __construct()
    {
        //
    }

    public function handle()
    {

        \Log::channel('import_logs')->info('Association job started');
        $records = TempProductUrl::all();
        foreach ($records as $record) {
            \Log::channel('import_logs')->info('Now handling :'. $record->id);

            $response = $this->handleRecordRecursively($record);
//            $response = $this->downloadImageFromGoogleDrive($record);
            if ($response) {
//                $record->delete();
                \Log::channel('import_logs')->info("Model id : {$record->model_id} => {$record->type} associated successfully.");
            } else {
                \Log::channel('import_logs')->info("Model id : {$record->model_id} => {$record->type} associated failed.");
            }
            //Delay execution for quarter second in order to avoid google rate limiting
            usleep(25000000);
        }
        \Log::channel('import_logs')->info('Association job finished');

    }

    public function handleRecordRecursively($record)
    {
        $response = $this->downloadImageFromGoogleDrive($record);
        if ($response) return true; //Successfully associated record
        $this->updateIpIndex();
        if ($this->ipIndex == count(self::USA_IPS) - 1) //Failed after trying all IPs
            return false;
        else
            $this->handleRecordRecursively($record); //Try with another IP
    }

    public function downloadImageFromGoogleDrive($rec): bool
    {

        preg_match('/\/d\/(.*?)\//', $rec->url, $matches);

        $fileId = $matches[1] ?? ''; //Check here

        // Download the file using GuzzleHttp
        $headers = [
            'X-Forwarded-For' =>self::USA_IPS[$this->ipIndex], // Replace with the IP address you want to send
            'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
        ];
        $client = new Client([
            'base_uri' => 'https://drive.google.com',
            'headers' => $headers,
        ]);

        try {
            $response = $client->get("/uc?id={$fileId}&export=download");
            $contentDisposition = $response->getHeaderLine('Content-Disposition');
            preg_match('/filename="(.+)"/', $contentDisposition, $matches);
            $filename = $matches[1] ?? '';

            if ($filename){
                // Save the file to Laravel storage directory
                $fileContents = $response->getBody()->getContents();
                \Storage::disk('public')->put($filename, $fileContents);

                return $this->associateFile($rec, $filename);
            } else {
                return false;
            }

        } catch (\Exception $e) {
            \Log::channel('import_logs')->info($rec->type.' association failed for model id => '. $rec->model_id);
            \Log::channel('import_logs')->info($e->getMessage());
            \Log::channel('import_logs')->info("IP : ". self::USA_IPS[$this->ipIndex]);
            return false;
        }
    }

    public function associateFile($rec, $filename): bool
    {
        if ($rec->type == 'image') {
            $product = Product::find($rec->model_id);
            if (!file_exists(public_path('storage/'. $filename))) return false;

            //Delete old image of product
            if (!empty($product->featured_image)) {
                $product->clearMediaCollection('product_featured_image');
            }

            $product->addMedia(public_path('storage/'.$filename))
                ->toMediaCollection('product_featured_image', 'product')
                ->save();
        } else {
            $product_price = ProductPrice::find($rec->model_id);
            if (!file_exists(public_path('storage/'. $filename))) return false;
            \Log::channel('import_logs')->info(public_path('storage/'. $filename));
            $file = new UploadedFile(public_path('storage/'.$filename), $filename);

            $product_price->product_sketch = $this->storePDF($file, $product_price->product->featured_image->id, 'product');
            \Log::channel('import_logs')->info('Sketch : '.$product_price->product_sketch);
            $product_price->save();
        }
        return true;
    }

    public function updateIpIndex(): void
    {
        $this->ipIndex == count(self::USA_IPS) - 1 ? $this->ipIndex = 0 : $this->ipIndex++;
    }
}