Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
namespace Aws\S3;
3
 
4
use Aws\Arn\ArnParser;
5
use Aws\Arn\S3\AccessPointArn;
6
use Aws\Exception\MultipartUploadException;
7
use Aws\Result;
8
use Aws\S3\Exception\S3Exception;
9
use GuzzleHttp\Promise\Coroutine;
1441 ariadna 10
use GuzzleHttp\Promise\PromiseInterface;
1 efrain 11
use GuzzleHttp\Promise\PromisorInterface;
12
use InvalidArgumentException;
13
 
14
/**
15
 * Copies objects from one S3 location to another, utilizing a multipart copy
16
 * when appropriate.
17
 */
18
class ObjectCopier implements PromisorInterface
19
{
20
    const DEFAULT_MULTIPART_THRESHOLD = MultipartUploader::PART_MAX_SIZE;
21
 
22
    private $client;
23
    private $source;
24
    private $destination;
25
    private $acl;
26
    private $options;
27
 
28
    private static $defaults = [
29
        'before_lookup' => null,
30
        'before_upload' => null,
31
        'concurrency'   => 5,
32
        'mup_threshold' => self::DEFAULT_MULTIPART_THRESHOLD,
33
        'params'        => [],
34
        'part_size'     => null,
35
        'version_id'    => null,
36
    ];
37
 
38
    /**
39
     * @param S3ClientInterface $client         The S3 Client used to execute
40
     *                                          the copy command(s).
41
     * @param array             $source         The object to copy, specified as
42
     *                                          an array with a 'Bucket' and
43
     *                                          'Key' keys. Provide a
44
     *                                          'VersionID' key to copy a
45
     *                                          specified version of an object.
46
     * @param array             $destination    The bucket and key to which to
47
     *                                          copy the $source, specified as
48
     *                                          an array with a 'Bucket' and
49
     *                                          'Key' keys.
50
     * @param string            $acl            ACL to apply to the copy
51
     *                                          (default: private).
52
     * @param array             $options        Options used to configure the
53
     *                                          copy process. Options passed in
54
     *                                          through 'params' are added to
55
     *                                          the sub commands.
56
     *
57
     * @throws InvalidArgumentException
58
     */
59
    public function __construct(
60
        S3ClientInterface $client,
61
        array $source,
62
        array $destination,
63
        $acl = 'private',
64
        array $options = []
65
    ) {
66
        $this->validateLocation($source);
67
        $this->validateLocation($destination);
68
 
69
        $this->client = $client;
70
        $this->source = $source;
71
        $this->destination = $destination;
72
        $this->acl = $acl;
73
        $this->options = $options + self::$defaults;
74
    }
75
 
76
    /**
77
     * Perform the configured copy asynchronously. Returns a promise that is
78
     * fulfilled with the result of the CompleteMultipartUpload or CopyObject
79
     * operation or rejected with an exception.
80
     *
81
     * @return Coroutine
82
     */
1441 ariadna 83
    public function promise(): PromiseInterface
1 efrain 84
    {
85
        return Coroutine::of(function () {
86
            $headObjectCommand = $this->client->getCommand(
87
                'HeadObject',
88
                $this->options['params'] + $this->source
89
            );
90
            if (is_callable($this->options['before_lookup'])) {
91
                $this->options['before_lookup']($headObjectCommand);
92
            }
93
            $objectStats = (yield $this->client->executeAsync(
94
                $headObjectCommand
95
            ));
96
 
97
            if ($objectStats['ContentLength'] > $this->options['mup_threshold']) {
98
                $mup = new MultipartCopy(
99
                    $this->client,
100
                    $this->getSourcePath(),
101
                    ['source_metadata' => $objectStats, 'acl' => $this->acl]
102
                        + $this->destination
103
                        + $this->options
104
                );
105
 
106
                yield $mup->promise();
107
            } else {
108
                $defaults = [
109
                    'ACL' => $this->acl,
110
                    'MetadataDirective' => 'COPY',
111
                    'CopySource' => $this->getSourcePath(),
112
                ];
113
 
114
                $params = array_diff_key($this->options, self::$defaults)
115
                    + $this->destination + $defaults + $this->options['params'];
116
 
117
                yield $this->client->executeAsync(
118
                    $this->client->getCommand('CopyObject', $params)
119
                );
120
            }
121
        });
122
    }
123
 
124
    /**
125
     * Perform the configured copy synchronously. Returns the result of the
126
     * CompleteMultipartUpload or CopyObject operation.
127
     *
128
     * @return Result
129
     *
130
     * @throws S3Exception
131
     * @throws MultipartUploadException
132
     */
133
    public function copy()
134
    {
135
        return $this->promise()->wait();
136
    }
137
 
138
    private function validateLocation(array $location)
139
    {
140
        if (empty($location['Bucket']) || empty($location['Key'])) {
141
            throw new \InvalidArgumentException('Locations provided to an'
142
                . ' Aws\S3\ObjectCopier must have a non-empty Bucket and Key');
143
        }
144
    }
145
 
146
    private function getSourcePath()
147
    {
148
        $path = "/{$this->source['Bucket']}/";
149
        if (ArnParser::isArn($this->source['Bucket'])) {
150
            try {
151
                new AccessPointArn($this->source['Bucket']);
152
                $path = "{$this->source['Bucket']}/object/";
153
            } catch (\Exception $e) {
154
                throw new \InvalidArgumentException(
155
                    'Provided ARN was a not a valid S3 access point ARN ('
156
                    . $e->getMessage() . ')',
157
                    0,
158
                    $e
159
                );
160
            }
161
        }
162
 
163
        $sourcePath = $path . rawurlencode($this->source['Key']);
164
        if (isset($this->source['VersionId'])) {
165
            $sourcePath .= "?versionId={$this->source['VersionId']}";
166
        }
167
 
168
        return $sourcePath;
169
    }
170
}