1: <?php
2: 3: 4: 5: 6: 7: 8: 9:
10:
11: namespace OpenCloud\ObjectStore\Upload;
12:
13: use Exception;
14: use OpenCloud\Common\Http\Client;
15: use Guzzle\Http\EntityBody;
16: use OpenCloud\Common\Exceptions\RuntimeException;
17: use OpenCloud\ObjectStore\Exception\UploadException;
18:
19: 20: 21:
22: class AbstractTransfer
23: {
24: 25: 26:
27: const MIN_PART_SIZE = 1048576;
28:
29: 30: 31:
32: const MAX_PART_SIZE = 5368709120;
33:
34: 35: 36:
37: const DEFAULT_PART_SIZE = 1073741824;
38:
39: 40: 41:
42: protected $client;
43:
44: 45: 46:
47: protected $entityBody;
48:
49: 50: 51: 52: 53:
54: protected $transferState;
55:
56: 57: 58:
59: protected $options;
60:
61: 62: 63:
64: protected $partSize;
65:
66: 67: 68:
69: protected $defaultOptions = array(
70: 'concurrency' => true,
71: 'partSize' => self::DEFAULT_PART_SIZE,
72: 'prefix' => 'segment',
73: 'doPartChecksum' => true
74: );
75:
76: 77: 78:
79: public static function newInstance()
80: {
81: return new static();
82: }
83:
84: 85: 86: 87:
88: public function setClient(Client $client)
89: {
90: $this->client = $client;
91: return $this;
92: }
93:
94: 95: 96: 97:
98: public function setEntityBody(EntityBody $entityBody)
99: {
100: $this->entityBody = $entityBody;
101: return $this;
102: }
103:
104: 105: 106: 107:
108: public function setTransferState(TransferState $transferState)
109: {
110: $this->transferState = $transferState;
111: return $this;
112: }
113:
114: 115: 116:
117: public function getOptions()
118: {
119: return $this->options;
120: }
121:
122: 123: 124: 125:
126: public function setOptions($options)
127: {
128: $this->options = $options;
129: return $this;
130: }
131:
132: 133: 134: 135: 136:
137: public function setOption($option, $value)
138: {
139: $this->options[$option] = $value;
140: return $this;
141: }
142:
143: public function getPartSize()
144: {
145: return $this->partSize;
146: }
147:
148: 149: 150:
151: public function setup()
152: {
153: $this->options = array_merge($this->defaultOptions, $this->options);
154: $this->partSize = $this->validatePartSize();
155:
156: return $this;
157: }
158:
159: 160: 161: 162: 163:
164: protected function validatePartSize()
165: {
166: $min = min($this->options['partSize'], self::MAX_PART_SIZE);
167: return max($min, self::MIN_PART_SIZE);
168: }
169:
170: 171: 172: 173: 174: 175: 176: 177:
178: public function upload()
179: {
180: if (!$this->transferState->isRunning()) {
181: throw new RuntimeException('The transfer has been aborted.');
182: }
183:
184: try {
185: $this->transfer();
186: $response = $this->createManifest();
187: } catch (Exception $e) {
188: throw new UploadException($this->transferState, $e);
189: }
190:
191: return $response;
192: }
193:
194: 195: 196: 197: 198: 199: 200: 201: 202:
203: private function createManifest()
204: {
205: $parts = array();
206:
207: foreach ($this->transferState as $part) {
208: $parts[] = (object) array(
209: 'path' => $part->getPath(),
210: 'etag' => $part->getETag(),
211: 'size_bytes' => $part->getContentLength()
212: );
213: }
214:
215: $headers = array(
216: 'Content-Length' => 0,
217: 'X-Object-Manifest' => sprintf('%s/%s/%s/',
218: $this->options['containerName'],
219: $this->options['objectName'],
220: $this->options['prefix']
221: )
222: );
223:
224: $url = clone $this->options['containerUrl'];
225: $url->addPath($this->options['objectName']);
226:
227: return $this->client->put($url, $headers)->send();
228: }
229:
230: }