Passed
Push — master ( e165dc...217243 )
by Roeland
12:21 queued 10s
created

S3ObjectTrait::copyObject()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2017 Robin Appelman <[email protected]>
4
 *
5
 * @author Christoph Wurst <[email protected]>
6
 * @author Florent <[email protected]>
7
 * @author Morris Jobke <[email protected]>
8
 * @author Robin Appelman <[email protected]>
9
 * @author Roeland Jago Douma <[email protected]>
10
 *
11
 * @license GNU AGPL version 3 or any later version
12
 *
13
 * This program is free software: you can redistribute it and/or modify
14
 * it under the terms of the GNU Affero General Public License as
15
 * published by the Free Software Foundation, either version 3 of the
16
 * License, or (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License
24
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25
 *
26
 */
27
28
namespace OC\Files\ObjectStore;
29
30
use Aws\S3\Exception\S3MultipartUploadException;
31
use Aws\S3\MultipartUploader;
32
use Aws\S3\ObjectUploader;
33
use Aws\S3\S3Client;
34
use Icewind\Streams\CallbackWrapper;
35
use OC\Files\Stream\SeekableHttpStream;
36
37
trait S3ObjectTrait {
38
	/**
39
	 * Returns the connection
40
	 *
41
	 * @return S3Client connected client
42
	 * @throws \Exception if connection could not be made
43
	 */
44
	abstract protected function getConnection();
45
46
	/**
47
	 * @param string $urn the unified resource name used to identify the object
48
	 * @return resource stream with the read data
49
	 * @throws \Exception when something goes wrong, message will be logged
50
	 * @since 7.0.0
51
	 */
52
	public function readObject($urn) {
53
		return SeekableHttpStream::open(function ($range) use ($urn) {
0 ignored issues
show
Bug Best Practice introduced by
The expression return OC\Files\Stream\S...ion(...) { /* ... */ }) could also return false which is incompatible with the documented return type resource. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
54
			$command = $this->getConnection()->getCommand('GetObject', [
55
				'Bucket' => $this->bucket,
56
				'Key' => $urn,
57
				'Range' => 'bytes=' . $range,
58
			]);
59
			$request = \Aws\serialize($command);
60
			$headers = [];
61
			foreach ($request->getHeaders() as $key => $values) {
62
				foreach ($values as $value) {
63
					$headers[] = "$key: $value";
64
				}
65
			}
66
			$opts = [
67
				'http' => [
68
					'protocol_version' => 1.1,
69
					'header' => $headers,
70
				],
71
			];
72
73
			$context = stream_context_create($opts);
74
			return fopen($request->getUri(), 'r', false, $context);
75
		});
76
	}
77
78
	/**
79
	 * @param string $urn the unified resource name used to identify the object
80
	 * @param resource $stream stream with the data to write
81
	 * @throws \Exception when something goes wrong, message will be logged
82
	 * @since 7.0.0
83
	 */
84
	public function writeObject($urn, $stream) {
85
		$count = 0;
86
		$countStream = CallbackWrapper::wrap($stream, function ($read) use (&$count) {
87
			$count += $read;
88
		});
89
90
		$uploader = new MultipartUploader($this->getConnection(), $countStream, [
91
			'bucket' => $this->bucket,
92
			'key' => $urn,
93
			'part_size' => $this->uploadPartSize,
94
		]);
95
96
		try {
97
			$uploader->upload();
98
		} catch (S3MultipartUploadException $e) {
99
			// This is an empty file so just touch it then
100
			if ($count === 0 && feof($countStream)) {
101
				$uploader = new ObjectUploader($this->getConnection(), $this->bucket, $urn, '');
102
				$uploader->upload();
103
			} else {
104
				throw $e;
105
			}
106
		}
107
108
		fclose($countStream);
109
	}
110
111
	/**
112
	 * @param string $urn the unified resource name used to identify the object
113
	 * @return void
114
	 * @throws \Exception when something goes wrong, message will be logged
115
	 * @since 7.0.0
116
	 */
117
	public function deleteObject($urn) {
118
		$this->getConnection()->deleteObject([
119
			'Bucket' => $this->bucket,
120
			'Key' => $urn,
121
		]);
122
	}
123
124
	public function objectExists($urn) {
125
		return $this->getConnection()->doesObjectExist($this->bucket, $urn);
126
	}
127
128
	public function copyObject($from, $to) {
129
		$this->getConnection()->copy($this->getBucket(), $from, $this->getBucket(), $to);
0 ignored issues
show
Bug introduced by
It seems like getBucket() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

129
		$this->getConnection()->copy($this->/** @scrutinizer ignore-call */ getBucket(), $from, $this->getBucket(), $to);
Loading history...
130
	}
131
}
132