Browse Source

chunked upload

moell 7 months ago
parent
commit
9ed57a5899

+ 3 - 0
app/Exceptions/Handler.php

@@ -3,6 +3,7 @@
 namespace App\Exceptions;
 
 use App\Http\Controllers\JsonResponseHelper;
+use App\Libraries\ChunkedUpload\Exceptions\UploadFailedException;
 use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
 use Throwable;
 
@@ -29,10 +30,12 @@ class Handler extends ExceptionHandler
         $this->reportable(function (Throwable $e) {
             return match (get_class($e)) {
                 ValidationException::class => false,
+                UploadFailedException::class => false,
                 default => true,
             };
         });
 
         $this->renderable(fn(ValidationException $e) => $this->unprocesableEtity($e->getErrors(), message: $e->getMessage()));
+        $this->renderable(fn(ValidationException $e) => $this->badRequest($e->getMessage()));
     }
 }

+ 20 - 0
app/Libraries/ChunkedUpload/ChunkedUploadFactory.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Libraries\ChunkedUpload;
+
+use App\Libraries\ChunkedUpload\Contacts\ChunkedUploadContact;
+use App\Libraries\ChunkedUpload\Disks\Cos;
+use App\Libraries\ChunkedUpload\Disks\StandardDrive;
+
+class ChunkedUploadFactory
+{
+    public static function make(string $disk = null): ChunkedUploadContact
+    {
+        $disk = $disk ?: config("filesystems.default");
+
+        return match ($disk) {
+            "cos" => new Cos(),
+            default => new StandardDrive(),
+        };
+    }
+}

+ 18 - 0
app/Libraries/ChunkedUpload/Contacts/ChunkedUploadContact.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace App\Libraries\ChunkedUpload\Contacts;
+
+use App\Services\File\Upload\ProgressBar;
+use Illuminate\Http\UploadedFile;
+
+interface ChunkedUploadContact
+{
+    /**
+     * @param UploadedFile $file
+     * @param string $savePath
+     * @param string $name
+     * @param ProgressBar|null $progressBar 进度条
+     * @return mixed
+     */
+    public function upload(UploadedFile $file, string $savePath, string $name, ?ProgressBar $progressBar): string;
+}

+ 59 - 0
app/Libraries/ChunkedUpload/Disks/Cos.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace App\Libraries\ChunkedUpload\Disks;
+
+use App\Libraries\ChunkedUpload\Contacts\ChunkedUploadContact;
+use App\Libraries\ChunkedUpload\Exceptions\UploadFailedException;
+use App\Services\File\Upload\ProgressBar;
+use Illuminate\Http\UploadedFile;
+use Illuminate\Support\Facades\Log;
+use Qcloud\Cos\Client;
+
+class Cos implements ChunkedUploadContact
+{
+    public function upload(UploadedFile $file, string $savePath, string $name, ?ProgressBar $progressBar): string
+    {
+        $pathname = sprintf("%s/%s", $savePath, $name);
+
+        $cosClient = new Client([
+            'region' => config('filesystems.disks.cos.region'),
+            'credentials' => [
+                'secretId' => config('filesystems.disks.cos.secret_id'),
+                'secretKey' => config('filesystems.disks.cos.secret_key')
+            ]
+        ]);
+
+        try {
+            $notUploadedSize = $file->getSize();
+
+            $options = [
+                'PartSize' => 5 * 1024 * 1024,
+                'Progress' => function ($totalSize, $uploadedSize) use (&$notUploadedSize, $progressBar) {
+                    $partSize = $uploadedSize - ($totalSize - $notUploadedSize);
+
+                    $notUploadedSize = $totalSize - $uploadedSize;
+
+                    $progressBar?->increment($partSize);
+                },
+                'ACL' => 'private',
+            ];
+
+            $cosClient->upload(
+                sprintf("%s-%s", config('filesystems.disks.cos.bucket'), config('filesystems.disks.cos.app_id')),
+                $pathname,
+                fopen($file->getRealPath(),  'rb'),
+                $options,
+            );
+
+            if ($notUploadedSize > 0) {
+                $progressBar?->increment($notUploadedSize);
+            }
+        } catch (\Exception $exception) {
+            Log::error($exception->getTraceAsString());
+
+            throw new UploadFailedException("File upload failed.");
+        }
+
+        return $pathname;
+    }
+}

+ 19 - 0
app/Libraries/ChunkedUpload/Disks/StandardDrive.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace App\Libraries\ChunkedUpload\Disks;
+
+use App\Libraries\ChunkedUpload\Contacts\ChunkedUploadContact;
+use App\Services\File\Upload\ProgressBar;
+use Illuminate\Http\UploadedFile;
+
+class StandardDrive implements ChunkedUploadContact
+{
+    public function upload(UploadedFile $file, string $savePath, string $name, ?ProgressBar $progressBar): string
+    {
+        $pathname = $file->storeAs($savePath, $name);
+
+        $progressBar?->increment($file->getSize());
+
+        return $pathname;
+    }
+}

+ 10 - 0
app/Libraries/ChunkedUpload/Exceptions/UploadFailedException.php

@@ -0,0 +1,10 @@
+<?php
+
+namespace App\Libraries\ChunkedUpload\Exceptions;
+
+
+
+class UploadFailedException extends \Exception
+{
+
+}

+ 8 - 7
app/Services/File/Upload/FilesUploadTrait.php

@@ -4,6 +4,7 @@ namespace App\Services\File\Upload;
 
 use App\Http\Resources\API\FileUploadSuccessResource;
 use App\Libraries\BIM\BIMFactory;
+use App\Libraries\ChunkedUpload\ChunkedUploadFactory;
 use App\Models\BimFile;
 use App\Models\ContainerContent;
 use App\Models\Enums\FileObjectType;
@@ -43,15 +44,17 @@ trait FilesUploadTrait
 
     protected function uploadFile(Request $request, UploadedFile $file, ?ProgressBar $progressBar = null): array
     {
-        $extension = $file->getClientOriginalExtension() ? $file->getClientOriginalExtension(): pathinfo($file->getClientOriginalName(), PATHINFO_EXTENSION);
+        $extension = $file->getClientOriginalExtension()
+            ? $file->getClientOriginalExtension()
+            : pathinfo($file->getClientOriginalName(), PATHINFO_EXTENSION);
 
-        $pathname = $file->storeAs(
+        $pathname = ChunkedUploadFactory::make()->upload(
+            $file,
             sprintf("c%s/%s/%s", Auth::user()->company_id, $request->get("object_type"), date("Ymd")),
-            sprintf("%s.%s", md5(uniqid()), $extension)
+            sprintf("%s.%s", md5(uniqid()), $extension),
+            $progressBar
         );
 
-        $progressBar?->increment($file->getSize());
-
         $data = [
             'bim' => [],
         ];
@@ -66,8 +69,6 @@ trait FilesUploadTrait
             ]);
         }
 
-        throw_validation_if(! $pathname, "File upload failed.");
-
         $data['file'] = [
             'pathname' => $pathname,
             'title' => $file->getClientOriginalName(),

+ 1 - 0
composer.json

@@ -16,6 +16,7 @@
         "maatwebsite/excel": "^3.1",
         "overtrue/laravel-filesystem-cos": "^3.4",
         "overtrue/laravel-query-logger": "^3.1",
+        "qcloud/cos-sdk-v5": "^2.6",
         "spatie/laravel-permission": "^6.3",
         "tucker-eric/eloquentfilter": "^3.2"
     },

+ 240 - 1
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "9d1e003a2024b3520c11d581802c63fb",
+    "content-hash": "a2ce1c7c3733e1f8702ee315121eb0be",
     "packages": [
         {
             "name": "aliyuncs/oss-sdk-php",
@@ -954,6 +954,89 @@
             ],
             "time": "2023-11-12T22:16:48+00:00"
         },
+        {
+            "name": "guzzlehttp/command",
+            "version": "1.3.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/guzzle/command.git",
+                "reference": "0eebc653784f4902b3272e826fe8e88743d14e77"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/guzzle/command/zipball/0eebc653784f4902b3272e826fe8e88743d14e77",
+                "reference": "0eebc653784f4902b3272e826fe8e88743d14e77",
+                "shasum": ""
+            },
+            "require": {
+                "guzzlehttp/guzzle": "^7.8",
+                "guzzlehttp/promises": "^1.5.3 || ^2.0.1",
+                "guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
+                "php": "^7.2.5 || ^8.0"
+            },
+            "require-dev": {
+                "bamarni/composer-bin-plugin": "^1.8.2",
+                "phpunit/phpunit": "^8.5.19 || ^9.5.8"
+            },
+            "type": "library",
+            "extra": {
+                "bamarni-bin": {
+                    "bin-links": true,
+                    "forward-command": false
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "GuzzleHttp\\Command\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Graham Campbell",
+                    "email": "hello@gjcampbell.co.uk",
+                    "homepage": "https://github.com/GrahamCampbell"
+                },
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                },
+                {
+                    "name": "Jeremy Lindblom",
+                    "email": "jeremeamia@gmail.com",
+                    "homepage": "https://github.com/jeremeamia"
+                },
+                {
+                    "name": "Tobias Nyholm",
+                    "email": "tobias.nyholm@gmail.com",
+                    "homepage": "https://github.com/Nyholm"
+                }
+            ],
+            "description": "Provides the foundation for building command-based web service clients",
+            "support": {
+                "issues": "https://github.com/guzzle/command/issues",
+                "source": "https://github.com/guzzle/command/tree/1.3.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/GrahamCampbell",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/Nyholm",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/command",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2023-12-03T20:46:20+00:00"
+        },
         {
             "name": "guzzlehttp/guzzle",
             "version": "7.8.1",
@@ -1056,6 +1139,93 @@
             ],
             "time": "2023-12-03T20:35:24+00:00"
         },
+        {
+            "name": "guzzlehttp/guzzle-services",
+            "version": "1.4.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/guzzle/guzzle-services.git",
+                "reference": "bcab7c0d61672b606510a6fe5af3039d04968c0f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/guzzle/guzzle-services/zipball/bcab7c0d61672b606510a6fe5af3039d04968c0f",
+                "reference": "bcab7c0d61672b606510a6fe5af3039d04968c0f",
+                "shasum": ""
+            },
+            "require": {
+                "guzzlehttp/command": "^1.3.1",
+                "guzzlehttp/guzzle": "^7.8",
+                "guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
+                "guzzlehttp/uri-template": "^1.0.1",
+                "php": "^7.2.5 || ^8.0"
+            },
+            "require-dev": {
+                "bamarni/composer-bin-plugin": "^1.8.2",
+                "phpunit/phpunit": "^8.5.19 || ^9.5.8"
+            },
+            "suggest": {
+                "gimler/guzzle-description-loader": "^0.0.4"
+            },
+            "type": "library",
+            "extra": {
+                "bamarni-bin": {
+                    "bin-links": true,
+                    "forward-command": false
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "GuzzleHttp\\Command\\Guzzle\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Graham Campbell",
+                    "email": "hello@gjcampbell.co.uk",
+                    "homepage": "https://github.com/GrahamCampbell"
+                },
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                },
+                {
+                    "name": "Stefano Kowalke",
+                    "email": "blueduck@mail.org",
+                    "homepage": "https://github.com/Konafets"
+                },
+                {
+                    "name": "Tobias Nyholm",
+                    "email": "tobias.nyholm@gmail.com",
+                    "homepage": "https://github.com/Nyholm"
+                }
+            ],
+            "description": "Provides an implementation of the Guzzle Command library that uses Guzzle service descriptions to describe web services, serialize requests, and parse responses into easy to use model structures.",
+            "support": {
+                "issues": "https://github.com/guzzle/guzzle-services/issues",
+                "source": "https://github.com/guzzle/guzzle-services/tree/1.4.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/GrahamCampbell",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/Nyholm",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle-services",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2023-12-03T20:48:14+00:00"
+        },
         {
             "name": "guzzlehttp/promises",
             "version": "2.0.2",
@@ -3889,6 +4059,75 @@
             ],
             "time": "2023-10-14T21:56:36+00:00"
         },
+        {
+            "name": "qcloud/cos-sdk-v5",
+            "version": "v2.6.14",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/tencentyun/cos-php-sdk-v5.git",
+                "reference": "f59af74e7a45de259786e378e6b45cc61039caa3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/tencentyun/cos-php-sdk-v5/zipball/f59af74e7a45de259786e378e6b45cc61039caa3",
+                "reference": "f59af74e7a45de259786e378e6b45cc61039caa3",
+                "shasum": ""
+            },
+            "require": {
+                "ext-curl": "*",
+                "ext-json": "*",
+                "ext-libxml": "*",
+                "ext-mbstring": "*",
+                "ext-simplexml": "*",
+                "guzzlehttp/guzzle": "^6.2.1 || ^7.0",
+                "guzzlehttp/guzzle-services": "^1.1",
+                "guzzlehttp/psr7": "^1.3.1 || ^2.0",
+                "php": ">=5.6"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.4-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "src/Common.php"
+                ],
+                "psr-4": {
+                    "Qcloud\\Cos\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "yaozongyou",
+                    "email": "yaozongyou@vip.qq.com"
+                },
+                {
+                    "name": "lewzylu",
+                    "email": "327874225@qq.com"
+                },
+                {
+                    "name": "tuunalai",
+                    "email": "550566181@qq.com"
+                }
+            ],
+            "description": "PHP SDK for QCloud COS",
+            "keywords": [
+                "cos",
+                "php",
+                "qcloud"
+            ],
+            "support": {
+                "issues": "https://github.com/tencentyun/cos-php-sdk-v5/issues",
+                "source": "https://github.com/tencentyun/cos-php-sdk-v5/tree/v2.6.14"
+            },
+            "time": "2024-07-29T14:10:31+00:00"
+        },
         {
             "name": "ralouphie/getallheaders",
             "version": "3.0.3",

+ 1 - 1
lang/en/auth.php

@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 return [
     'ban'      => 'The current user has been blocked from logging in.',
-    'failed'   => 'The entered account or password is incorrect.',
+    'failed'   => 'These credentials do not match our records.',
     'password' => 'The password is incorrect.',
     'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
 ];