Swift.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Adrian Brzezinski <adrian.brzezinski@eo.pl>
  6. * @author Jörn Friedrich Dreyer <jfd@butonic.de>
  7. * @author Morris Jobke <hey@morrisjobke.de>
  8. * @author Robin Appelman <robin@icewind.nl>
  9. * @author Roeland Jago Douma <roeland@famdouma.nl>
  10. *
  11. * @license AGPL-3.0
  12. *
  13. * This code is free software: you can redistribute it and/or modify
  14. * it under the terms of the GNU Affero General Public License, version 3,
  15. * as published by the Free Software Foundation.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU Affero General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Affero General Public License, version 3,
  23. * along with this program. If not, see <http://www.gnu.org/licenses/>
  24. *
  25. */
  26. namespace OC\Files\ObjectStore;
  27. use GuzzleHttp\Client;
  28. use GuzzleHttp\Exception\BadResponseException;
  29. use GuzzleHttp\Psr7\Utils;
  30. use Icewind\Streams\RetryWrapper;
  31. use OCP\Files\NotFoundException;
  32. use OCP\Files\ObjectStore\IObjectStore;
  33. use OCP\Files\StorageAuthException;
  34. use Psr\Log\LoggerInterface;
  35. const SWIFT_SEGMENT_SIZE = 1073741824; // 1GB
  36. class Swift implements IObjectStore {
  37. /**
  38. * @var array
  39. */
  40. private $params;
  41. /** @var SwiftFactory */
  42. private $swiftFactory;
  43. public function __construct($params, ?SwiftFactory $connectionFactory = null) {
  44. $this->swiftFactory = $connectionFactory ?: new SwiftFactory(
  45. \OC::$server->getMemCacheFactory()->createDistributed('swift::'),
  46. $params,
  47. \OC::$server->get(LoggerInterface::class)
  48. );
  49. $this->params = $params;
  50. }
  51. /**
  52. * @return \OpenStack\ObjectStore\v1\Models\Container
  53. * @throws StorageAuthException
  54. * @throws \OCP\Files\StorageNotAvailableException
  55. */
  56. private function getContainer() {
  57. return $this->swiftFactory->getContainer();
  58. }
  59. /**
  60. * @return string the container name where objects are stored
  61. */
  62. public function getStorageId() {
  63. if (isset($this->params['bucket'])) {
  64. return $this->params['bucket'];
  65. }
  66. return $this->params['container'];
  67. }
  68. public function writeObject($urn, $stream, ?string $mimetype = null) {
  69. $tmpFile = \OC::$server->getTempManager()->getTemporaryFile('swiftwrite');
  70. file_put_contents($tmpFile, $stream);
  71. $handle = fopen($tmpFile, 'rb');
  72. if (filesize($tmpFile) < SWIFT_SEGMENT_SIZE) {
  73. $this->getContainer()->createObject([
  74. 'name' => $urn,
  75. 'stream' => Utils::streamFor($handle),
  76. 'contentType' => $mimetype,
  77. ]);
  78. } else {
  79. $this->getContainer()->createLargeObject([
  80. 'name' => $urn,
  81. 'stream' => Utils::streamFor($handle),
  82. 'segmentSize' => SWIFT_SEGMENT_SIZE,
  83. 'contentType' => $mimetype,
  84. ]);
  85. }
  86. }
  87. /**
  88. * @param string $urn the unified resource name used to identify the object
  89. * @return resource stream with the read data
  90. * @throws \Exception from openstack or GuzzleHttp libs when something goes wrong
  91. * @throws NotFoundException if file does not exist
  92. */
  93. public function readObject($urn) {
  94. try {
  95. $publicUri = $this->getContainer()->getObject($urn)->getPublicUri();
  96. $tokenId = $this->swiftFactory->getCachedTokenId();
  97. $response = (new Client())->request('GET', $publicUri,
  98. [
  99. 'stream' => true,
  100. 'headers' => [
  101. 'X-Auth-Token' => $tokenId,
  102. 'Cache-Control' => 'no-cache',
  103. ],
  104. ]
  105. );
  106. } catch (BadResponseException $e) {
  107. if ($e->getResponse() && $e->getResponse()->getStatusCode() === 404) {
  108. throw new NotFoundException("object $urn not found in object store");
  109. } else {
  110. throw $e;
  111. }
  112. }
  113. return RetryWrapper::wrap($response->getBody()->detach());
  114. }
  115. /**
  116. * @param string $urn Unified Resource Name
  117. * @return void
  118. * @throws \Exception from openstack lib when something goes wrong
  119. */
  120. public function deleteObject($urn) {
  121. $this->getContainer()->getObject($urn)->delete();
  122. }
  123. /**
  124. * @return void
  125. * @throws \Exception from openstack lib when something goes wrong
  126. */
  127. public function deleteContainer() {
  128. $this->getContainer()->delete();
  129. }
  130. public function objectExists($urn) {
  131. return $this->getContainer()->objectExists($urn);
  132. }
  133. public function copyObject($from, $to) {
  134. $this->getContainer()->getObject($from)->copy([
  135. 'destination' => $this->getContainer()->name . '/' . $to
  136. ]);
  137. }
  138. }